tabulo 2.2.0 → 2.3.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: 295d0e4161611edd684ef1f65143767b418af24f0e630e83bb6554cf25636e44
4
- data.tar.gz: e4a0e0fcc8a2efdedb251d413f65f2627b7706136af55026728d6c906f0bc311
3
+ metadata.gz: 87e2e8bb108886b594c80a32396ab586c90792ae6e5efeb5769e457b13d6c96d
4
+ data.tar.gz: 03c93ac0d5419fb654244ab574d9e7aa43263f40ca71e008f6d43772a76ffece
5
5
  SHA512:
6
- metadata.gz: 8cc23cce74adbe70451dc387007baa32339ac8d0942d55594e8516ac871880c4ef8176a69db5da7dad2dcfa122d83ae838cb9129e3df8212f3a1ae4ab337c92a
7
- data.tar.gz: dfa4e051e1f45a41e3611b8c22422ee9f043671d4d7f432318fab6465c6b888c5a3e67302a3950e241d73dc17e99d3b26e2d2738b3eacc162f5a4e07b628acaa
6
+ metadata.gz: ae04026433b44638cd777f483fb0e8b0494370cc71fb84c5bc91cc38c65c92aa4e68183b48db1e92e53b3e3ede6b680975190d2626510f0ad31b6f651bb9538d
7
+ data.tar.gz: 5a543577d7d678ccee445789d588147a778fa45899876872749ad1ced9119e99369b43b1e7b642d2f9eae27c41d2e904de9d7765513b9b813824deac5e8d958c
data/CHANGELOG.md CHANGED
@@ -1,5 +1,13 @@
1
1
  # Changelog
2
2
 
3
+ ### v2.3.0
4
+
5
+ * Provide `#remove_column` method.
6
+ * Provide `before` option to `#add_column`, to allow insertion of column into non-final position.
7
+ * Provide `styler` and `header_styler` options in table initializer, to enable default stylers
8
+ to be set for all columns.
9
+ * Documentation improvements and code tidy-ups.
10
+
3
11
  ### v2.2.0
4
12
 
5
13
  * New `column_formatter` option on `Tabulo::Table` initializer, enabling the table's default column
@@ -15,7 +23,7 @@
15
23
 
16
24
  ### v2.1.0
17
25
 
18
- * New `:reduced_ascii` and `:reduced_modern` border options
26
+ * New `reduced_ascii` and `reduced_modern` border options
19
27
  * Fix `column_width` option not properly inherited from original table by the new table created
20
28
  by calling #transpose.
21
29
 
data/README.md CHANGED
@@ -7,13 +7,9 @@
7
7
  [![Code Climate][CC img]][Code Climate]
8
8
  [![Awesome][AR img]][Awesome Ruby]
9
9
 
10
- Tabulo is a terminal table generator for Ruby.
10
+ Tabulo is a terminal table generator for Ruby. It is both highly configurable and very easy to use.
11
11
 
12
- It offers a DRY, "column-centric" interface, and is designed to make it very easy to produce highly
13
- readable tables, even from large and unwieldy data sets and streams.
14
-
15
- Tabulo is both easy to use and feature rich, allowing you to quickly tabulate any enumerable
16
- collection, with options for automatic column sizing, a variety of border styles, and more.
12
+ _Quick API:_
17
13
 
18
14
  ```
19
15
  > puts Tabulo::Table.new(User.all, :id, :first_name, :last_name, border: :modern).pack
@@ -25,12 +21,35 @@ collection, with options for automatic column sizing, a variety of border styles
25
21
  └────┴────────────┴───────────┘
26
22
  ```
27
23
 
24
+ _Full API:_
25
+
26
+ ```
27
+ table = Tabulo::Table.new(User.all, border: :modern) do |t|
28
+ t.add_column("ID", &:id)
29
+ t.add_column("First name", &:first_name)
30
+ t.add_column("Last name") { |user| user.last_name.upcase }
31
+ end
32
+ ```
33
+
34
+ ```
35
+ > puts table.pack
36
+ ┌────┬────────────┬───────────┐
37
+ │ ID │ First name │ Last name │
38
+ ├────┼────────────┼───────────┤
39
+ │ 1 │ John │ CITIZEN │
40
+ │ 2 │ Jane │ DOE │
41
+ └────┴────────────┴───────────┘
42
+ ```
43
+
28
44
  ## Features
29
45
 
