tablesmith 0.5.0 → 0.6.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f7a031da03b4834e3512f66e1ee9541826d6dfdd7992d593dbbf686f9b5029d0
4
- data.tar.gz: fcca01f815f5b51e31ff1c148e8137edec52a5405e54588216305e50d5ff1a3f
3
+ metadata.gz: e3c75c62ab94384c394373d395134e52bbb21e4e94f8cc94646f450ada1f9678
4
+ data.tar.gz: 9aa2c83212ca484555bd5f7344e38e0ddc7b603315e2f976ff29e6054bb571bb
5
5
  SHA512:
6
- metadata.gz: 0e1360f9d29e4b9439253b5e6e40279842df875daa2d926f30b265ab32531befe69911dbe3f436cf4c99b0d0adb00188180e9aa5578f7b1f48a121a52149c2f6
7
- data.tar.gz: e93c2e664a4c3809c557dc173643d9d38bc51c8913252490bbd46065e1a7c877fe54af44d8140a788e6478c083f93542dcf5fb2abaa8585a98cd44da32840a76
6
+ metadata.gz: f0b940e2db92a0941ed25daaf81f501bec3d13964e1769f4d582a2966d76674ab151b6576010929ee2028f01e02e9fbdd10de0e526e7a7c0d26680f31193b1ee
7
+ data.tar.gz: 949d1f0e968bb9f4c8315508e755ba596736e9cb68dc037f5c06bbce3303e2062ac235e942f32b44a8ca9943b2961a42846270847dab18cb3a1b62a0e3ae32d1
@@ -1,6 +1,3 @@
1
- require:
2
- - rubocop_lineup
3
-
4
1
  AllCops:
5
2
  TargetRubyVersion: 2.3
6
3
 
@@ -54,6 +51,9 @@ Layout/ClassStructure:
54
51
  Layout/DotPosition:
55
52
  EnforcedStyle: trailing
56
53
 
54
+ Layout/SpaceInsideHashLiteralBraces:
55
+ Enabled: false
56
+
57
57
  Lint/Void:
58
58
  Exclude:
59
59
  - 'spec/**'
@@ -89,6 +89,9 @@ Metrics/MethodLength:
89
89
  CountComments: false # count full line comments?
90
90
  Max: 15
91
91
 
92
+ Naming/UncommunicativeMethodParamName:
93
+ Enabled: false
94
+
92
95
  Rails/Date:
93
96
  Enabled: true
94
97
  EnforcedStyle: flexible
data/Appraisals CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  appraise 'activerecord-4' do
2
4
  gem 'activerecord', '~> 4.0'
3
5
  gem 'sqlite3', '~> 1.3.6'
data/README.md CHANGED
@@ -39,13 +39,25 @@ require 'tablesmith'
39
39
  | 1 | 2 |
40
40
  +---+---+
41
41
 
42
- > [{date: '1/1/2020', amt: 35}, {date: '1/2/2020', amt: 80}].to_table
42
+ > t = [{date: '1/1/2020', amt: 35}, {date: '1/2/2020', amt: 80}].to_table
43
43
  => +----------+-----+
44
44
  | date | amt |
45
45
  +----------+-----+
46
46
  | 1/1/2020 | 35 |
47
47
  | 1/2/2020 | 80 |
48
48
  +----------+-----+
49
+
50
+ > # Table delegates to Array, all Array methods are available.
51
+ > t.select! { |h| h[:amt] > 40 }
52
+ => [{:date=>"1/2/2020", :amt=>80}]
53
+
54
+ > t
55
+ => +----------+-----+
56
+ | date | amt |
57
+ +----------+-----+
58
+ | 1/2/2020 | 80 |
59
+ +----------+-----+
60
+
49
61
 
50
62
  > p1 = Person.create(first_name: 'chrismo', custom_attributes: { instrument: 'piano', style: 'jazz' })
51
63
  => #<Person:0x00007fac3eb406a8 id: 1, first_name: "chrismo", last_name: nil, age: nil, custom_attributes: {:instrument=>"piano", :style=>"jazz"}>
data/Rakefile CHANGED
@@ -11,3 +11,9 @@ desc 'Run the specs.'
11
11
  RSpec::Core::RakeTask.new do |t|
12
12
  t.pattern = '*_spec.rb'
13
13
  end
14
+
15
+ require 'rubocop/rake_task'
16
+
17
+ RuboCop::RakeTask.new(:rubocop)
18
+
19
+ task default: :rubocop
@@ -1,8 +1,10 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # This file was generated by Appraisal
2
4
 
3
- source "https://rubygems.org"
5
+ source 'https://rubygems.org'
4
6
 
5
- gem "activerecord", "~> 4.0"
6
- gem "sqlite3", "~> 1.3.6"
7
+ gem 'activerecord', '~> 4.0'
8
+ gem 'sqlite3', '~> 1.3.6'
7
9
 
