tablesmith 0.5.0 → 0.6.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: 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