46
+ * Presents a [DRY initialization interface](#configuring-columns): by being “column based” rather than
47
+ “row based”, it spares the developer the burden of syncing the ordering within the header row
48
+ with that of the body rows.
30
49
  * Lets you set [fixed column widths](#fixed-column-widths), then either [wrap](#overflow-handling)
31
50
  or [truncate](#overflow-handling) the overflow.
32
- * Alternatively, ["pack"](#pack) the table so that each column is automatically just wide enough for
33
- its contents, but [without overflowing the terminal horizontally](#max-table-width).
51
+ * Alternatively, you can [“pack”](#pack) the table so that each column is automatically just
52
+ wide enough for its contents, but [without overflowing the terminal horizontally](#max-table-width).
34
53
  * Alignment of cell content is [configurable](#cell-alignment), but has helpful content-based
35
54
  defaults (numbers right, strings left).
36
55
  * Tabulate any `Enumerable`: the underlying collection need not be an array.
@@ -44,9 +63,8 @@ collection, with options for automatic column sizing, a variety of border styles
44
63
  * Multibyte Unicode characters are correctly handled.
45
64
  * Apply [colours](#colours-and-styling) and other styling to table content and borders, without breaking the table.
46
65
  * Easily [transpose](#transposition) the table, so that rows are swapped with columns.
47
- * Choose from multiple [border configurations](#borders), including Markdown, "ASCII", and smoothly joined Unicode border characters.
48
- * Use a [DRY initialization interface](#configuring-columns): by being "column based", it is
49
- designed to spare the developer the burden of syncing the ordering within the header row with that of the body rows.
66
+ * Choose from multiple [border configurations](#borders), including Markdown, “ASCII”, and smoothly
67
+ joined Unicode border characters.
50
68
 
51
69
  Tabulo has also been ported to Crystal (with some modifications): see [Tablo](https://github.com/hutou/tablo).
52
70
 
@@ -65,7 +83,11 @@ Tabulo has also been ported to Crystal (with some modifications): see [Tablo](ht
65
83
  * [Automating column widths](#automating-column-widths)
66
84
  * [Overflow handling](#overflow-handling)
67
85
  * [Formatting cell values](#formatting-cell-values)
68
- * [Colours and styling](#colours-and-styling)
86
+ * [Colours and other styling](#colours-and-styling)
87
+ * [Styling cell content](#styling-cell-content)
88
+ * [Styling column headers](#styling-column-headers)
89
+ * [Setting default styles](#default-styles)
90
+ * [Styling borders](#border-styling)
69
91
  * [Repeating headers](#repeating-headers)
70
92
  * [Using a Table Enumerator](#using-a-table-enumerator)
71
93
  * [Accessing cell values](#accessing-cell-values)
@@ -73,13 +95,14 @@ Tabulo has also been ported to Crystal (with some modifications): see [Tablo](ht
73
95
  * [Transposing rows and columns](#transposition)
74
96
  * [Border configuration](#borders)
75
97
  * [Row dividers](#dividers)
98
+ * [Using a table as a snapshot rather than as a dynamic view](#freezing-a-table)
76
99
  * [Comparison with other libraries](#motivation)
77
100
  * [Contributing](#contributing)
78
101
  * [License](#license)
79
102
 
80
103
  ## Installation
81
104
 
82
- Add this line to your application's Gemfile:
105
+ Add this line to your application’s Gemfile:
83
106
 
84
107
  ```ruby
85
108
  gem 'tabulo'
@@ -126,7 +149,7 @@ table = Tabulo::Table.new([1, 2, 5]) do |t|
126
149
  end
127
150
  ```
128
151
 
129
- When the columns correspond to methods, you can also use the "quick API", by passing a symbol
152
+ When the columns correspond to methods, you can also use the “quick API”, by passing a symbol
130
153
  directly to `new` for each column:
131
154
 
132
155
  ```ruby
@@ -167,6 +190,30 @@ end
167
190
  +--------------+--------------+--------------+
168
191
  ```
169
192
 
193
+ By default, each new column is added to the right of all the other columns so far added to the
194
+ table. However, if you want to insert a new column into some other position, you can use the
195
+ `before` option, passing the label of the column to the left of which you want the new column to be added:
196
+
197
+ ```ruby
198
+ table = Table::Table.new([1, 2, 3], :itself, :odd?)
199
+ table.add_column(:even?, before: :odd?)
200
+ ```
201
+
202
+ ```
203
+ > puts table
204
+ +--------------+--------------+--------------+
205
+ | itself | even? | odd? |
206
+ +--------------+--------------+--------------+
207
+ | 1 | false | true |
208
+ | 2 | true | false |
209
+ | 5 | false | true |
210
+ +--------------+--------------+--------------+
211
+ ```
212
+
213
+ There is also a `#remove_column` method, for deleting an existing column from a table; see the
214
+ [documentation](https://www.rubydoc.info/gems/tabulo/2.3.0/Tabulo/Table#remove_column-instance_method)
215
+ for details.
216
+
170
217
  <a name="cell-alignment"></a>
171
218
  ### Cell alignment
172
219
 
@@ -278,7 +325,7 @@ table = Tabulo::Table.new([1, 2, 5], :itself, :even?, :odd?, column_padding: [0,
278
325
  <a name="pack"></a>
279
326
  #### Automating column widths
280
327
 
281
- Instead of setting column widths "manually", you can tell the table to sort out the widths
328
+ Instead of setting column widths &ldquo;manually&rdquo;, you can tell the table to sort out the widths
282
329
  itself, so that each column is just wide enough for its header and contents (plus a character
283
330
  of padding):
284
331
 
@@ -297,7 +344,7 @@ table.pack
297
344
  +--------+-------+
298
345
  ```
299
346
 
300
- The `pack` method returns the table itself, so you can "pack-and-print" in one go:
347
+ The `pack` method returns the table itself, so you can &ldquo;pack-and-print&rdquo; in one go:
301
348
 
302
349
  ```ruby
303
350
  puts Tabulo::Table.new([1, 2], :itself, :even?).pack
@@ -334,12 +381,15 @@ the table will fit.
334
381
 
335
382
  Note that `pack`ing the table necessarily involves traversing the entire collection up front as
336
383
  the maximum cell width needs to be calculated for each column. You may not want to do this
337
- if the collection is very large. Note also the effect of `pack` is to fix the column widths
338
- as appropriate to the formatted cell contents given the state of the underlying collection
339
- _at the point of packing_. If the underlying collection changes between that point, and when
340
- the table is printed, then the columns will _not_ be resized yet again on printing. This is a
341
- consequence of the table always being essentially a "live view" on the underlying collection:
342
- formatted contents are never cached within the table itself.
384
+ if the collection is very large.
385
+
386
+ Note also the effect of `pack` is to fix the column widths as appropriate to the formatted cell
387
+ contents given the state of the underlying collection _at the point of packing_. If the underlying
388
+ collection changes between that point, and when the table is printed, then the columns will _not_ be
389
+ resized yet again on printing. This is a consequence of the table always being essentially a
390
+ &ldquo;live view&rdquo; on the underlying collection: formatted contents are never cached within the
391
+ table itself. There are [ways around this](#freezing-a-table), however, if this is not the desired
392
+ behaviour&mdash;see [below](#freezing-a-table).
343
393
 
344
394
  <a name="overflow-handling"></a>
345
395
  #### Overflow handling
@@ -397,10 +447,10 @@ The character used to indicate truncation, which defaults to `~`, can be configu
397
447
  ### Formatting cell values
398
448
 
399
449
  While the callable passed to `add_column` determines the underyling, calculated value in each
400
- cell of the column, there is a separate concept, of a "formatter", that determines how that value will
401
- be visually displayed. By default, `.to_s` is called on the underlying cell value to "format"
402
- it; however, you can format it differently by passing another callable to the `formatter` option
403
- of `add_column`:
450
+ cell of the column, there is a separate concept, of a &ldquo;formatter&rdquo;, that determines how
451
+ that value will be visually displayed. By default, `.to_s` is called on the underlying cell value to
452
+ &ldquo;format&rdquo; it; however, you can format it differently by passing another callable to the
453
+ `formatter` option of `add_column`:
404
454
 
405
455
  ```ruby
406
456
  table = Tabulo::Table.new(1..3) do |t|
@@ -422,7 +472,7 @@ end
422
472
  +--------------+--------------+
423
473
  ```
424
474
 
425
- Note the numbers in the "Reciprocal" column in this example are still right-aligned, even though
475
+ Note the numbers in the &ldquo;Reciprocal&rdquo; column in this example are still right-aligned, even though
426
476
  the callable passed to `formatter` returns a String. Default cell alignment is determined by the type
427
477
  of the underlying cell value, not the way it is formatted. This is usually the desired result.
428
478
 
@@ -452,7 +502,10 @@ Formatters set for individual columns on calling `#add_column` always override t
452
502
  the table.
453
503
 
454
504
  <a name="colours-and-styling"></a>
455
- ### Colours and styling
505
+ ### Colours and other styling
506
+
507
+ <a name="styling-cell-content"></a>
508
+ #### Styling cell content
456
509
 
457
510
  In most terminals, if you want to print text that is coloured, or has certain other styles such as
458
511
  underlining, you need to use ANSI escape sequences, either directly, or by means of a library such
@@ -485,13 +538,19 @@ table.add_column(
485
538
  )
486
539
  ```
487
540
 
488
- The `styler` option should be passed a callable that takes two parameters: the
489
- first represents the content of the cell (in this case a boolean indicating whether the
490
- number is even); and the second represents the formatted string value of that cell, i.e. the
491
- cell content after any processing by the [formatter](#formatting-cell-values).
492
- If the content of a cell is wrapped over multiple lines, then the `styler` will be called
493
- once per line, so that each line of the cell will have the escape sequence applied to it
494
- separately (ensuring the styling doesn't bleed into neighbouring cells).
541
+ The `styler` option should be passed a callable that takes two parameters: the first represents
542
+ the underlying value of the cell (in this case a boolean indicating whether the number is even);
543
+ and the second represents the formatted string value of that cell, i.e. the cell content after
544
+ any processing by the [formatter](#formatting-cell-values). If the content of a cell is wrapped
545
+ over multiple lines, then the `styler` will be called once per line, so that each line of the
546
+ cell will have the escape sequence applied to it separately (ensuring the styling doesn&#8217;t bleed
547
+ into neighbouring cells).
548
+
549
+ If the content of a cell has been [truncated](#overflow-handling), then whatever colours or other styling
550
+ apply to the cell content will also be applied the truncation indicator character.
551
+
552
+ <a name="styling-column-headers"></a>
553
+ #### Styling column headers
495
554
 
496
555
  If you want to apply colours or other styling to the content of a column header, as opposed
497
556
  to cells in the table body, use the `header_styler` option, e.g.:
@@ -500,23 +559,39 @@ to cells in the table body, use the `header_styler` option, e.g.:
500
559
  table.add_column(:even?, header_styler: -> (s) { "\033[32m#{s}\033[0m" })
501
560
  ```
502
561
 
503
- To apply colours or other styling to the row divider, column divider, corner and border
504
- characters of the table, use the `border_styler` option when initializing the table, e.g.:
562
+ <a name="default-styles"></a>
563
+ #### Setting default styles
564
+
565
+ By default, no styling is applied to the headers or body content of a column unless configured to do
566
+ so via the `header_styler` or `styler` option when calling `add_column` for that particular column.
567
+ It is possible to apply styling by default to _all_ columns in a table, however, as the table initializer
568
+ also accepts both a `header_styler` and a `styler` option. For example, if you want all the header text
569
+ in the table to be green, you could do:
505
570
 
506
571
  ```ruby
507
- table = Tabulo::Table.new(1..5, :itself, :even?, :odd?, border_styler: -> (s) { "\033[32m#{s}\033[0m" })
572
+ table = Tabulo::Table.new(1..5, :itself, :even?, :odd?, header_styler: -> (s) { "\033[32m#{s}\033[0m" })
508
573
  ```
509
574
 
510
- If the content of a cell has been [truncated](#overflow-handling), then whatever colours or other styling
511
- apply to the cell content will also be applied the truncation indicator character.
575
+ Now, all columns in the table will have automatically have green header text, unless overridden
576
+ by another header styler being passed to `#add_column`.
577
+
578
+ <a name="border-styling"></a>
579
+ #### Styling borders
580
+
581
+ Styling can also be applied to borders and dividing lines, using the `border_styler` option when
582
+ initializing the table, e.g.:
583
+
584
+ ```ruby
585
+ table = Tabulo::Table.new(1..5, :itself, :even?, :odd?, border_styler: -> (s) { "\033[32m#{s}\033[0m" })
586
+ ```
512
587
 
513
588
  <a name="repeating-headers"></a>
514
589
  ### Repeating headers
515
590
 
516
591
  By default, headers are only shown once, at the top of the table (`header_frequency: :start`). If
517
592
  `header_frequency` is passed `nil`, headers are not shown at all; or, if passed an `Integer` N,
518
- headers are shown at the top and then repeated every N rows. This can be handy when you're looking
519
- at table that's taller than your terminal.
593
+ headers are shown at the top and then repeated every N rows. This can be handy when you&#8217;re looking
594
+ at table that&#8217;s taller than your terminal.
520
595
 
521
596
  E.g.:
522
597
 
@@ -548,7 +623,7 @@ table = Tabulo::Table.new(1..10, :itself, :even?, header_frequency: 5)
548
623
  <a name="enumerator"></a>
549
624
  ### Using a Table Enumerator
550
625
 
551
- Because it's an `Enumerable`, a `Tabulo::Table` can also give you an `Enumerator`,
626
+ Because it&#8217;s an `Enumerable`, a `Tabulo::Table` can also give you an `Enumerator`,
552
627
  which is useful when you want to step through rows one at a time. In a Rails console,
553
628
  for example, you might do this:
554
629
 
@@ -596,8 +671,8 @@ end
596
671
 
597
672
  The first argument to `add_column` always provides the key for the purpose of accessing the `Hash`
598
673
  form of a `Tabulo::Row`. (If the provided argument was a `String`, it will be converted to a
599
- `Symbol` for purposes of accessing this `Hash`.) This key serves as a sort of "logical label" for
600
- the column; and it need not be the same as the column header. If we want the header to be different
674
+ `Symbol` for purposes of accessing this `Hash`.) This key serves as a sort of &ldquo;logical label&rdquo;
675
+ for the column; and it need not be the same as the column header. If we want the header to be different
601
676
  to the label, we can achieve this using the `header` option to `add_column`:
602
677
 
603
678
  ```ruby
@@ -676,8 +751,8 @@ a new table in which the rows and columns are swapped:
676
751
 
677
752
  By default, a header row is added to the new table, showing the string value of the element
678
753
  represented in that column. This can be configured, however, along with other aspects of
679
- `transpose`'s behaviour. For details, see the
680
- [documentation](https://www.rubydoc.info/gems/tabulo/2.2.0/Tabulo/Table#transpose-instance_method).
754
+ `transpose`&#8217;s behaviour. For details, see the
755
+ [documentation](https://www.rubydoc.info/gems/tabulo/2.3.0/Tabulo/Table#transpose-instance_method).
681
756
 
682
757
  <a name="borders"></a>
683
758
  ### Configuring borders
@@ -813,6 +888,76 @@ If you want a line before every row, pass `1` to `row_divider_frequency`. For ex
813
888
  └──────────────┴──────────────┴──────────────┘
814
889
  ```
815
890
 
891
+ <a name="freezing-a-table"></a>
892
+ ### Using a table as a snapshot rather than as a dynamic view
893
+
894
+ The nature of a `Tabulo::Table` is that of a dynamic view onto the underlying `sources` enumerable
895
+ from which it was initialized (or which was subsequently assigned to its `sources` attribute). That
896
+ is, if the contents of the `sources` enumerable change subsequent to initialization of or assignment to
897
+ `sources`, then the table when printed will show the `sources` as they are at the time of printing,
898
+ not as they were at the time of initialization or assignment. For example:
899
+
900
+ ```ruby
901
+ arr = [1, 2]
902
+ table = Tabulo::Table.new(arr, :itself, :even?, :odd?)
903
+ ```
904
+
905
+ ```
906
+ > puts table
907
+ +--------------+--------------+--------------+
908
+ | itself | even? | odd? |
909
+ +--------------+--------------+--------------+
910
+ | 1 | false | true |
911
+ | 2 | true | false |
912
+ +--------------+--------------+--------------+
913
+ ```
914
+
915
+ ```ruby
916
+ arr << 3
917
+ ```
918
+
919
+ ```
920
+ > puts table
921
+ +--------------+--------------+--------------+
922
+ | itself | even? | odd? |
923
+ +--------------+--------------+--------------+
924
+ | 1 | false | true |
925
+ | 2 | true | false |
926
+ | 3 | false | true |
927
+ +--------------+--------------+--------------+
928
+ ```
929
+
930
+ In this example, even though no direct mutations have been made to `table`, the result
931
+ of calling `puts table` has changed, in virtue of a mutation on the underyling enumerable `arr`.
932
+
933
+ A similar behaviour can be seen when `sources` is an ActiveRecord query, and there
934
+ are changes to the relevant database table(s) such that the result of the query changes. This is
935
+ worth bearing in mind when calling [`pack`](#pack) on a table, since if the `sources` enumerable
936
+ changes between `pack`ing and printing, then the column widths calculated by the `pack` method
937
+ may no longer be &ldquo;just right&rdquo; given the changed `sources`.
938
+
939
+ If this is not the desired behaviour, there are ways around this. For example, if dealing with an
940
+ ActiveRecord relation, you can convert the query to a plain array before initializing the table:
941
+
942
+ ```ruby
943
+ sources = User.all.to_a
944
+ table = Tabulo::Table.new(sources, :id, :first_name, :last_name)
945
+ table.pack
946
+ puts table
947
+ ```
948
+
949
+ Passing an `Array` rather than the ActiveRecord query directly means that if there are changes to
950
+ the content of the `users` database table, these will not be reflected in the rendered content of
951
+ the `Tabulo::Table` (unless some of the `Tabulo::Table` columns are based on callables that perform
952
+ further database queries when called&hellip;).
953
+
954
+ Note that it is also possible simply to store the string value of a table for later use,
955
+ rather than the table itself:
956
+
957
+ ```ruby
958
+ rendered_table = Tabulo::Table.new(1..10, :itself, :even?, :odd?).pack.to_s
959
+ ```
960
+
816
961
  <a name="motivation"></a>
817
962
  ## Comparison with other libraries
818
963
 
@@ -826,7 +971,7 @@ There are other libraries for generating plain text tables in Ruby. Popular amon
826
971
  *DISCLAIMER: My comments regarding these other libraries are based only on my own, possibly flawed
827
972
  reading of the documentation for, and experimentation with, these libraries at the time of my
828
973
  writing this. Their APIs, features or documentation may well change between when I write this, and
829
- when you read it. Please consult the libraries' own documentation for yourself, rather than relying
974
+ when you read it. Please consult the libraries&#8217; own documentation for yourself, rather than relying
830
975
  on these comments.*
831
976
 
832
977
  While these libraries have their strengths, I have personally found that, for the common use case of
@@ -835,7 +980,7 @@ query result), using these libraries feels more cumbersome than it could be.
835
980
 
836
981
  For example, suppose we have called `User.all` from the Rails console, and want to print
837
982
  a table showing the email, first name, last name and ID of each user,
838
- with column headings. Also, we want the ID column to be right-aligned, because it's a number.
983
+ with column headings. Also, we want the ID column to be right-aligned, because it&#8217;s a number.
839
984
 
840
985
  In **terminal-table**, we could achieve this as follows:
841
986
 
@@ -848,7 +993,7 @@ puts table
848
993
  ```
849
994
 
850
995
  The problem here is that there is no single source of knowledge about which columns
851
- appear, and in which order. If we want to add another column to the left of "email",
996
+ appear, and in which order. If we want to add another column to the left of &ldquo;email&rdquo;,
852
997
  we need to amend the rows array, and the headings array, and the index passed to `align_column`.
853
998
  We bear the burden of keeping these three in sync. This is not be a big deal for small one-off
854
999
  tables, but for tables that have many columns, or that are constructed
@@ -856,9 +1001,9 @@ dynamically based on user input or other runtime factors determining the columns
856
1001
  to be included, this can be a hassle and a source of brittleness.
857
1002
 
858
1003
  **tty-table** has a somewhat different API to `terminal-table`. It offers both a
859
- "row-based" and a "column-based" method of initializing a table. The row-based method
860
- is similar to `terminal-table`'s in that it burdens the developer with syncing the
861
- column ordering across multiple code locations. The "column-based" API for `tty-table`, on
1004
+ &ldquo;row-based&rdquo; and a &ldquo;column-based&rdquo; method of initializing a table. The row-based method
1005
+ is similar to `terminal-table`&#8217;s in that it burdens the developer with syncing the
1006
+ column ordering across multiple code locations. The &ldquo;column-based&rdquo; API for `tty-table`, on
862
1007
  the other hand, seems to avoid this problem. One way of using it is like this:
863
1008
 
864
1009
  ```ruby
@@ -874,26 +1019,27 @@ table = TTY::Table.new [
874
1019
  puts table
875
1020
  ```
876
1021
 
877
- While this doesn't seem too bad, it does mean that the underlying collection (`users`) has to
1022
+ While this doesn&#8217;t seem too bad, it does mean that the underlying collection (`users`) has to
878
1023
  be traversed multiple times, once for each column, which is inefficient, particularly
879
- if the underlying collection is large. In addition, it's not clear how to pass separate
1024
+ if the underlying collection is large. In addition, it&#8217;s not clear how to pass separate
880
1025
  formatting information for each column when initializing in this way. (Perhaps there is a way to do
881
- this, but if there is, it doesn't seem to be documented.) So it seems we still have to use
1026
+ this, but if there is, it doesn&#8217;t seem to be documented.) So it seems we still have to use
882
1027
  `table.align_column(3, :right)`, which again burdens us with keeping the column index
883
1028
  passed to `align_column` in sync.
884
1029
 
885
1030
  As for **table\_print**, this is a handy gem for quickly tabulating ActiveRecord
886
1031
  collections from the Rails console. `table_print` is similar to `tabulo` in that it has a
887
- column-based API, so it doesn't suffer from the multiple-source-of-knowledge issue in regards to
1032
+ column-based API, so it doesn&#8217;t suffer from the multiple-source-of-knowledge issue in regards to
888
1033
  column orderings. However, it lacks certain other useful features, such as the ability to repeat
889
1034
  headers every N rows, the automatic alignment of columns based on cell content (numbers right,
890
1035
  strings left), and a quick and easy way to automatically resize columns to accommodate cell content
891
- without overflowing the terminal. Also, as of the time of writing, `table_print`'s last significant
1036
+ without overflowing the terminal. Also, as of the time of writing, `table_print`&#8217;s last significant
892
1037
  commit (ignoring a deprecation warning fix in April 2018) was in March 2016.
893
1038
 
894
- Finally, it is worth mentioning the **hirb** library. This is similar to `table_print`, in that it's
1039
+ Finally, it is worth mentioning the **hirb** library. This is similar to `table_print`, in that
1040
+ it&#8217;s
895
1041
  well suited to quickly displaying ActiveRecord collections from the Rails console. However, like
896
- `table_print`, there are certain useful features it's lacking; and using it outside the console
1042
+ `table_print`, there are certain useful features it&#8217;s lacking; and using it outside the console
897
1043
  environment seems cumbersome. Moreover, it seems no longer to be maintained. At the time of writing,
898
1044
  its last commit was in March 2015.
899
1045
 
@@ -915,14 +1061,14 @@ The gem is available as open source under the terms of the [MIT
915
1061
  License](http://opensource.org/licenses/MIT).
916
1062
 
917
1063
  [Gem Version]: https://rubygems.org/gems/tabulo
918
- [Documentation]: http://www.rubydoc.info/gems/tabulo/2.2.0
1064
+ [Documentation]: http://www.rubydoc.info/gems/tabulo/2.3.0
919
1065
  [Build Status]: https://travis-ci.org/matt-harvey/tabulo
920
1066
  [Coverage Status]: https://coveralls.io/r/matt-harvey/tabulo
921
1067
  [Code Climate]: https://codeclimate.com/github/matt-harvey/tabulo
922
1068
  [Awesome Ruby]: https://github.com/markets/awesome-ruby#cli-utilities
923
1069
 
924
1070
  [GV img]: https://img.shields.io/gem/v/tabulo.svg
925
- [DC img]: https://img.shields.io/badge/documentation-v2.2.0-blue.svg
1071
+ [DC img]: https://img.shields.io/badge/documentation-v2.3.0-blue.svg
926
1072
  [BS img]: https://img.shields.io/travis/matt-harvey/tabulo.svg
927
1073
  [CS img]: https://img.shields.io/coveralls/matt-harvey/tabulo.svg
928
1074
  [CC img]: https://codeclimate.com/github/matt-harvey/tabulo/badges/gpa.svg
data/VERSION CHANGED
@@ -1 +1 @@
1
- 2.2.0
1
+ 2.3.0
data/lib/tabulo/column.rb CHANGED
@@ -6,16 +6,23 @@ module Tabulo
6
6
  attr_accessor :width
7
7
  attr_reader :header
8
8
 
9
- def initialize(header:, width:, align_header:, align_body:, formatter:, extractor:, styler:,
10
- header_styler:, truncation_indicator:, padding_character:)
9
+ def initialize(
10
+ align_body:,
11
+ align_header:,
12
+ extractor:,
13
+ formatter:,
14
+ header:,
15
+ header_styler:,
16
+ padding_character:,
17
+ styler:,
18
+ truncation_indicator:,
19
+ width:)
11
20
 
12
- @header = header
13
- @width = width
14
- @align_header = align_header
15
21
  @align_body = align_body
16
- @formatter = formatter
22
+ @align_header = align_header
17
23
  @extractor = extractor
18
- @styler = styler || -> (_, s) { s }
24
+ @formatter = formatter
25
+ @header = header
19
26
 
20
27
  @header_styler =
21
28
  if header_styler
@@ -24,31 +31,33 @@ module Tabulo
24
31
  -> (_, s) { s }
25
32
  end
26
33
 
27
- @truncation_indicator = truncation_indicator
28
34
  @padding_character = padding_character
35
+ @styler = styler || -> (_, s) { s }
36
+ @truncation_indicator = truncation_indicator
37
+ @width = width
29
38
  end
30
39
 
31
40
  def header_cell
32
41
  Cell.new(
33
- value: @header,
34
- formatter: -> (s) { s },
35
42
  alignment: @align_header,
36
- width: @width,
43
+ formatter: -> (s) { s },
44
+ padding_character: @padding_character,
37
45
  styler: @header_styler,
38
46
  truncation_indicator: @truncation_indicator,
39
- padding_character: @padding_character,
47
+ value: @header,
48
+ width: @width,
40
49
  )
41
50
  end
42
51
 
43
52
  def body_cell(source)
44
53
  Cell.new(
45
- value: body_cell_value(source),
46
- formatter: @formatter,
47
54
  alignment: @align_body,
48
- width: @width,
55
+ formatter: @formatter,
56
+ padding_character: @padding_character,
49
57
  styler: @styler,
50
58
  truncation_indicator: @truncation_indicator,
51
- padding_character: @padding_character,
59
+ value: body_cell_value(source),
60
+ width: @width,
52
61
  )
53
62
  end
54
63
 
data/lib/tabulo/row.rb CHANGED
@@ -7,11 +7,11 @@ module Tabulo
7
7
  attr_reader :source
8
8
 
9
9
  # @!visibility private
10
- def initialize(table, source, header: :top, divider: false)
10
+ def initialize(table, source, divider: false, header: :top)
11
11
  @table = table
12
12
  @source = source
13
- @header = header
14
13
  @divider = divider
14
+ @header = header
15
15
  end
16
16
 
17
17
  # Calls the given block once for each {Cell} in the {Row}, passing that {Cell} as parameter.
data/lib/tabulo/table.rb CHANGED
@@ -74,17 +74,21 @@ module Tabulo
74
74
  # element indicates the amount to apply to the right.
75
75
  # @param [Integer, nil] column_width The default column width for columns in this
76
76
  # table, not excluding padding. If <tt>nil</tt>, then {DEFAULT_COLUMN_WIDTH} will be used.
77
- # @param [nil, #to_proc] formatter (:to_s.to_proc) The default value for the `formatter` option
78
- # when columns are added to this table via {#add_column}.
77
+ # @param [nil, #to_proc] formatter (:to_s.to_proc) The default formatter for columns in this
78
+ # table. See `formatter` option of {#add_column} for details.
79
79
  # @param [:start, nil, Integer] header_frequency (:start) Controls the display of column headers.
80
80
  # If passed <tt>:start</tt>, headers will be shown at the top of the table only. If passed <tt>nil</tt>,
81
81
  # headers will not be shown. If passed an Integer N (> 0), headers will be shown at the top of the table,
82
82
  # then repeated every N rows.
83
+ # @param [nil, #to_proc] header_styler (nil) The default header styler for columns in this
84
+ # table. See `header_styler` option of {#add_column} for details.
83
85
  # @param [nil, Integer] row_divider_frequency (nil) Controls the display of horizontal row dividers within
84
86
  # the table body. If passed <tt>nil</tt>, dividers will not be shown. If passed an Integer N (> 0),
85
87
  # dividers will be shown after every N rows. The characters used to form the dividers are
86
88
  # determined by the `border` option, and are the same as those used to form the bottom edge of the
87
89
  # header row.
90
+ # @param [nil, #to_proc] styler (nil) The default styler for columns in this table. See `styler`
91
+ # option of {#add_column} for details.
88
92
  # @param [nil, String] truncation_indicator Determines the character used to indicate that a
89
93
  # cell's content has been truncated. If omitted or passed <tt>nil</tt>,
90
94
  # defaults to {DEFAULT_TRUNCATION_INDICATOR}. If passed something other than <tt>nil</tt> or
@@ -114,7 +118,9 @@ module Tabulo
114
118
  column_width: nil,
115
119
  formatter: :to_s.to_proc,
116
120
  header_frequency: :start,
121
+ header_styler: nil,
117
122
  row_divider_frequency: nil,
123
+ styler: nil,
118
124
  truncation_indicator: nil,
119
125
  wrap_body_cells_to: nil,
120
126
  wrap_header_cells_to: nil)
@@ -139,6 +145,7 @@ module Tabulo
139
145
  @column_width = (column_width || DEFAULT_COLUMN_WIDTH)
140
146
  @formatter = formatter
141
147
  @header_frequency = header_frequency
148
+ @header_styler = header_styler
142
149
  @row_divider_frequency = row_divider_frequency
143
150
  @truncation_indicator = validate_character(truncation_indicator,
144
151
  DEFAULT_TRUNCATION_INDICATOR, InvalidTruncationIndicatorError, "truncation indicator")
@@ -171,6 +178,11 @@ module Tabulo
171
178
  # by the Table-level setting passed to the <tt>align_header</tt> (which itself defaults
172
179
  # to <tt>:center</tt>). Otherwise, this option determines the alignment of the header
173
180
  # content for this column.
181
+ # @param [Symbol, String, Integer, nil] before (nil) The label of the column before (i.e. to
182
+ # the left of) which the new column should inserted. If <tt>nil</tt> is passed, it will be
183
+ # inserted after all other columns. If there is no column with the given label, then an
184
+ # {InvalidColumnLabelError} will be raised. A non-Integer labelled column can be identified
185
+ # in either String or Symbol form for this purpose.
174
186
  # @param [#to_proc] formatter (nil) A lambda or other callable object that
175
187
  # will be passed the calculated value of each cell to determine how it should be displayed. This
176
188
  # is distinct from the extractor (see below). For example, if the extractor for this column
@@ -222,6 +234,7 @@ module Tabulo
222
234
  label,
223
235
  align_body: nil,
224
236
  align_header: nil,
237
+ before: nil,
225
238
  formatter: nil,
226
239
  header: nil,
227
240
  header_styler: nil,
@@ -241,19 +254,43 @@ module Tabulo
241
254
  raise InvalidColumnLabelError, "Column label already used in this table."
242
255
  end
243
256
 
244
- @column_registry[column_label] =
245
- Column.new(
246
- align_body: align_body || @align_body,
247
- align_header: align_header || @align_header,
248
- extractor: extractor || label.to_proc,
249
- formatter: formatter || @formatter,
250
- header: (header || label).to_s,
251
- header_styler: header_styler,
252
- padding_character: PADDING_CHARACTER,
253
- styler: styler,
254
- truncation_indicator: @truncation_indicator,
255
- width: width || @column_width,
256
- )
257
+ column = Column.new(
258
+ align_body: align_body || @align_body,
259
+ align_header: align_header || @align_header,
260
+ extractor: extractor || label.to_proc,
261
+ formatter: formatter || @formatter,
262
+ header: (header || label).to_s,
263
+ header_styler: header_styler || @header_styler,
264
+ padding_character: PADDING_CHARACTER,
265
+ styler: styler || @styler,
266
+ truncation_indicator: @truncation_indicator,
267
+ width: width || @column_width,
268
+ )
269
+
270
+ add_column_before(column, column_label, before)
271
+ end
272
+
273
+ # Removes the column identifed by the passed label.
274
+ #
275
+ # @example
276
+ # table = Table.new(1..10, :itself, :even?, :odd?)
277
+ # table.add_column(:even2, header: "even?") { |n| n.even? }
278
+ # table.remove_column(:even2)
279
+ # table.remove_column(:odd?)
280
+ #
281
+ # @param [Symbol, String, Integer] label The unique identifier for the column to be removed,
282
+ # corresponding to the label that was passed as the first parameter to {#add_column} (or was
283
+ # used in the table initializer) when the column was originally added. For columns that were
284
+ # originally added with a String or Symbol label, either a String or Symbol form of that label
285
+ # can be passed to {#remove_column}, indifferently. For example, if the label passed to
286
+ # {#add_column} had been `"height"`, then that column could be removed by passing either
287
+ # `"height"` or `:height` to {#remove_column}. (However, if an Integer was originally passed
288
+ # as the label to {#add_column}, then only that same Integer, as an Integer, can be passed to
289
+ # {#remove_column} to remove that column.)
290
+ # @return [true, false] If the label identifies a column in the table, then the column will be
291
+ # removed and true will be returned; otherwise no column will be removed, and false will be returned.
292
+ def remove_column(label)
293
+ !!column_registry.delete(Integer === label ? label : label.to_sym)
257
294
  end
258
295
 
259
296
  # @return [String] a graphical "ASCII" representation of the Table, suitable for
@@ -420,15 +457,15 @@ module Tabulo
420
457
  # @return [Table] a new {Table}
421
458
  # @raise [InvalidBorderError] if invalid argument passed to `border` parameter.
422
459
  def transpose(opts = {})
423
- default_opts = [:column_width, :column_padding, :formatter, :header_frequency,
424
- :row_divider_frequency, :wrap_header_cells_to, :wrap_body_cells_to, :truncation_indicator, :align_header,
425
- :align_body, :border, :border_styler].map do |sym|
460
+ default_opts = [:align_body, :align_header, :border, :border_styler, :column_padding, :column_width,
461
+ :formatter, :header_frequency, :row_divider_frequency, :truncation_indicator, :wrap_body_cells_to,
462
+ :wrap_header_cells_to].map do |sym|
426
463
  [sym, instance_variable_get("@#{sym}")]
427
464
  end.to_h
428
465
 
429
466
  initializer_opts = default_opts.merge(Util.slice_hash(opts, *default_opts.keys))
430
- default_extra_opts = { field_names_width: nil, field_names_header: "",
431
- field_names_body_alignment: :right, field_names_header_alignment: :right, headers: :to_s.to_proc }
467
+ default_extra_opts = { field_names_body_alignment: :right, field_names_header: "",
468
+ field_names_header_alignment: :right, field_names_width: nil, headers: :to_s.to_proc }
432
469
  extra_opts = default_extra_opts.merge(Util.slice_hash(opts, *default_extra_opts.keys))
433
470
 
434
471
  # The underlying enumerable for the new table, is the columns of the original table.
@@ -440,8 +477,9 @@ module Tabulo
440
477
  width_opt = extra_opts[:field_names_width]
441
478
  field_names_width = (width_opt.nil? ? fields.map { |f| f.header.length }.max : width_opt)
442
479
 
443
- t.add_column(:dummy, header: extra_opts[:field_names_header], width: field_names_width, align_header:
444
- extra_opts[:field_names_header_alignment], align_body: extra_opts[:field_names_body_alignment], &:header)
480
+ t.add_column(:dummy, align_body: extra_opts[:field_names_body_alignment],
481
+ align_header: extra_opts[:field_names_header_alignment], header: extra_opts[:field_names_header],
482
+ width: field_names_width, &:header)
445
483
 
446
484
  # Add a column to the new table for each of the original table's sources
447
485
  sources.each_with_index do |source, i|
@@ -476,6 +514,28 @@ module Tabulo
476
514
 
477
515
  private
478
516
 
517
+ # @!visibility private
518
+ def add_column_before(column, label, before)
519
+ if before == nil
520
+ @column_registry[label] = column
521
+ else
522
+ old_column_entries = @column_registry.to_a
523
+ new_column_entries = []
524
+ found = false
525
+ old_column_entries.each do |entry|
526
+ if entry[0] == before
527
+ found = true
528
+ new_column_entries << [label, column]
529
+ end
530
+ new_column_entries << entry
531
+ end
532
+ unless found
533
+ raise InvalidColumnLabelError, "There is no column with label #{before}"
534
+ end
535
+ @column_registry = new_column_entries.to_h
536
+ end
537
+ end
538
+
479
539
  # @!visibility private
480
540
  def total_column_padding
481
541
  @left_column_padding + @right_column_padding
@@ -1,3 +1,3 @@
1
1
  module Tabulo
2
- VERSION = "2.2.0"
2
+ VERSION = "2.3.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.2.0
4
+ version: 2.3.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-01-14 00:00:00.000000000 Z
11
+ date: 2020-02-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: tty-screen