# File lib/biotcm/table.rb, line 65 def primary_key=(val) @primary_key = val.nil? ? nil : val.to_s end
class BioTCM::Table
One of the basic data models used in BioTCM
to process {github.com/biotcm/biotcm/wiki/Formats#tab .tab files}, developed under “strict entry and tolerant exit” philosophy.
For more details, please refer to the test.
Constants
- VERSION
Version
Attributes
Comments
Primary key
Public Class Methods
@private Factory method @return [Table]
# File lib/biotcm/table.rb, line 19 def self.build(primary_key: nil, row_keys: {}, col_keys: {}, content: [], comments: []) @tab = new @tab.instance_variable_set(:@primary_key, primary_key) @tab.instance_variable_set(:@row_keys, row_keys) @tab.instance_variable_set(:@col_keys, col_keys) @tab.instance_variable_set(:@content, content) @tab.instance_variable_set(:@comments, comments) @tab end
Load a table from a file @param filepath [String] @param encoding [String] @param seperator [String] @return [Table]
# File lib/biotcm/table.rb, line 34 def self.load(filepath, encoding: Encoding.default_external, seperator: "\t") raise ArgumentError, 'Illegal argument type for Table.load' unless filepath.is_a?(String) File.open(filepath, "r:#{encoding}").read.to_table(seperator: seperator) end
Create an empty table with keys @param primary_key
[String] @param row_keys
[Array] @param col_keys
[Array]
# File lib/biotcm/table.rb, line 43 def initialize(primary_key: nil, row_keys: [], col_keys: [], comments: []) @primary_key = primary_key @row_keys = row_keys.map.with_index { |r, ri| [r, ri] }.to_h @col_keys = col_keys.map.with_index { |c, ci| [c, ci] }.to_h @content = row_keys.collect { col_keys.collect { '' } } @comments = comments end
Public Instance Methods
Clone this table @return [Table]
# File lib/biotcm/table.rb, line 53 def clone self.class.build( primary_key: @primary_key, row_keys: @row_keys.clone, col_keys: @col_keys.clone, content: @content.collect(&:clone), comments: @comments.clone ) end
Access a column @overload col(col)
Get a column @param col [String] @return [Hash]
@overload col(col, val)
Set a column @param col [String] @param val [Hash, Array] @return [Table]
# File lib/biotcm/table.rb, line 230 def col(col, val = nil) if val.nil? get_col(col) else set_col(col, val) end end
Get col keys @return [Array]
# File lib/biotcm/table.rb, line 85 def col_keys @col_keys.keys end
Set col keys @param val [Array]
# File lib/biotcm/table.rb, line 91 def col_keys=(val) raise ArgumentError, 'Illegal agrument type' unless val.is_a?(Array) raise ArgumentError, 'Unmatched size' if val.size < @col_keys.size @col_keys = val.map.with_index { |v, i| [v, i] }.to_h end
Set comments @param val [Array/String]
# File lib/biotcm/table.rb, line 99 def comments=(val) if val.respond_to?(:collect) @comments = val.map(&:to_s) elsif val.respond_to?(:to_s) @comments = [val.to_s] end end
Iterate by col
# File lib/biotcm/table.rb, line 295 def each_col if block_given? @col_keys.each_key { |c| yield(c, col(c)) } self else Enumerator.new do |y| @col_keys.each_key { |c| y << [c, col(c)] } end end end
Iterate by row
# File lib/biotcm/table.rb, line 283 def each_row if block_given? @row_keys.each_key { |r| yield(r, row(r)) } self else Enumerator.new do |y| @row_keys.each_key { |r| y << [r, row(r)] } end end end
Access an element @overload ele(row, col)
Get an element @param row [String] @param col [String] @return [String]
@overload ele(row, col, val)
Set an element @param row [String] @param col [String] @param val [String] @return [Table]
# File lib/biotcm/table.rb, line 119 def ele(row, col, val = nil) if val.nil? get_ele(row, col) else set_ele(row, col, val) end end
Get a column @param col [String] @return [Hash]
# File lib/biotcm/table.rb, line 241 def get_col(col) col = @col_keys[col] col.nil? ? nil : @row_keys.map { |r, ri| [r, @content[ri][col]] }.to_h end
Get an element @param row [String] @param col [String] @return [String]
# File lib/biotcm/table.rb, line 131 def get_ele(row, col) row = @row_keys[row] col = @col_keys[col] row && col ? @content[row][col] : nil end
Get a row @param row [String] @return [Hash]
# File lib/biotcm/table.rb, line 178 def get_row(row) row = @row_keys[row] row.nil? ? nil : @col_keys.map { |c, ci| [c, @content[row][ci]] }.to_h end
@private For inspection
# File lib/biotcm/table.rb, line 416 def inspect '#<Table primary_key=' + @primary_key.inspect + ' col_keys=' + @col_keys.keys.sort_by { |k| @col_keys[k] }.inspect + ' row_keys=' + @row_keys.keys.sort_by { |k| @row_keys[k] }.inspect + ' content=' + @content.inspect + ' comments=' + @comments.join.inspect + '>' end
Merge with another table @param tab [Table]
# File lib/biotcm/table.rb, line 359 def merge(tab) raise ArgumentError, 'Only tables could be merged' unless tab.is_a?(self.class) raise ArgumentError, 'Primary keys not the same' unless tab.primary_key == primary_key # Empty content content = [] row_keys = (@row_keys.keys | tab.row_keys).map.with_index { |row, i| [row, i] }.to_h col_keys = (@col_keys.keys | tab.col_keys).map.with_index { |col, i| [col, i] }.to_h row_keys.size.times { content << Array.new(col_keys.size, '') } # rubocop:disable Lint/Eval, Style/SpaceInsideStringInterpolation # Fill content with self eval <<-END_OF_DOC @row_keys.each do |row, old_ri| new_ri = row_keys[row] #{ str = [] @col_keys.map do |col, old_ci| new_ci = col_keys[col] str << "content[new_ri][#{new_ci}] = @content[old_ri][#{old_ci}]" end str.join("\n" + ' ' * 8) } end END_OF_DOC # Fill content with tab @content_merged_with = tab.instance_variable_get(:@content) eval <<-END_OF_DOC tab.row_keys.each_with_index do |row, old_ri| new_ri = row_keys[row] #{ str = [] tab.col_keys.each_with_index do |col, old_ci| new_ci = col_keys[col] str << "content[new_ri][#{new_ci}] = @content_merged_with[old_ri][#{old_ci}]" end str.join("\n" + ' ' * 8) } end END_OF_DOC # rubocop:enable Lint/Eval, Style/SpaceInsideStringInterpolation, Lint/UselessAssignment # Create a new table self.class.build( primary_key: primary_key, row_keys: row_keys, col_keys: col_keys, content: content, comments: comments + tab.comments ) end
Set the primary key @param val [String]
Access a row @overload row(row)
Get a row @param row [String] @return [Hash]
@overload row(row, val)
Set a row @param row [String] @param val [Hash, Array] @return [Table]
# File lib/biotcm/table.rb, line 167 def row(row, val = nil) if val.nil? get_row(row) else set_row(row, val) end end
Get row keys @return [Array]
# File lib/biotcm/table.rb, line 71 def row_keys @row_keys.keys end
Set row keys @param val [Array]
# File lib/biotcm/table.rb, line 77 def row_keys=(val) raise ArgumentError, 'Illegal agrument type' unless val.is_a?(Array) raise ArgumentError, 'Unmatched size' if val.size < @row_keys.size @row_keys = val.map.with_index { |v, i| [v, i] }.to_h end
Print in a file @param filepath [String] @return [self]
# File lib/biotcm/table.rb, line 438 def save(filepath) File.open(filepath, 'w').puts self self end
Select row(s) and column(s) to build a new table @param rows [Array] @param cols [Array] @return [Table]
# File lib/biotcm/table.rb, line 324 def select(rows, cols) # Prune rows if rows == :all row_keys = @row_keys.clone content = @content.collect(&:clone) else raise ArgumentError, 'Illegal argument type' unless rows.is_a?(Array) row_keys = {} (rows & @row_keys.keys).each { |row| row_keys[row] = row_keys.size } content = [] row_keys.each_key { |row| content << @content[@row_keys[row]] } end # Prune columns if cols == :all col_keys = @col_keys.clone else raise ArgumentError, 'Illegal argument type' unless cols.is_a?(Array) col_keys = {} (cols & @col_keys.keys).each { |col| col_keys[col] = col_keys.size } eval 'content.collect! { |arr| [' + col_keys.keys.collect { |col| "arr[#{@col_keys[col]}]" }.join(',') + '] }' # rubocop:disable Lint/Eval end # Create a new table self.class.build( primary_key: primary_key, row_keys: row_keys, col_keys: col_keys, content: content, comments: comments ) end
Select column(s) to build a new table @param cols [Array] @return [Table]
# File lib/biotcm/table.rb, line 316 def select_col(cols) select(:all, cols) end
Select row(s) to build a new table @param rows [Array] @return [Table]
# File lib/biotcm/table.rb, line 309 def select_row(rows) select(rows, :all) end
Set a column @param col [String] @param val [Hash, Array] @return [Table]
# File lib/biotcm/table.rb, line 250 def set_col(col, val) if !col.is_a?(String) || (!val.is_a?(Hash) && !val.is_a?(Array)) raise ArgumentError, 'Illegal argument type' elsif val.is_a?(Array) && val.size != row_keys.size raise ArgumentError, 'Row size not match' end case val when Array if @col_keys[col] col = @col_keys[col] val.each_with_index { |v, row| @content[row][col] = v } else col = @col_keys[col] = @col_keys.size val.each_with_index { |v, row| @content[row] << v } end when Hash unless @col_keys[col] @col_keys[col] = @col_keys.size @content.each { |arr| arr << '' } end col = @col_keys[col] val.each do |k, v| row = @row_keys[k] @content[row][col] = v if row end end self end
Set an element @param row [String] @param col [String] @param val [String] @return [Table]
# File lib/biotcm/table.rb, line 142 def set_ele(row, col, val) unless row.is_a?(String) && col.is_a?(String) && val.respond_to?(:to_s) raise ArgumentError, 'Illegal argument type' end set_row(row, [''] * @col_keys.size) unless @row_keys[row] set_col(col, [''] * @row_keys.size) unless @col_keys[col] row = @row_keys[row] col = @col_keys[col] @content[row][col] = val.to_s self end
Set a row @param row [String] @param val [Hash, Array] @return [Table]
# File lib/biotcm/table.rb, line 187 def set_row(row, val) # Setter if !row.is_a?(String) || (!val.is_a?(Hash) && !val.is_a?(Array)) raise ArgumentError, 'Illegal argument type' elsif val.is_a?(Array) && val.size != col_keys.size raise ArgumentError, 'Column size not match' end case val when Array if @row_keys[row] row = @row_keys[row] @content[row] = val else @row_keys[row] = @row_keys.size @content << val end when Hash unless @row_keys[row] @row_keys[row] = @row_keys.size @content << ([''] * @col_keys.size) end row = @row_keys[row] val.each do |k, v| col = @col_keys[k] @content[row][col] = v if col end end self end
@private Convert to String
# File lib/biotcm/table.rb, line 427 def to_s [ @comments.collect { |line| '# ' + line }, @primary_key.nil? ? @col_keys.keys.join("\t") : [@primary_key, @col_keys.keys].join("\t"), @row_keys.keys.zip(@content).collect { |a| a.join("\t") } ].flatten.join("\n") end