tabulo 2.4.1 → 2.5.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d49cd1a3bfb031b2ced0f4539bd8ea16b2943df0c999f7b70e8ddf83cfcd5fa1
4
- data.tar.gz: 745a3834a8c62ba85a7fbd8bdd826dc0bf9e18a1cb6fd54ac81e311870c02f61
3
+ metadata.gz: 970ffd91a62eceded969200a310d85faaf83f8a264f12b4d7dbbbb20d913d6cf
4
+ data.tar.gz: 1b1d3452e33cb7a07f4940291f68370a6443beb46c013e109348c6ec81647f9c
5
5
  SHA512:
6
- metadata.gz: 939d50fdbe7bdfd94740ddddc86d3774c688e505633e693e27f41806224af8c601de6a4aa124ff868aefdc151ca72d4da89dfa2c045bce2b9e45c61064a7723a
7
- data.tar.gz: 6cad47f7c06a52de935ebeec3710722344ac7d28159bca3d7efb2b9b627751a1c4d879d8b0d22beb0eb4af8705f03ee310d925b96b86d175d4c39e3f7b76acbf
6
+ metadata.gz: 34d885006b3dbf0d8190d91126e4b9ead491b214014f172d57187708836e00ec2e3f97cbe5aa7dc2b9a44ef559bc142cd51c2f3ce255e9e0e20bcc320dd7f73b
7
+ data.tar.gz: 9e14cb7b9a6423bb37d863c5a1d0e1c9198804bf2018889400e51fa4c98622dc498d37914aacc9c79602b21ef493e8e0ac62274609e05993de7d78e70064871c
@@ -1,5 +1,9 @@
1
1
  # Changelog
2
2
 
3
+ ### v2.5.0
4
+
5
+ * Add option of table title, together with options for styling and aligning the title
6
+
3
7
  ### v2.4.1
4
8
 
5
9
  * Fix warnings under Ruby 2.7
