Class: Tabulo::Table
Overview
Represents a table primarily intended for "pretty-printing" in a fixed-width font.
A Table is also an Enumerable, of which each element is a Row.
Instance Method Summary collapse
-
#add_column(label, header: nil, align_header: :center, align_body: nil, width: nil, formatter: :to_s.to_proc, &extractor) ⇒ Object
Adds a column to the Table.
- #each ⇒ Object
-
#formatted_header ⇒ String
An "ASCII" graphical representation of the Table column headers.
-
#horizontal_rule ⇒ String
An "ASCII" graphical representation of a horizontal dividing line suitable for printing at any point in the table.
-
#initialize(sources, columns: [], column_width: nil, header_frequency: :start, wrap_header_cells_to: nil, wrap_body_cells_to: nil) {|_self| ... } ⇒ Table
constructor
A new Table.
-
#shrinkwrap!(max_table_width: nil) ⇒ Table
Reset all the column widths so that each column is just wide enough to accommodate its header text as well as the formatted content of each its cells for the entire collection, together with a single character of padding on either side of the column, without any wrapping.
-
#to_s ⇒ String
A graphical "ASCII" representation of the Table, suitable for display in a fixed-width font.
Constructor Details
#initialize(sources, columns: [], column_width: nil, header_frequency: :start, wrap_header_cells_to: nil, wrap_body_cells_to: nil) {|_self| ... } ⇒ Table
Returns a new Table.
51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 |
# File 'lib/tabulo/table.rb', line 51 def initialize(sources, columns: [], column_width: nil, header_frequency: :start, wrap_header_cells_to: nil, wrap_body_cells_to: nil) @sources = sources @header_frequency = header_frequency @wrap_header_cells_to = wrap_header_cells_to @wrap_body_cells_to = wrap_body_cells_to @default_column_width = (column_width || DEFAULT_COLUMN_WIDTH) @column_registry = { } columns.each { |item| add_column(item) } yield self if block_given? end |
Instance Method Details
#add_column(label, header: nil, align_header: :center, align_body: nil, width: nil, formatter: :to_s.to_proc, &extractor) ⇒ Object
Adds a column to the Table.
99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 |
# File 'lib/tabulo/table.rb', line 99 def add_column(label, header: nil, align_header: :center, align_body: nil, width: nil, formatter: :to_s.to_proc, &extractor) column_label = label.to_sym if column_registry.include?(column_label) raise InvalidColumnLabelError, "Column label already used in this table." end @column_registry[column_label] = Column.new( header: (header || label).to_s, align_header: align_header, align_body: align_body, width: (width || @default_column_width), formatter: formatter, extractor: (extractor || label.to_proc) ) end |
#each ⇒ Object
138 139 140 141 142 143 144 145 146 147 148 149 150 151 |
# File 'lib/tabulo/table.rb', line 138 def each @sources.each_with_index do |source, index| include_header = case @header_frequency when :start index == 0 when Integer index % @header_frequency == 0 else @header_frequency end yield body_row(source, with_header: include_header) end end |
#formatted_header ⇒ String
Returns an "ASCII" graphical representation of the Table column headers.
154 155 156 157 |
# File 'lib/tabulo/table.rb', line 154 def formatted_header cells = column_registry.map { |_, column| column.header_subcells } format_row(cells, @wrap_header_cells_to) end |
#horizontal_rule ⇒ String
Returns an "ASCII" graphical representation of a horizontal dividing line suitable for printing at any point in the table.
167 168 169 170 171 172 |
# File 'lib/tabulo/table.rb', line 167 def horizontal_rule inner = column_registry.map do |_, column| surround(column.horizontal_rule, HORIZONTAL_RULE_CHARACTER) end surround_join(inner, CORNER_CHARACTER) end |
#shrinkwrap!(max_table_width: nil) ⇒ Table
Reset all the column widths so that each column is just wide enough to accommodate its header text as well as the formatted content of each its cells for the entire collection, together with a single character of padding on either side of the column, without any wrapping.
Note that calling this method will cause the entire source Enumerable to be traversed and all the column extractors and formatters to be applied in order to calculate the required widths.
Note also that this method causes column widths to be fixed as appropriate to the formatted cell contents given the state of the source Enumerable at the point it is called. If the source Enumerable changes between that point, and the point when the Table is printed, then columns will not be resized yet again on printing.
200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 |
# File 'lib/tabulo/table.rb', line 200 def shrinkwrap!(max_table_width: nil) return self if column_registry.none? columns = column_registry.values columns.each do |column| column.width = wrapped_width(column.header) end @sources.each do |source| columns.each do |column| width = wrapped_width(column.formatted_cell_content(source)) column.width = width if width > column.width end end if max_table_width total_columns_width = columns.inject(0) { |sum, column| sum + column.width } total_padding = column_registry.count * 2 total_borders = column_registry.count + 1 unadjusted_table_width = total_columns_width + total_padding + total_borders # Ensure max table width is at least wide enough to accommodate table borders and padding # and one character of content. min_table_width = total_padding + total_borders + column_registry.count max_table_width = min_table_width if min_table_width > max_table_width required_reduction = [unadjusted_table_width - max_table_width, 0].max required_reduction.times do widest_column = columns.inject(columns.first) do |widest, column| column.width >= widest.width ? column : widest end widest_column.width -= 1 end end self end |
#to_s ⇒ String
Returns a graphical "ASCII" representation of the Table, suitable for display in a fixed-width font.
121 122 123 124 125 126 127 |
# File 'lib/tabulo/table.rb', line 121 def to_s if column_registry.any? join_lines(map(&:to_s)) else "" end end |