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.
Constant Summary collapse
- DEFAULT_COLUMN_WIDTH =
12- HORIZONTAL_RULE_CHARACTER =
"-"- VERTICAL_RULE_CHARACTER =
"|"- CORNER_CHARACTER =
"+"- PADDING_CHARACTER =
" "- TRUNCATION_INDICATOR =
"~"
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.
39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 |
# File 'lib/tabulo/table.rb', line 39 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) @columns = [] 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.
84 85 86 87 88 89 90 91 92 93 94 95 96 |
# File 'lib/tabulo/table.rb', line 84 def add_column(label, header: nil, align_header: :center, align_body: nil, width: nil, formatter: :to_s.to_proc, &extractor) @columns << Column.new( label: label.to_sym, 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
117 118 119 120 121 122 123 124 125 126 127 128 129 130 |
# File 'lib/tabulo/table.rb', line 117 def each @sources.each_with_index do |source, index| include_header = case @header_frequency when :start index == 0 when Fixnum 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.
133 134 135 136 |
# File 'lib/tabulo/table.rb', line 133 def formatted_header cells = @columns.map(&: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.
146 147 148 149 |
# File 'lib/tabulo/table.rb', line 146 def horizontal_rule inner = @columns.map { |column| surround(column.horizontal_rule, HORIZONTAL_RULE_CHARACTER) } 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.
172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 |
# File 'lib/tabulo/table.rb', line 172 def shrinkwrap!(max_table_width: nil) return self if columns.none? wrapped_width = -> (str) { str.split($/).map(&:length).max || 1 } columns.each do |column| column.width = wrapped_width.call(column.header) end @sources.each do |source| columns.each do |column| width = wrapped_width.call(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 = columns.count * 2 total_borders = columns.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 + columns.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.
100 101 102 103 104 105 106 |
# File 'lib/tabulo/table.rb', line 100 def to_s if @columns.any? join_lines(map(&:to_s)) else "" end end |