data/README.md CHANGED
@@ -65,6 +65,7 @@ end
65
65
  * Easily [transpose](#transposition) the table, so that rows are swapped with columns.
66
66
  * Choose from multiple [border configurations](#borders), including Markdown, “ASCII”, and smoothly
67
67
  joined Unicode border characters.
68
+ * Optionally add a [title](#title) to your table.
68
69
 
69
70
  Tabulo has also been ported to Crystal (with some modifications): see [Tablo](https://github.com/hutou/tablo).
70
71
 
@@ -82,6 +83,7 @@ Tabulo has also been ported to Crystal (with some modifications): see [Tablo](ht
82
83
  * [Column labels _vs_ headers](#labels-headers)
83
84
  * [Positioning columns](#column-positioning)
84
85
  * [Removing columns](#removing-columns)
86
+ * [Adding a title](#title)
85
87
  * [Cell alignment](#cell-alignment)
86
88
  * [Column width, wrapping and truncation](#column-width-wrapping-and-truncation)
87
89
  * [Configuring fixed widths](#configuring-fixed-widths)
@@ -92,6 +94,7 @@ Tabulo has also been ported to Crystal (with some modifications): see [Tablo](ht
92
94
  * [Colours and other styling](#colours-and-styling)
93
95
  * [Styling cell content](#styling-cell-content)
94
96
  * [Styling column headers](#styling-column-headers)
97
+ * [Styling the table title](#styling-title)
95
98
  * [Setting default styles](#default-styles)
96
99
  * [Styling borders](#border-styling)
97
100
  * [Repeating headers](#repeating-headers)
@@ -286,6 +289,33 @@ the label of the column you want to remove:
286
289
  table.remove_column(:even?)
287
290
  ```
288
291
 
292
+ <a name="title"></a>
293
+ ### Adding a title
294
+
295
+ You can optionally give your table a title, using the `title` option when initializing the table:
296
+
297
+ ```ruby
298
+ table = Tabulo::Table.new([1, 2, 3], :itself, :odd?, title: "Numbers")
299
+ table.add_column(:even?, before: :odd?)
300
+ ```
301
+
302
+ ```
303
+ > puts table
304
+ +--------------------------------------------+
305
+ | Numbers |
306
+ +--------------+--------------+--------------+
307
+ | itself | even? | odd? |
308
+ +--------------+--------------+--------------+
309
+ | 1 | false | true |
310
+ | 2 | true | false |
311
+ | 3 | false | true |
312
+ +--------------+--------------+--------------+
313
+ ```
314
+
315
+ There is a caveat: Using the `title` option with the `:markdown` [border type](#borders) will cause
316
+ the rendered table to cease being valid Markdown, as unfortunately almost no markdown engines support
317
+ adding a captions (i.e. titles) to tables.
318
+
289
319
  <a name="cell-alignment"></a>
290
320
  ### Cell alignment
291
321
 
@@ -307,6 +337,13 @@ passing similarly-named options to `add_column`, e.g.:
307
337
  table.add_column("Doubled", align_header: :right, align_body: :left) { |n| n * 2 }
308
338
  ```
309
339
 
340
+ If a table title is present, it is center-aligned by default. This can be changed using the
341
+ `align_title` option when initializing the table:
342
+
343
+ ```ruby
344
+ table = Tabulo::Table.new([1, 2], :itself, :even?, title: "Numbers", align_title: :left)
345
+ ```
346
+
310
347
  ### Column width, wrapping and truncation
311
348
 
312
349
  <a name="fixed-column-widths"></a>
@@ -373,6 +410,26 @@ table.pack
373
410
  +-------------------------+------+
374
411
  ```
375
412
 
413
+ If the table [title](#title) happens to be too long to for the existing width of the table, `pack`
414
+ will also arrange for the table to be widened sufficiently to accommodate it without wrapping:
415
+
416
+ ```ruby
417
+ table = Tabulo::Table.new(["a", "b"], :itself, :size, title: "Here are some letters of the alphabet")
418
+ table.pack
419
+ ```
420
+
421
+ ```
422
+ > puts table
423
+ +---------------------------------------+
424
+ | Here are some letters of the alphabet |
425
+ +-------------------+-------------------+
426
+ | itself | size |
427
+ +-------------------+-------------------+
428
+ | a | 1 |
429
+ | b | 1 |
430
+ +-------------------+-------------------+
431
+ ```
432
+
376
433
  The `pack` method returns the table itself, so you can &ldquo;pack-and-print&rdquo; in one go:
377
434
 
378
435
  ```ruby
@@ -576,7 +633,7 @@ the table.
576
633
  The `formatter` callback also has an alternative, 2-parameter version. If `formatter` is passed
577
634
  a 2-parameter callable, the second parameter will be given a `CellData` instance,
578
635
  containing additional information about the cell that may be useful in determining how to format
579
- it&mdash;see the [documentation](https://www.rubydoc.info/gems/tabulo/2.4.1/Tabulo/CellData.html)
636
+ it&mdash;see the [documentation](https://www.rubydoc.info/gems/tabulo/2.5.0/Tabulo/CellData.html)
580
637
  for details.
581
638
 
582
639
  <a name="colours-and-styling"></a>
@@ -622,7 +679,7 @@ the number is even); the second represents the formatted string value of that ce
622
679
  content after any processing by the [formatter](#formatting-cell-values); and the third parameter,
623
680
  if present, will be passed a `CellData` object, containing other information about the cell
624
681
  that may be useful in determining how to style it&mdash;see the
625
- [documentation](https://www.rubydoc.info/gems/tabulo/2.4.1/Tabulo/CellData.html) for details.
682
+ [documentation](https://www.rubydoc.info/gems/tabulo/2.5.0/Tabulo/CellData.html) for details.
626
683
 
627
684
  If the content of a cell is wrapped over multiple lines, then the `styler` will be called once
628
685
  per line, so that each line of the cell will have the escape sequence applied to it separately
@@ -642,8 +699,18 @@ table.add_column(:even?, header_styler: -> (s) { "\033[32m#{s}\033[0m" })
642
699
  ```
643
700
 
644
701
  The `header_styler` option accepts either a 1- or 2-parameter callable. See the
645
- [documentation](https://www.rubydoc.info/gems/tabulo/2.4.1/Tabulo/Table#add_column-instance_method)
702
+ [documentation](https://www.rubydoc.info/gems/tabulo/2.5.0/Tabulo/Table#add_column-instance_method)
646
703
  for details.
704
+ ```
705
+
706
+ <a name="styling-title"></a>
707
+ #### Styling the table title
708
+
709
+ To apply colours or other styling to the table title, if present, use the `title_styler` option
710
+ when initializing the table. This accepts a single-parameter callable:
711
+
712
+ ```ruby
713
+ table = Tabulo::Table.new(1..5, :itself, :even?, :odd?, title: "Numbers", title_styler: -> (s) { "\033[32m#{s}\033[0m" })
647
714
 
648
715
  <a name="default-styles"></a>
649
716
  #### Setting default styles
@@ -706,6 +773,8 @@ table = Tabulo::Table.new(1..10, :itself, :even?, header_frequency: 5)
706
773
  +--------------+--------------+
707
774
  ```
708
775
 
776
+ Note that if the table has a [title](#title), it will not be repeated; only column headers are repeated.
777
+
709
778
  <a name="enumerator"></a>
710
779
  ### Using a Table Enumerator
711
780
 
@@ -835,7 +904,7 @@ a new table in which the rows and columns are swapped:
835
904
  By default, a header row is added to the new table, showing the string value of the element
836
905
  represented in that column. This can be configured, however, along with other aspects of
837
906
  `transpose`&#8217;s behaviour. For details, see the
838
- [documentation](https://www.rubydoc.info/gems/tabulo/2.4.1/Tabulo/Table#transpose-instance_method).
907
+ [documentation](https://www.rubydoc.info/gems/tabulo/2.5.0/Tabulo/Table#transpose-instance_method).
839
908
 
840
909
  <a name="borders"></a>
841
910
  ### Configuring borders
@@ -854,6 +923,17 @@ This is done using the `border` option passed to `Table.new`. The options are as
854
923
  | 2 | true | false |
855
924
  | 3 | false | true |
856
925
  +--------------+--------------+--------------+
926
+
927
+ > puts Tabulo::Table.new(1..3, :itself, :even?, :odd?, border: :ascii, title: "Numbers")
928
+ +--------------------------------------------+
929
+ | Numbers |
930
+ +--------------+--------------+--------------+
931
+ | itself | even? | odd? |
932
+ +--------------+--------------+--------------+
933
+ | 1 | false | true |
934
+ | 2 | true | false |
935
+ | 3 | false | true |
936
+ +--------------+--------------+--------------+
857
937
  ```
858
938
 
859
939
  `:modern`&mdash;uses smoothly joined Unicode characters:
@@ -867,6 +947,17 @@ This is done using the `border` option passed to `Table.new`. The options are as
867
947
  │ 2 │ true │ false │
868
948
  │ 3 │ false │ true │
869
949
  └──────────────┴──────────────┴──────────────┘
950
+
951
+ > puts Tabulo::Table.new(1..3, :itself, :even?, :odd?, border: :modern, title: "Numbers")
952
+ ┌────────────────────────────────────────────┐
953
+ │ Numbers │
954
+ ├──────────────┬──────────────┬──────────────┤
955
+ │ itself │ even? │ odd? │
956
+ ├──────────────┼──────────────┼──────────────┤
957
+ │ 1 │ false │ true │
958
+ │ 2 │ true │ false │
959
+ │ 3 │ false │ true │
960
+ └──────────────┴──────────────┴──────────────┘
870
961
  ```
871
962
 
872
963
  `:markdown`&mdash;renders a GitHub flavoured Markdown table:
@@ -878,8 +969,20 @@ This is done using the `border` option passed to `Table.new`. The options are as
878
969
  | 1 | false | true |
879
970
  | 2 | true | false |
880
971
  | 3 | false | true |
972
+
973
+ > puts Tabulo::Table.new(1..3, :itself, :even?, :odd?, border: :markdown, title: "Numbers")
974
+ | Numbers |
975
+ | itself | even? | odd? |
976
+ |--------------|--------------|--------------|
977
+ | 1 | false | true |
978
+ | 2 | true | false |
979
+ | 3 | false | true |
881
980
  ```
882
981
 
982
+ _However_, note that when a table is rendered using the `:markdown` border type in combination with a
983
+ (non-`nil`) `title`, the result will be _invalid Markdown_. This is because Markdown engines do not
984
+ generally support adding a caption (i.e. title) element to tables.
985
+
883
986
  `:blank`&mdash;no border or divider characters are printed:
884
987
 
885
988
  ```
@@ -888,6 +991,14 @@ This is done using the `border` option passed to `Table.new`. The options are as
888
991
  1 false true
889
992
  2 true false
890
993
  3 false true
994
+
995
+
996
+ > puts Tabulo::Table.new(1..3, :itself, :even?, :odd?, border: :blank, title: "Numbers")
997
+ Numbers
998
+ itself even? odd?
999
+ 1 false true
1000
+ 2 true false
1001
+ 3 false true
891
1002
  ```
892
1003
 
893
1004
  `:reduced_ascii`&mdash;similar to `:ascii`, but without vertical lines:
@@ -901,6 +1012,17 @@ This is done using the `border` option passed to `Table.new`. The options are as
901
1012
  2 true false
902
1013
  3 false true
903
1014
  -------------- -------------- --------------
1015
+
1016
+ > puts Tabulo::Table.new(1..3, :itself, :even?, :odd?, border: :reduced_modern, title: "Numbers")
1017
+ --------------------------------------------
1018
+ Numbers
1019
+ -------------- -------------- --------------
1020
+ itself even? odd?
1021
+ -------------- -------------- --------------
1022
+ 1 false true
1023
+ 2 true false
1024
+ 3 false true
1025
+ -------------- -------------- --------------
904
1026
  ```
905
1027
 
906
1028
  `:reduced_modern`&mdash;similar to `:modern`, but without vertical lines:
@@ -914,6 +1036,17 @@ This is done using the `border` option passed to `Table.new`. The options are as
914
1036
  2 true false
915
1037
  3 false true
916
1038
  ────────────── ────────────── ──────────────
1039
+
1040
+ > puts Tabulo::Table.new(1..3, :itself, :even?, :odd?, border: :reduced_ascii, title: "Numbers")
1041
+ ────────────────────────────────────────────
1042
+ Numbers
1043
+ ────────────── ────────────── ──────────────
1044
+ itself even? odd?
1045
+ ────────────── ────────────── ──────────────
1046
+ 1 false true
1047
+ 2 true false
1048
+ 3 false true
1049
+ ────────────── ────────────── ──────────────
917
1050
  ```
918
1051
 
919
1052
  `:classic`&mdash;reproduces the default behaviour in Tabulo v1; this is like the `:ascii` option,
@@ -927,6 +1060,16 @@ but without a bottom border:
927
1060
  | 1 | false | true |
928
1061
  | 2 | true | false |
929
1062
  | 3 | false | true |
1063
+
1064
+ > puts Tabulo::Table.new(1..3, :itself, :even?, :odd?, border: :classic, title: "Numbers")
1065
+ +--------------------------------------------+
1066
+ | Numbers |
1067
+ +--------------+--------------+--------------+
1068
+ | itself | even? | odd? |
1069
+ +--------------+--------------+--------------+
1070
+ | 1 | false | true |
1071
+ | 2 | true | false |
1072
+ | 3 | false | true |
930
1073
  ```
931
1074
 
932
1075
  Note that, by default, none of the border options includes lines drawn _between_ rows in the body of the table.
@@ -1144,14 +1287,14 @@ The gem is available as open source under the terms of the [MIT
1144
1287
  License](http://opensource.org/licenses/MIT).
1145
1288
 
1146
1289
  [Gem Version]: https://rubygems.org/gems/tabulo
1147
- [Documentation]: http://www.rubydoc.info/gems/tabulo/2.4.1
1290
+ [Documentation]: http://www.rubydoc.info/gems/tabulo/2.5.0
1148
1291
  [Build Status]: https://travis-ci.org/matt-harvey/tabulo
1149
1292
  [Coverage Status]: https://coveralls.io/r/matt-harvey/tabulo
1150
1293
  [Code Climate]: https://codeclimate.com/github/matt-harvey/tabulo
1151
1294
  [Awesome Ruby]: https://github.com/markets/awesome-ruby#cli-utilities
1152
1295
 
1153
1296
  [GV img]: https://img.shields.io/gem/v/tabulo.svg
1154
- [DC img]: https://img.shields.io/badge/documentation-v2.4.1-blue.svg
1297
+ [DC img]: https://img.shields.io/badge/documentation-v2.5.0-blue.svg
1155
1298
  [BS img]: https://img.shields.io/travis/matt-harvey/tabulo.svg
1156
1299
  [CS img]: https://img.shields.io/coveralls/matt-harvey/tabulo.svg
1157
1300
  [CC img]: https://codeclimate.com/github/matt-harvey/tabulo/badges/gpa.svg
data/VERSION CHANGED
@@ -1 +1 @@
1
- 2.4.1
1
+ 2.5.0
@@ -115,6 +115,10 @@ module Tabulo
115
115
  def horizontal_rule(column_widths, position = :bottom)
116
116
  left, center, right, segment =
117
117
  case position
118
+ when :title_top
119
+ [@corner_top_left, @edge_top, @corner_top_right, @edge_top]
120
+ when :title_bottom
121
+ [@tee_left, @tee_top, @tee_right, @edge_top]
118
122
  when :top
119
123
  [@corner_top_left, @tee_top, @corner_top_right, @edge_top]
120
124
  when :middle
@@ -123,6 +127,11 @@ module Tabulo
123
127
  [@corner_bottom_left, @tee_bottom, @corner_bottom_right, @edge_bottom]
124
128
  end
125
129
  segments = column_widths.map { |width| segment * width }
130
+
131
+ # Prevent weird bottom edge of title if segments empty but right/left not empty, as in
132
+ # Markdown border.
133
+ left = right = "" if segments.all?(&:empty?)
134
+
126
135
  style("#{left}#{segments.join(center)}#{right}")
127
136
  end
128
137
 
@@ -43,13 +43,18 @@ module Tabulo
43
43
  # @param [:left, :right, :center] align_header (:center) Determines the alignment of header text
44
44
  # for columns in this Table. Can be overridden for individual columns using the
45
45
  # <tt>align_header</tt> option passed to {#add_column}
46
+ # @param [:left, :right, :center] align_header (:center) Determines the alignment of the table
47
+ # title, if present.
46
48
  # @param [:ascii, :markdown, :modern, :blank, nil] border (nil) Determines the characters used
47
49
  # for the Table border, including both the characters around the outside of table, and the lines drawn
48
50
  # within the table to separate columns from each other and the header row from the Table body.
49
51
  # If <tt>nil</tt>, then the value of {DEFAULT_BORDER} will be used.
50
52
  # Possible values are:
51
53
  # - `:ascii` Uses ASCII characters only
52
- # - `:markdown` Produces a GitHub-flavoured Markdown table
54
+ # - `:markdown` Produces a GitHub-flavoured Markdown table. Note: Using the `title`
55
+ # option in combination with this border type will cause the rendered
56
+ # table not to be valid Markdown, since Markdown engines do not generally
57
+ # support adding a caption element (i.e. title) to tables.
53
58
  # - `:modern` Uses non-ASCII Unicode characters to render a border with smooth continuous lines
54
59
  # - `:blank` No border characters are rendered
55
60
  # - `:reduced_ascii` Like `:ascii`, but without left or right borders, and with internal vertical
@@ -89,6 +94,19 @@ module Tabulo
89
94
  # header row.
90
95
  # @param [nil, #to_proc] styler (nil) The default styler for columns in this table. See `styler`
91
96
  # option of {#add_column} for details.
97
+ # @param [nil, String] title (nil) If passed a String, will arrange for a title to be shown at the top
98
+ # of the table. Note: If the `border` option is set to `:markdown`, adding a title to the table
99
+ # will cause it to cease being valid Markdown when rendered, since Markdown engines do not generally
100
+ # support adding a caption element (i.e. title) to tables.
101
+ # @param [nil, #to_proc] title_styler (nil) A lambda or other callable object that will
102
+ # determine the colors or other styling applied to the table title. If the table doesn't have
103
+ # a title, this parameter has no effect. If passed a single-parameter callable, then that
104
+ # callable will be called for each line of content within the title, and the resulting string
105
+ # rendered in place of that line.
106
+ # The extra width of the string returned by the <tt>title_styler</tt> is not taken into
107
+ # consideration by the internal table width calculations involved in rendering the
108
+ # table. Thus it can be used to apply ANSI escape codes to title content, to color the
109
+ # title for example, without breaking the table formatting.
92
110
  # @param [nil, String] truncation_indicator Determines the character used to indicate that a
93
111
  # cell's content has been truncated. If omitted or passed <tt>nil</tt>,
94
112
  # defaults to {DEFAULT_TRUNCATION_INDICATOR}. If passed something other than <tt>nil</tt> or
@@ -107,15 +125,17 @@ module Tabulo
107
125
  # @return [Table] a new {Table}
108
126
  # @raise [InvalidColumnLabelError] if non-unique Symbols are provided to columns.
109
127
  # @raise [InvalidBorderError] if invalid option passed to `border` parameter.
110
- def initialize(sources, *columns, align_body: :auto, align_header: :center, border: nil,
111
- border_styler: nil, column_padding: nil, column_width: nil, formatter: :to_s.to_proc,
128
+ def initialize(sources, *columns, align_body: :auto, align_header: :center, align_title: :center,
129
+ border: nil, border_styler: nil, column_padding: nil, column_width: nil, formatter: :to_s.to_proc,
112
130
  header_frequency: :start, header_styler: nil, row_divider_frequency: nil, styler: nil,
113
- truncation_indicator: nil, wrap_body_cells_to: nil, wrap_header_cells_to: nil)
131
+ title: nil, title_styler: nil, truncation_indicator: nil, wrap_body_cells_to: nil,
132
+ wrap_header_cells_to: nil)
114
133
 
115
134
  @sources = sources
116
135
 
117
136
  @align_body = align_body
118
137
  @align_header = align_header
138
+ @align_title = align_title
119
139
  @border = (border || DEFAULT_BORDER)
120
140
  @border_styler = border_styler
121
141
  @border_instance = Border.from(@border, @border_styler)
@@ -130,6 +150,8 @@ module Tabulo
130
150
  @header_styler = header_styler
131
151
  @row_divider_frequency = row_divider_frequency
132
152
  @styler = styler
153
+ @title = title
154
+ @title_styler = title_styler
133
155
  @truncation_indicator = validate_character(truncation_indicator,
134
156
  DEFAULT_TRUNCATION_INDICATOR, InvalidTruncationIndicatorError, "truncation indicator")
135
157
  @wrap_body_cells_to = wrap_body_cells_to
@@ -339,7 +361,8 @@ module Tabulo
339
361
  end
340
362
  end
341
363
 
342
- # @return [String] an "ASCII" graphical representation of the Table column headers.
364
+ # @return [String] a graphical representation of the Table column headers formatted with fixed
365
+ # width plain text.
343
366
  def formatted_header
344
367
  cells = get_columns.map(&:header_cell)
345
368
  format_row(cells, @wrap_header_cells_to)
@@ -348,9 +371,11 @@ module Tabulo
348
371
  # Produce a horizontal dividing line suitable for printing at the top, bottom or middle
349
372
  # of the table.
350
373
  #
351
- # @param [:top, :middle, :bottom] position (:bottom) Specifies the position
352
- # for which the resulting horizontal dividing line is intended to be printed.
353
- # This determines the border characters that are used to construct the line.
374
+ # @param [:top, :middle, :bottom, :title_top, :title_bottom] position (:bottom)
375
+ # Specifies the position for which the resulting horizontal dividing line is intended to
376
+ # be printed. This determines the border characters that are used to construct the line.
377
+ # The `:title_top` and `:title_bottom` options are used internally for adding borders
378
+ # above and below the table title text.
354
379
  # @return [String] an "ASCII" graphical representation of a horizontal
355
380
  # dividing line.
356
381
  # @example Print a horizontal divider between each pair of rows, and again at the bottom:
@@ -368,10 +393,13 @@ module Tabulo
368
393
  @border_instance.horizontal_rule(column_widths, position)
369
394
  end
370
395
 
371
- # Reset all the column widths so that each column is *just* wide enough to accommodate
396
+ # Resets all the column widths so that each column is *just* wide enough to accommodate
372
397
  # its header text as well as the formatted content of each its cells for the entire
373
398
  # collection, together with a single character of padding on either side of the column,
374
- # without any wrapping.
399
+ # without any wrapping. In addition, if the table has a title but is not wide enough to
400
+ # accommodate (without wrapping) the title text (with a character of padding either side),
401
+ # widens the columns roughly evenly until the table as a whole is just wide enough to
402
+ # accommodate the title text.
375
403
  #
376
404
  # Note that calling this method will cause the entire source Enumerable to
377
405
  # be traversed and all the column extractors and formatters to be applied in order
@@ -411,6 +439,10 @@ module Tabulo
411
439
  shrink_to(max_table_width == :auto ? TTY::Screen.width : max_table_width)
412
440
  end
413
441
 
442
+ if @title
443
+ expand_to(Unicode::DisplayWidth.of(@title) + total_column_padding + (@border == :blank ? 0 : 2))
444
+ end
445
+
414
446
  self
415
447
  end
416
448
 
@@ -433,8 +465,9 @@ module Tabulo
433
465
  # The following options are the same as the keyword params for the {#initialize} method for
434
466
  # {Table}: <tt>column_width</tt>, <tt>column_padding</tt>, <tt>formatter</tt>,
435
467
  # <tt>header_frequency</tt>, <tt>row_divider_frequency</tt>, <tt>wrap_header_cells_to</tt>,
436
- # <tt>wrap_body_cells_to</tt>, <tt>border</tt>, <tt>border_styler</tt>, <tt>truncation_indicator</tt>,
437
- # <tt>align_header</tt>, <tt>align_body</tt>.
468
+ # <tt>wrap_body_cells_to</tt>, <tt>border</tt>, <tt>border_styler</tt>, <tt>title</tt>,
469
+ # <tt>title_styler</tt>, <tt>truncation_indicator</tt>, <tt>align_header</tt>, <tt>align_body</tt>,
470
+ # <tt>align_title</tt>.
438
471
  # These are applied in the same way as documented for {#initialize}, when
439
472
  # creating the new, transposed Table. Any options not specified explicitly in the call to {#transpose}
440
473
  # will inherit their values from the original {Table} (with the exception of settings
@@ -458,9 +491,9 @@ module Tabulo
458
491
  # @return [Table] a new {Table}
459
492
  # @raise [InvalidBorderError] if invalid argument passed to `border` parameter.
460
493
  def transpose(opts = {})
461
- default_opts = [:align_body, :align_header, :border, :border_styler, :column_padding, :column_width,
462
- :formatter, :header_frequency, :row_divider_frequency, :truncation_indicator, :wrap_body_cells_to,
463
- :wrap_header_cells_to].map do |sym|
494
+ default_opts = [:align_body, :align_header, :align_title, :border, :border_styler, :column_padding,
495
+ :column_width, :formatter, :header_frequency, :row_divider_frequency, :title, :title_styler,
496
+ :truncation_indicator, :wrap_body_cells_to, :wrap_header_cells_to].map do |sym|
464
497
  [sym, instance_variable_get("@#{sym}")]
465
498
  end.to_h
466
499
 
@@ -496,7 +529,16 @@ module Tabulo
496
529
  cells = get_columns.map.with_index { |c, i| c.body_cell(source, row_index: index, column_index: i) }
497
530
  inner = format_row(cells, @wrap_body_cells_to)
498
531
 
499
- if header == :top
532
+ if @title && header == :top
533
+ join_lines([
534
+ horizontal_rule(:title_top),
535
+ formatted_title,
536
+ horizontal_rule(:title_bottom),
537
+ formatted_header,
538
+ horizontal_rule(:middle),
539
+ inner
540
+ ].reject(&:empty?))
541
+ elsif header == :top
500
542
  join_lines([
501
543
  horizontal_rule(:top),
502
544
  formatted_header,
@@ -548,6 +590,44 @@ module Tabulo
548
590
  @column_registry[label] = column
549
591
  end
550
592
 
593
+ # @visibility private
594
+ def formatted_title
595
+ columns = get_columns
596
+ num_fudged_columns = columns.count - 1
597
+ basic_width = columns.inject(0) { |total_width, column| total_width + column.width }
598
+ extra_for_internal_dividers = (@border == :blank ? 0 : 1)
599
+ extra_for_internal_padding = @left_column_padding + @right_column_padding
600
+ extra_total = num_fudged_columns * (extra_for_internal_dividers + extra_for_internal_padding)
601
+ title_cell_width = basic_width + extra_total
602
+ styler =
603
+ if @title_styler
604
+ -> (v, s) { @title_styler.call(s) }
605
+ else
606
+ -> (v, s) { s }
607
+ end
608
+ title_cell = Cell.new(
609
+ alignment: @align_title,
610
+ cell_data: nil,
611
+ formatter: -> (s) { s },
612
+ padding_character: PADDING_CHARACTER,
613
+ styler: styler,
614
+ truncation_indicator: @truncation_indicator,
615
+ value: @title,
616
+ width: title_cell_width
617
+ )
618
+ cells = [title_cell]
619
+ max_cell_height = cells.map(&:height).max
620
+ row_height = ([nil, max_cell_height].compact.min || 1)
621
+ subcell_stacks = cells.map do |cell|
622
+ cell.padded_truncated_subcells(row_height, @left_column_padding, @right_column_padding)
623
+ end
624
+ subrows = subcell_stacks.transpose.map do |subrow_components|
625
+ @border_instance.join_cell_contents(subrow_components)
626
+ end
627
+
628
+ join_lines(subrows)
629
+ end
630
+
551
631
  # @!visibility private
552
632
  def normalize_column_label(label)
553
633
  case label
@@ -558,6 +638,25 @@ module Tabulo
558
638
  end
559
639
  end
560
640
 
641
+ # @!visibility private
642
+ def expand_to(min_table_width)
643
+ columns = get_columns
644
+ num_columns = columns.count
645
+ total_columns_width = columns.inject(0) { |sum, column| sum + column.width }
646
+ total_padding = num_columns * total_column_padding
647
+ total_borders = num_columns + 1
648
+ unadjusted_table_width = total_columns_width + total_padding + total_borders
649
+ required_increase = Util.max(min_table_width - unadjusted_table_width, 0)
650
+
651
+ required_increase.times do
652
+ narrowest_column = columns.inject(columns.first) do |narrowest, column|
653
+ column.width <= narrowest.width ? column : narrowest
654
+ end
655
+
656
+ narrowest_column.width += 1
657
+ end
658
+ end
659
+
561
660
  # @!visibility private
562
661
  def shrink_to(max_table_width)
563
662
  columns = get_columns
@@ -1,3 +1,3 @@
1
1
  module Tabulo
2
- VERSION = "2.4.1"
2
+ VERSION = "2.5.0"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: tabulo
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.4.1
4
+ version: 2.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Matthew Harvey
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2020-04-16 00:00:00.000000000 Z
11
+ date: 2020-04-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: tty-screen