8
- gemspec path: "../"
10
+ gemspec path: '../'
@@ -1,8 +1,10 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # This file was generated by Appraisal
2
4
 
3
- source "https://rubygems.org"
5
+ source 'https://rubygems.org'
4
6
 
5
- gem "activerecord", "~> 5.1.0"
6
- gem "sqlite3", "~> 1.4"
7
+ gem 'activerecord', '~> 5.1.0'
8
+ gem 'sqlite3', '~> 1.4'
7
9
 
8
- gemspec path: "../"
10
+ gemspec path: '../'
@@ -1,8 +1,10 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # This file was generated by Appraisal
2
4
 
3
- source "https://rubygems.org"
5
+ source 'https://rubygems.org'
4
6
 
5
- gem "activerecord", "~> 5.2.0"
6
- gem "sqlite3", "~> 1.4"
7
+ gem 'activerecord', '~> 5.2.0'
8
+ gem 'sqlite3', '~> 1.4'
7
9
 
8
- gemspec path: "../"
10
+ gemspec path: '../'
@@ -1,8 +1,10 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # This file was generated by Appraisal
2
4
 
3
- source "https://rubygems.org"
5
+ source 'https://rubygems.org'
4
6
 
5
- gem "activerecord", "~> 6.0.0"
6
- gem "sqlite3", "~> 1.4"
7
+ gem 'activerecord', '~> 6.0.0'
8
+ gem 'sqlite3', '~> 1.4'
7
9
 
8
- gemspec path: "../"
10
+ gemspec path: '../'
@@ -1,5 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'tablesmith/delegated_array_class'
3
4
  require 'tablesmith/table'
4
5
  require 'tablesmith/array_rows_source'
5
6
  require 'tablesmith/hash_rows_base'
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Tablesmith
4
+ # This adjustment to `DelegateClass(Array)` is necessary to allow calling puts
5
+ # on a `Tablesmith::Table` and still get the table output, rather than the
6
+ # default puts output of the underlying `Array`.
7
+ #
8
+ # Explaining why requires breaking some things down.
9
+ #
10
+ # The implementation of `Kernel::puts` has special code for an `Array`. The
11
+ # code inside `rb_io_puts` (in io.c) first checks to see if the object passed
12
+ # to it is a `String`. If not, it then calls `io_puts_ary`, which in turn
13
+ # calls `rb_check_array_type`. If `rb_check_array_type` confirms the passed
14
+ # object is an `Array`, then `io_puts_ary` loops over the elements of the
15
+ # `Array` and passes it to `rb_io_puts`. If the `Array` check fails in the
16
+ # original `rb_io_puts`, `rb_obj_as_string` is used.
17
+ #
18
+ # Early versions of `Tablesmith::Table` subclassed `Array`, but even after
19
+ # changing `Tablesmith::Table` to use any of the `Delegator` options, the code
20
+ # in `rb_check_array_type` still detected `Tablesmith::Table` as an `Array`.
21
+ # How does it do this?
22
+ #
23
+ # `rb_check_array_type` calls:
24
+ #
25
+ # `return rb_check_convert_type_with_id(ary, T_ARRAY, "Array", idTo_ary);`
26
+ #
27
+ # If a straight up type check fails, then it attempts to convert the object to
28
+ # an `Array` via the `to_ary` method.
29
+ #
30
+ # And wha-lah. We simply need to undefine the `to_ary` method added to
31
+ # `Tablesmith::Table` by `DelegateClass(Array)` and `rb_io_puts` will no
32
+ # longer output `Table` as an `Array` and will use its `to_s` method, the same
33
+ # as `print`.
34
+ def self.delegated_array_class
35
+ DelegateClass(Array).tap do |klass|
36
+ klass.undef_method(:to_ary)
37
+ end
38
+ end
39
+ end
@@ -4,17 +4,30 @@ require 'text-table'
4
4
  require 'csv'
5
5
 
6
6
  module Tablesmith
7
- class Table < Array
7
+ class Table < Tablesmith.delegated_array_class
8
+ def initialize(array = [])
9
+ super(array)
10
+ @array = array
11
+ end
12
+
8
13
  def method_missing(meth_id, *args)
9
- count = 1
10
- map do |t|
11
- $stderr.print '.' if (count.divmod(100)[1]).zero?
12
- count += 1
13
- t.send(meth_id, *args)
14
- end
14
+ # In order to support `Kernel::puts` of a `Table`, we need to ignore
15
+ # `to_ary` calls here as well. See comments on `delegated_array_class`.
16
+ #
17
+ # While `DelegatorClass(Array)` proactively defines methods on `Table`
18
+ # that come from `Array`, it _also_ will pass calls through method_missing
19
+ # to the target object if it says it will respond to it.
20
+ #
21
+ # It seems a little redundant, but it is what it is, and so we must also
22
+ # cut off calls to `to_ary` in both places.
23
+ return nil if meth_id.to_sym == :to_ary
24
+
25
+ super
15
26
  end
