tablesmith 0.4.1 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +5 -5
- data/.gitignore +2 -1
- data/.rubocop.yml +112 -2
- data/.ruby-version +1 -1
- data/.travis.yml +21 -0
- data/Appraisals +19 -0
- data/Gemfile +2 -0
- data/README.md +112 -11
- data/Rakefile +4 -2
- data/gemfiles/activerecord_4.gemfile +8 -0
- data/gemfiles/activerecord_5.1.gemfile +8 -0
- data/gemfiles/activerecord_5.2.gemfile +8 -0
- data/gemfiles/activerecord_6.0.gemfile +8 -0
- data/lib/tablesmith.rb +2 -0
- data/lib/tablesmith/active_record_source.rb +4 -2
- data/lib/tablesmith/array_rows_source.rb +3 -1
- data/lib/tablesmith/hash_rows_base.rb +4 -1
- data/lib/tablesmith/hash_rows_source.rb +8 -8
- data/lib/tablesmith/html_formatter.rb +1 -0
- data/lib/tablesmith/table.rb +34 -32
- data/lib/tablesmith/version.rb +3 -1
- data/spec/active_record_table_spec.rb +51 -49
- data/spec/array_table_spec.rb +61 -2
- data/spec/fixtures.rb +2 -0
- data/spec/hash_rows_table_spec.rb +15 -12
- data/spec/hash_table_spec.rb +23 -1
- data/spec/spec_helper.rb +6 -2
- data/spec/table_spec.rb +5 -3
- data/tablesmith.gemspec +15 -10
- metadata +77 -15
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: f7a031da03b4834e3512f66e1ee9541826d6dfdd7992d593dbbf686f9b5029d0
|
4
|
+
data.tar.gz: fcca01f815f5b51e31ff1c148e8137edec52a5405e54588216305e50d5ff1a3f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0e1360f9d29e4b9439253b5e6e40279842df875daa2d926f30b265ab32531befe69911dbe3f436cf4c99b0d0adb00188180e9aa5578f7b1f48a121a52149c2f6
|
7
|
+
data.tar.gz: e93c2e664a4c3809c557dc173643d9d38bc51c8913252490bbd46065e1a7c877fe54af44d8140a788e6478c083f93542dcf5fb2abaa8585a98cd44da32840a76
|
data/.gitignore
CHANGED
data/.rubocop.yml
CHANGED
@@ -4,8 +4,118 @@ require:
|
|
4
4
|
AllCops:
|
5
5
|
TargetRubyVersion: 2.3
|
6
6
|
|
7
|
-
Layout/
|
7
|
+
Layout/ClassStructure:
|
8
8
|
Enabled: true
|
9
|
+
Categories:
|
10
|
+
module_inclusion:
|
11
|
+
- include
|
12
|
+
- prepend
|
13
|
+
- extend
|
14
|
+
association:
|
15
|
+
- has_many
|
16
|
+
- has_one
|
17
|
+
- belongs_to
|
18
|
+
- has_and_belongs_to_many
|
19
|
+
validations:
|
20
|
+
- validate
|
21
|
+
- validates_inclusion_of
|
22
|
+
- validates_presence_of
|
23
|
+
callbacks:
|
24
|
+
- before_initialize
|
25
|
+
- before_validation
|
26
|
+
- before_save
|
27
|
+
- before_create
|
28
|
+
- before_update
|
29
|
+
- before_destroy
|
30
|
+
- after_save
|
31
|
+
- after_create
|
32
|
+
- after_validation
|
33
|
+
- after_initialize
|
34
|
+
- after_update
|
35
|
+
- after_destroy
|
36
|
+
enums:
|
37
|
+
- enum
|
38
|
+
scopes:
|
39
|
+
- scope
|
40
|
+
ExpectedOrder:
|
41
|
+
- association
|
42
|
+
- module_inclusion
|
43
|
+
- validations
|
44
|
+
- constants
|
45
|
+
- enums
|
46
|
+
- callbacks
|
47
|
+
- scopes
|
48
|
+
- public_class_methods
|
49
|
+
- initializer
|
50
|
+
- public_methods
|
51
|
+
- protected_methods
|
52
|
+
- private_methods
|
53
|
+
|
54
|
+
Layout/DotPosition:
|
55
|
+
EnforcedStyle: trailing
|
56
|
+
|
57
|
+
Lint/Void:
|
58
|
+
Exclude:
|
59
|
+
- 'spec/**'
|
60
|
+
|
61
|
+
Metrics:
|
62
|
+
Enabled: true
|
63
|
+
|
64
|
+
Metrics/AbcSize:
|
65
|
+
Max: 20
|
66
|
+
|
67
|
+
Metrics/BlockLength:
|
68
|
+
Exclude:
|
69
|
+
- 'Rakefile'
|
70
|
+
- '**/*.rake'
|
71
|
+
- 'spec/**/*.rb'
|
72
|
+
- 'test/**/*.rb'
|
73
|
+
ExcludedMethods: ['included', 'namespace']
|
74
|
+
|
75
|
+
Metrics/ClassLength:
|
76
|
+
Exclude:
|
77
|
+
- 'Rakefile'
|
78
|
+
- 'spec/**/*.rb'
|
79
|
+
- 'test/**/*.rb'
|
80
|
+
|
81
|
+
Metrics/LineLength:
|
82
|
+
Enabled: false
|
83
|
+
Max: 120
|
84
|
+
AllowHeredoc: true
|
85
|
+
AllowURI: true
|
86
|
+
URISchemes: http, https
|
87
|
+
|
88
|
+
Metrics/MethodLength:
|
89
|
+
CountComments: false # count full line comments?
|
90
|
+
Max: 15
|
91
|
+
|
92
|
+
Rails/Date:
|
93
|
+
Enabled: true
|
94
|
+
EnforcedStyle: flexible
|
95
|
+
|
96
|
+
Rails/RefuteMethods:
|
97
|
+
Enabled: true
|
98
|
+
|
99
|
+
Rails/TimeZone:
|
100
|
+
Enabled: true
|
101
|
+
EnforcedStyle: flexible
|
102
|
+
|
103
|
+
Style/ClassAndModuleChildren:
|
104
|
+
Enabled: false
|
9
105
|
|
10
106
|
Style/Documentation:
|
11
|
-
Enabled: false
|
107
|
+
Enabled: false
|
108
|
+
|
109
|
+
Style/DocumentationMethod:
|
110
|
+
Enabled: false
|
111
|
+
|
112
|
+
Style/FrozenStringLiteralComment:
|
113
|
+
EnforcedStyle: when_needed
|
114
|
+
Enabled: true
|
115
|
+
|
116
|
+
# Technically this performs better, and I got no problem with it.
|
117
|
+
Style/ParallelAssignment:
|
118
|
+
Enabled: false
|
119
|
+
|
120
|
+
Style/WhenThen:
|
121
|
+
Enabled: true
|
data/.ruby-version
CHANGED
@@ -1 +1 @@
|
|
1
|
-
2.
|
1
|
+
2.6.5
|
data/.travis.yml
CHANGED
@@ -1 +1,22 @@
|
|
1
1
|
language: ruby
|
2
|
+
|
3
|
+
rvm:
|
4
|
+
- 2.4.6
|
5
|
+
- 2.5.5
|
6
|
+
- 2.6.5
|
7
|
+
- 2.7.0
|
8
|
+
|
9
|
+
gemfile:
|
10
|
+
- gemfiles/activerecord_4.gemfile
|
11
|
+
- gemfiles/activerecord_5.1.gemfile
|
12
|
+
- gemfiles/activerecord_5.2.gemfile
|
13
|
+
- gemfiles/activerecord_6.0.gemfile
|
14
|
+
|
15
|
+
before_install: gem install bundler -v 2.1.2
|
16
|
+
|
17
|
+
jobs:
|
18
|
+
exclude:
|
19
|
+
- rvm: 2.4.6
|
20
|
+
gemfile: gemfiles/activerecord_6.0.gemfile
|
21
|
+
- rvm: 2.7.0
|
22
|
+
gemfile: gemfiles/activerecord_4.gemfile
|
data/Appraisals
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
appraise 'activerecord-4' do
|
2
|
+
gem 'activerecord', '~> 4.0'
|
3
|
+
gem 'sqlite3', '~> 1.3.6'
|
4
|
+
end
|
5
|
+
|
6
|
+
appraise 'activerecord-5.1' do
|
7
|
+
gem 'activerecord', '~> 5.1.0'
|
8
|
+
gem 'sqlite3', '~> 1.4'
|
9
|
+
end
|
10
|
+
|
11
|
+
appraise 'activerecord-5.2' do
|
12
|
+
gem 'activerecord', '~> 5.2.0'
|
13
|
+
gem 'sqlite3', '~> 1.4'
|
14
|
+
end
|
15
|
+
|
16
|
+
appraise 'activerecord-6.0' do
|
17
|
+
gem 'activerecord', '~> 6.0.0'
|
18
|
+
gem 'sqlite3', '~> 1.4'
|
19
|
+
end
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -1,6 +1,8 @@
|
|
1
|
+
[](https://travis-ci.org/livingsocial/tablesmith)
|
2
|
+
|
1
3
|
# Tablesmith
|
2
4
|
|
3
|
-
Drop-in gem for console tables for Hash,
|
5
|
+
Drop-in gem for console tables for Array, Hash, and ActiveRecord.
|
4
6
|
|
5
7
|
## Installation
|
6
8
|
|
@@ -18,18 +20,117 @@ Or install it yourself as:
|
|
18
20
|
|
19
21
|
## Usage
|
20
22
|
|
21
|
-
|
23
|
+
### In irb or pry
|
24
|
+
|
25
|
+
```
|
26
|
+
require 'tablesmith'
|
27
|
+
|
28
|
+
> [[:foo, :bar], [1,3]].to_table
|
29
|
+
=> +-----+-----+
|
30
|
+
| foo | bar |
|
31
|
+
+-----+-----+
|
32
|
+
| 1 | 3 |
|
33
|
+
+-----+-----+
|
34
|
+
|
35
|
+
> {a: 1, b: 2}.to_table
|
36
|
+
=> +---+---+
|
37
|
+
| a | b |
|
38
|
+
+---+---+
|
39
|
+
| 1 | 2 |
|
40
|
+
+---+---+
|
41
|
+
|
42
|
+
> [{date: '1/1/2020', amt: 35}, {date: '1/2/2020', amt: 80}].to_table
|
43
|
+
=> +----------+-----+
|
44
|
+
| date | amt |
|
45
|
+
+----------+-----+
|
46
|
+
| 1/1/2020 | 35 |
|
47
|
+
| 1/2/2020 | 80 |
|
48
|
+
+----------+-----+
|
49
|
+
|
50
|
+
> p1 = Person.create(first_name: 'chrismo', custom_attributes: { instrument: 'piano', style: 'jazz' })
|
51
|
+
=> #<Person:0x00007fac3eb406a8 id: 1, first_name: "chrismo", last_name: nil, age: nil, custom_attributes: {:instrument=>"piano", :style=>"jazz"}>
|
52
|
+
> p2 = Person.create(first_name: 'romer', custom_attributes: { hobby: 'games' })
|
53
|
+
=> #<Person:0x00007fac3ebcbb68 id: 2, first_name: "romer", last_name: nil, age: nil, custom_attributes: {:hobby=>"games"}>
|
54
|
+
> batch = [p1, p2].to_table
|
55
|
+
=> +----+------------+-----------+-----+--------+------------+--------+
|
56
|
+
| person | custom_attributes |
|
57
|
+
+----+------------+-----------+-----+--------+------------+--------+
|
58
|
+
| id | first_name | last_name | age | hobby | instrument | style |
|
59
|
+
+----+------------+-----------+-----+--------+------------+--------+
|
60
|
+
| 1 | chrismo | | | | piano | jazz |
|
61
|
+
| 2 | romer | | | games | | |
|
62
|
+
+----+------------+-----------+-----+--------+------------+--------+
|
63
|
+
```
|
64
|
+
|
65
|
+
### In a Script
|
66
|
+
|
67
|
+
`puts` won't work because of how Kernel#puts has special case code for Arrays.
|
68
|
+
Tablesmith::Table subclasses Array, so it can't cope with puts. Try to remember
|
69
|
+
to use `print` instead.
|
70
|
+
|
71
|
+
```ruby
|
72
|
+
require 'tablesmith'
|
73
|
+
|
74
|
+
print [{date: '1/1/2020', amt: 35}, {date: '1/2/2020', amt: 80}].to_table
|
75
|
+
```
|
76
|
+
|
77
|
+
### CSV Support
|
78
|
+
```
|
79
|
+
> puts [{date: '1/1/2020', amt: 35}, {date: '1/2/2020', amt: 80}].to_table.to_csv
|
80
|
+
date,amt
|
81
|
+
1/1/2020,35
|
82
|
+
1/2/2020,80
|
83
|
+
```
|
84
|
+
|
85
|
+
### HTML Support
|
86
|
+
```
|
87
|
+
> puts [{date: '1/1/2020', amt: 35}, {date: '1/2/2020', amt: 80}].to_table.to_html
|
88
|
+
<table>
|
89
|
+
<thead>
|
90
|
+
<tr>
|
91
|
+
<th>date</th>
|
92
|
+
<th>amt</th>
|
93
|
+
</tr>
|
94
|
+
</thead>
|
95
|
+
<tbody>
|
96
|
+
<tr>
|
97
|
+
<td>1/1/2020</td>
|
98
|
+
<td>35</td>
|
99
|
+
</tr>
|
100
|
+
<tr>
|
101
|
+
<td>1/2/2020</td>
|
102
|
+
<td>80</td>
|
103
|
+
</tr>
|
104
|
+
</tbody>
|
105
|
+
</table>
|
106
|
+
```
|
107
|
+
|
108
|
+
## Troubleshooting
|
109
|
+
|
110
|
+
If you ever get a default inspection output in a console for a table, an
|
111
|
+
exception has likely occurred and been caught by IRB or Pry. Call
|
112
|
+
`.to_table.to_s` to see what the exception is.
|
113
|
+
|
114
|
+
```
|
115
|
+
[1] pry(main)> [1, [2, 3]].to_table
|
116
|
+
=> #<Tablesmith::Table:0x3fc083e14294>
|
117
|
+
[2] pry(main)> [1, [2, 3]].to_table.to_s
|
118
|
+
IndexError: element size differs (2 should be 1)
|
119
|
+
from /Users/chrismo/.bundle/ruby/2.6.0/gems/text-table-1.2.4/lib/text-table/table.rb:157:in `transpose'
|
120
|
+
```
|
22
121
|
|
23
122
|
## Why Not #{other_gem}?
|
24
123
|
|
25
|
-
Happy to learn about something else already out there, but have struggled to
|
26
|
-
that doesn't require some sort of setup. I want drop-in
|
27
|
-
Arrays and ActiveRecord objects.
|
124
|
+
Happy to learn about something else already out there, but I have struggled to
|
125
|
+
find something that doesn't require some sort of setup. I want drop-in
|
126
|
+
ready-to-go table output for Arrays, Hashes, and ActiveRecord objects.
|
28
127
|
|
29
|
-
Here's a quick list of other gems that I've tried out that are awesome and do
|
30
|
-
but don't seem to specialize in what I
|
128
|
+
Here's a quick list of other gems that I've tried out that are awesome and do
|
129
|
+
much more than what Tablesmith does, but don't seem to specialize in what I
|
130
|
+
want:
|
31
131
|
|
32
|
-
-
|
33
|
-
-
|
34
|
-
- table_print
|
35
|
-
- awesome_print
|
132
|
+
- [text-table](https://github.com/aptinio/text-table) _Tablesmith uses text-table underneath_
|
133
|
+
- [Hirb](https://github.com/cldwalker/hirb) _Hirb is cool, and pretty close to what I want_
|
134
|
+
- [table_print](http://tableprintgem.com/)
|
135
|
+
- [awesome_print](https://github.com/awesome-print/awesome_print)
|
136
|
+
- [tabulo](https://github.com/matt-harvey/tabulo)
|
data/Rakefile
CHANGED
@@ -1,9 +1,11 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'rspec/core/rake_task'
|
2
4
|
require 'bundler/gem_tasks'
|
3
5
|
|
4
|
-
FileList['tasks/*.rake'].each
|
6
|
+
FileList['tasks/*.rake'].each(&method(:load))
|
5
7
|
|
6
|
-
task :
|
8
|
+
task default: :spec
|
7
9
|
|
8
10
|
desc 'Run the specs.'
|
9
11
|
RSpec::Core::RakeTask.new do |t|
|
data/lib/tablesmith.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Tablesmith::ActiveRecordSource
|
2
4
|
include Tablesmith::HashRowsBase
|
3
5
|
|
@@ -37,7 +39,7 @@ module Tablesmith::ActiveRecordSource
|
|
37
39
|
end
|
38
40
|
|
39
41
|
include.each do |association, opts|
|
40
|
-
ar_class = first.class.reflections[association].klass
|
42
|
+
ar_class = first.class.reflections[association.to_s].klass
|
41
43
|
process_columns(opts, ar_class)
|
42
44
|
end
|
43
45
|
end
|
@@ -73,7 +75,7 @@ module Tablesmith::ActiveRecordSource
|
|
73
75
|
def flatten_inner_hashes(hash)
|
74
76
|
new_hash = {}
|
75
77
|
stack = hash.each_pair.to_a
|
76
|
-
while ary = stack.shift
|
78
|
+
while (ary = stack.shift)
|
77
79
|
key, value = ary
|
78
80
|
if value.is_a?(Hash)
|
79
81
|
value.each_pair do |assoc_key, assoc_value|
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module Tablesmith::ArrayRowsSource
|
2
4
|
def text_table
|
3
5
|
build_columns if columns.nil?
|
@@ -11,7 +13,7 @@ module Tablesmith::ArrayRowsSource
|
|
11
13
|
# TODO: no support for deep
|
12
14
|
def build_columns
|
13
15
|
@columns ||= []
|
14
|
-
|
16
|
+
map do |array_row|
|
15
17
|
@columns << array_row.map { |item| Tablesmith::Column.new(name: item) }
|
16
18
|
end
|
17
19
|
@columns.flatten!
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
# ActiveRecord and HashRowsSource share a lot, but not everything.
|
2
4
|
module Tablesmith::HashRowsBase
|
3
5
|
# not all resulting rows will have data in all columns, so make sure all rows pad out missing columns
|
@@ -8,6 +10,7 @@ module Tablesmith::HashRowsBase
|
|
8
10
|
|
9
11
|
def sort_columns(rows)
|
10
12
|
return if column_order.empty?
|
13
|
+
|
11
14
|
rows.map! do |row|
|
12
15
|
# this sort gives preference to column_order then falls back to alphabetic for leftovers.
|
13
16
|
# this is handy when columns auto-generate based on hash data.
|
@@ -32,4 +35,4 @@ module Tablesmith::HashRowsBase
|
|
32
35
|
column_names = rows.first.map(&:first)
|
33
36
|
grouped_headers(column_names) + [apply_column_aliases(column_names), :separator]
|
34
37
|
end
|
35
|
-
end
|
38
|
+
end
|