Class: TableTennis::TableData

Inherits:
Object
  • Object
show all
Includes:
MemoWise, Util::Inspectable
Defined in:
lib/table_tennis/table_data.rb

Overview

This class stores our data as rows & columns. The initialization is a little tricky due to memoization and some ordering issues, but basically works like this:

1) Start with input_rows. 2) Calculate ‘fat_rows` which is an array of hashes with all keys. This

might be too much data because we haven't taken config.columns into
account.

3) Use fat_rows to calculate rows & columns.

Generally we try to use this language:
  • ‘row` is a a Row, an array of cells

  • ‘column` is a Column. It doesn’t store any data directly but it

    can be enumerated.
    
  • ‘name` is a column.name

  • ‘value` is the value of a cell

  • ‘r` and `c` are row and column indexes

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from Util::Inspectable

#inspect

Constructor Details

#initialize(rows:, config: nil) ⇒ TableData

Returns a new instance of TableData.



26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
# File 'lib/table_tennis/table_data.rb', line 26

def initialize(rows:, config: nil)
  @config, @input_rows = config, rows

  if !config && !ENV["MINITEST"]
    raise ArgumentError, "must provide a config"
  end

  # We leave input_rows untouched so we can pass them back to the user for
  # `mark`. The only strange case is if the user passed in a plain old Hash.
  if @input_rows.is_a?(Hash)
    @input_rows = @input_rows.map { |key, value| {key:, value:} }
  elsif !@input_rows.is_a?(Enumerable)
    raise ArgumentError, "input_rows must be an array of hash-like objects, not #{input_rows.class}"
  end

  @links = {}
  @styles = {}
end

Instance Attribute Details

#configObject

Returns the value of attribute config.



24
25
26
# File 'lib/table_tennis/table_data.rb', line 24

def config
  @config
end

#input_rowsObject

Returns the value of attribute input_rows.



24
25
26
# File 'lib/table_tennis/table_data.rb', line 24

def input_rows
  @input_rows
end

Returns the value of attribute links.



24
25
26
# File 'lib/table_tennis/table_data.rb', line 24

def links
  @links
end

#stylesObject

Returns the value of attribute styles.



24
25
26
# File 'lib/table_tennis/table_data.rb', line 24

def styles
  @styles
end

Instance Method Details

#chrome_widthObject

layout math

with separators |•xxxx•|•xxxx•|•xxxx•|•xxxx•|•xxxx•|•xxxx•|•xxxx•|•xxxx•| ↑↑ ↑ ↑12 3 <- three chrome chars per column │

              

without |•xxxx••xxxx••xxxx••xxxx••xxxx••xxxx••xxxx••xxxx•|



108
109
110
# File 'lib/table_tennis/table_data.rb', line 108

def chrome_width
  config.separators ? (columns.length * 3 + 1) : (columns.length * 2 + 2)
end

#column_namesObject

Lazily calculate column names (always symbols)



65
# File 'lib/table_tennis/table_data.rb', line 65

def column_names = columns.map(&:name)

#columnsObject

Lazily calculate the list of columns.



46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
# File 'lib/table_tennis/table_data.rb', line 46

def columns
  names = config&.columns
  if !fat_rows.empty?
    names ||= {}.tap do |memo|
      fat_rows.each { |row| row.each_key { memo[_1] = 1 } }
    end.keys
  else
    names = []
  end
  names.each do |name|
    if !fat_rows.any? { _1.key?(name) }
      raise ArgumentError, "specified column `#{name}` not found in any row of input data"
    end
  end
  names.map.with_index { Column.new(self, _1, _2) }
end

#data_widthObject

what is the width of the columns, not including chrome?



89
# File 'lib/table_tennis/table_data.rb', line 89

def data_width = columns.sum(&:width)

#debug(str) ⇒ Object

for debugging



114
115
116
117
118
119
# File 'lib/table_tennis/table_data.rb', line 114

def debug(str)
  return if !config&.debug
  str = "[#{Time.now.strftime("%H:%M:%S")}] #{str}"
  str = str.ljust(@debug_width ||= Util::Console.winsize[1])
  puts Paint[str, :white, :green]
end

#debug_if_slow(str, &block) ⇒ Object



121
122
123
124
125
126
127
128
# File 'lib/table_tennis/table_data.rb', line 121

def debug_if_slow(str, &block)
  tm = Time.now
  yield.tap do
    if (elapsed = Time.now - tm) > 0.01
      debug(sprintf("%-40s [+%0.3fs]", str, elapsed))
    end
  end
end

#get_style(r: nil, c: nil) ⇒ Object

Get the style for a cell, row or column.



86
# File 'lib/table_tennis/table_data.rb', line 86

def get_style(r: nil, c: nil) = styles[[r, c]]

#rowsObject

fat_rows is an array of hashes with ALL keys (not just config.columns). rows is an array of Row objects with just the keys we want. We use memoization to cache the result of fat_rows, and then we create final rows with just the columns we want



72
73
74
# File 'lib/table_tennis/table_data.rb', line 72

def rows
  fat_rows.map.with_index { Row.new(_2, _1.values_at(*column_names)) }
end

#set_style(style:, r: nil, c: nil) ⇒ Object

Set the style for a cell, row or column. The “style” is a theme symbol or hex color.



83
# File 'lib/table_tennis/table_data.rb', line 83

def set_style(style:, r: nil, c: nil) = styles[[r, c]] = style

#table_widthObject

how wide is the table?



92
# File 'lib/table_tennis/table_data.rb', line 92

def table_width = data_width + chrome_width

#themeObject

currnet theme



78
# File 'lib/table_tennis/table_data.rb', line 78

def theme = Theme.new(config&.theme)