16
27
 
17
- def respond_to_missing?
28
+ def respond_to_missing?(meth_id, _include_all)
29
+ return false if meth_id.to_sym == :to_ary
30
+
18
31
  super
19
32
  end
20
33
 
@@ -118,9 +131,7 @@ module Tablesmith
118
131
  else
119
132
  row = []
120
133
  # this relies on Ruby versions where hash retains add order
121
- groups.each_pair do |name, span|
122
- row << { value: name, align: :center, colspan: span }
123
- end
134
+ groups.each { |name, span| row << {value: name, align: :center, colspan: span} }
124
135
  [row, :separator]
125
136
  end
126
137
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Tablesmith
4
- VERSION = '0.5.0'
4
+ VERSION = '0.6.0'
5
5
  end
@@ -14,7 +14,7 @@ describe 'Array Source' do
14
14
  [%w[a b c], %w[d e f]].to_table.to_s.should == expected
15
15
  end
16
16
 
17
- def do_just_works_test(_expected, meth_id)
17
+ def do_just_works_test(meth_id)
18
18
  orig_stdout = $stdout
19
19
  sio = StringIO.new
20
20
  $stdout = sio
@@ -33,7 +33,7 @@ describe 'Array Source' do
33
33
  +---+---+---+
34
34
  TABLE
35
35
 
36
- actual = do_just_works_test(expected, meth_id)
36
+ actual = do_just_works_test(meth_id)
37
37
  actual.should == expected
38
38
  end
39
39
 
@@ -42,14 +42,22 @@ describe 'Array Source' do
42
42
  end
43
43
 
44
44
  it 'just works with puts' do
45
- pending
46
-
47
- # Kernel.puts has special behavior for puts with Array,
48
- # which Table subclasses, so this isn't going to work,
49
- # unless we can stop subclassing Array.
50
45
  just_works(:puts)
51
46
  end
52
47
 
48
+ it 'just works with p' do
49
+ expected = <<~TABLE
50
+ +---+---+---+
51
+ | a | b | c |
52
+ +---+---+---+
53
+ | d | e | f |
54
+ +---+---+---+
55
+ TABLE
56
+
57
+ actual = do_just_works_test(:p)
58
+ actual.should == "#{expected}\n"
59
+ end
60
+
53
61
  it 'just works with inspect' do
54
62
  expected = <<~TABLE
55
63
  +---+---+---+
@@ -5,7 +5,7 @@ require 'spec_helper'
5
5
  include Tablesmith # rubocop:disable Style/MixinUsage:
6
6
 
7
7
  describe Table do
8
- it 'should subclass array' do
8
+ it 'should delegate to the internal array' do
9
9
  b = Table.new
10
10
  b.length.should == 0
11
11
  b << 1
@@ -15,12 +15,17 @@ describe Table do
15
15
  b.class.should == Table
16
16
  end
17
17
 
18
- it 'should pass unmatched Array messages to all items' do
18
+ it 'should no longer pass unmatched Array messages to all items' do
19
+ # earlier pre-1.0 versions implemented method_missing in order to provide
20
+ # syntactic sugar for calling map on the underlying Array. But as time went
21
+ # on, it felt too heavy-handed and not worth it.
22
+
19
23
  b = Table.new
20
24
  b.length.should == 0
21
25
  b << 1
22
26
  b << '2'
23
- b.to_i.should == [1, 2]
27
+ b.map(&:to_i).should == [1, 2]
28
+ -> { b.to_i }.should raise_error(NoMethodError)
24
29
  end
25
30
 
26
31
  it 'should handle empty Array' do
@@ -29,7 +34,7 @@ describe Table do
29
34
  | (empty) |
30
35
  +---------+
31
36
  TEXT
32
- [].to_table.text_table.to_s.should == expected
37
+ [].to_table.to_s.should == expected
33
38
  end
34
39
 
35
40
  it 'should handle a simple two row Array' do
@@ -42,7 +47,7 @@ describe Table do
42
47
  | d | e | f |
43
48
  +---+---+---+
44
49
  TABLE
45
- actual.to_table.text_table.to_s.should == expected
50
+ actual.to_table.to_s.should == expected
46
51
  end
47
52
 
48
53
  it 'should output csv' do
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: tablesmith
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.0
4
+ version: 0.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - chrismo
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-03-11 00:00:00.000000000 Z
11
+ date: 2020-03-21 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: text-table
@@ -190,6 +190,7 @@ files:
190
190
  - lib/tablesmith.rb
191
191
  - lib/tablesmith/active_record_source.rb
192
192
  - lib/tablesmith/array_rows_source.rb
193
+ - lib/tablesmith/delegated_array_class.rb
193
194
  - lib/tablesmith/hash_rows_base.rb
194
195
  - lib/tablesmith/hash_rows_source.rb
195
196
  - lib/tablesmith/html_formatter.rb