Class: TableTennis::Stage::Format

Inherits:
Base
  • Object
show all
Defined in:
lib/table_tennis/stage/format.rb

Overview

This stage “formats” the table by injesting columns that contain various ruby objects and formatting each as a string. Cells are formatted in place by transforming rows.

Constant Summary collapse

DELIMS =
/(\d)(?=(\d\d\d)+(?!\d))/

Instance Attribute Summary

Attributes inherited from Base

#data

Instance Method Summary collapse

Methods inherited from Base

#initialize

Methods included from Util::Inspectable

#inspect

Constructor Details

This class inherits a constructor from TableTennis::Stage::Base

Instance Method Details



103
104
105
106
107
108
109
# File 'lib/table_tennis/stage/format.rb', line 103

def detect_link(str)
  # fail fast, for speed
  return unless str.length >= 6 && str[0] == "["
  if str =~ /^\[([^\]]+)\]\(([^\)]+)\)$/
    [$1, $2]
  end
end

#fmt_number(x, digits: nil) ⇒ Object

this is a bit slow but easy to understand



82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
# File 'lib/table_tennis/stage/format.rb', line 82

def fmt_number(x, digits: nil)
  delims = config.delims && (x >= 1000 || x <= -1000)

  # convert to string (and honor digits)
  x = if digits
    "%0.#{digits}f" % x
  else
    # be careful not to leave a trailing .0
    x = x.to_i if x.is_a?(Float) && (x % 1) == 0
    x.to_s
  end

  if delims
    x, r = x.split(".")
    x.gsub!(DELIMS) { "#{_1}," }
    x = "#{x}.#{r}" if r
  end

  x
end

#fn_default(value) ⇒ Object

default formatting. cleanup whitespace



71
72
73
74
75
76
77
# File 'lib/table_tennis/stage/format.rb', line 71

def fn_default(value)
  return if value.nil?
  str = value.is_a?(String) ? value : value.to_s
  str = str.strip.gsub("\n", "\\n").gsub("\r", "\\r") if str.match?(/\s/)
  return if str.empty?
  str
end

#fn_float(value) ⇒ Object

fns for each column type



44
45
46
47
48
49
50
51
52
# File 'lib/table_tennis/stage/format.rb', line 44

def fn_float(value)
  # cap memo_wise
  @_memo_wise[__method__].tap { _1.clear if _1.length > 5000 }

  case value
  when String then fmt_number(to_f(value), digits: config.digits) if Util::Identify.number?(value)
  when Numeric then fmt_number(value, digits: config.digits)
  end
end

#fn_int(value) ⇒ Object



55
56
57
58
59
60
# File 'lib/table_tennis/stage/format.rb', line 55

def fn_int(value)
  case value
  when String then fmt_number(to_i(value)) if Util::Identify.int?(value)
  when Integer then fmt_number(value)
  end
end

#fn_time(value) ⇒ Object



62
63
64
# File 'lib/table_tennis/stage/format.rb', line 62

def fn_time(value)
  value.strftime(config.strftime) if Util::Identify.time?(value)
end

#runObject



7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
# File 'lib/table_tennis/stage/format.rb', line 7

def run
  # Sample each column and infer column types. Determine which fn_xxx to
  # use for each column.
  fns = columns.map do
    fn = case _1.type
    when :float then :fn_float
    when :int then :fn_int
    when :time then :fn_time if config.strftime
    end
    fn || :fn_default
  end

  rows.each.with_index do |row, r|
    row.each_index do |c|
      value = row[c]
      # Try to format using the column fn. This can return nil. For
      # example, a float column and value is nil, not a float, etc.
      str = send(fns[c], value)

      # If the column formatter failed, use the default formatter
      str ||= fn_default(value) || config.placeholder

      # look for markdown-style links
      if (link = detect_link(str))
        str, data.links[[r, c]] = link
      end

      # done
      row[c] = str
    end
  end
end

#to_f(str) ⇒ Object

str to_xxx that are resistant to commas



112
# File 'lib/table_tennis/stage/format.rb', line 112

def to_f(str) = str.delete(",").to_f

#to_i(str) ⇒ Object



113
# File 'lib/table_tennis/stage/format.rb', line 113

def to_i(str) = str.delete(",").to_i