bumblebee 2.0.1 → 2.1.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: 836e600a1fb3228d7704e561fac6a6677e1944b42d624f2a2c9f740035f9c35b
4
- data.tar.gz: 0f222b4d2742bf467837dd89621310b1721e9bae089dc2c69e4db7f7bdc399ba
3
+ metadata.gz: e63f0ffdddd7bea22fb6da178b542556cde964543a2d7c4c68ef6e85b3bb06f3
4
+ data.tar.gz: 28a41de9de06653b0d2d41d52818bb690d786f124e6e84be7e867a496da2a8c6
5
5
  SHA512:
6
- metadata.gz: 31e3cc0c89fe47147b793a1b43e4c8e41e5a1d1580e3955073ac9019e7c45b9e1b34e5c0d1991cb39e0175b40299f612c0d22c20e0d03fffb238897d66f733b7
7
- data.tar.gz: b223693ec13620e7d54ca3e4eed04c2face5774fba8c6e6645c4e44a070b0105e0f940dcc37306af479e62c7da906ca86b00bfd4737a1bd84bca21467692948c
6
+ metadata.gz: 3153683a9564325488926f6bde6cb77ce59d1674ac6fcb3a9e60911a21870a26905b9d14d851f660d2c0c74b7df34986eadfd488a85d21734b3a7ff515e3453c
7
+ data.tar.gz: 9d19b1ea86c98101bb523a8e2ab1d6e0a04230c6b6616a2ba76b0e9bf584ccf2fcb4184a9fb14980e467a5d93749a104bb2b87a26313e48b4b5d1e5653c6376e
@@ -1,3 +1,7 @@
1
+ # 2.1.0 (March 4th, 2019)
2
+
3
+ * Added two domain-specific language options for configuring Column objects through Template: subclass Template class or pass in block. This is optional and is backwards compatible.
4
+
1
5
  # 2.0.1 (February 5th, 2019)
2
6
 
3
7
  * Updated acts_as_hashable Dependency
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- bumblebee (2.0.1)
4
+ bumblebee (2.1.0)
5
5
  acts_as_hashable (~> 1.0)
6
6
 
7
7
  GEM
@@ -95,10 +95,11 @@ PLATFORMS
95
95
  DEPENDENCIES
96
96
  bumblebee!
97
97
  guard-rspec (~> 4.7)
98
+ pry
98
99
  rspec (~> 3.8)
99
100
  rubocop (~> 0.63.1)
100
101
  simplecov (~> 0.16.1)
101
102
  simplecov-console (~> 0.4.2)
102
103
 
103
104
  BUNDLED WITH
104
- 1.17.2
105
+ 1.17.3
data/README.md CHANGED
@@ -244,6 +244,110 @@ The two main methods:
244
244
 
245
245
  also accept custom options that [Ruby's CSV::new](https://ruby-doc.org/stdlib-2.6/libdoc/csv/rdoc/CSV.html#method-c-new) accepts. The only caveat is that Bumblebee needs headers for its mapping, so it overrides the header options.
246
246
 
247
+ #### Template DSL
248
+
249
+ You can choose to pass in a block for template/column specification if you would rather prefer a code-first approach over a configuration-first approach.
250
+
251
+ ##### Using Blocks
252
+
253
+ ````ruby
254
+ csv = Bumblebee.generate_csv(objects) do |t|
255
+ t.column :id, header: 'ID #',
256
+ to_object: ->(o) { o['ID #'].to_i }
257
+
258
+ t.column :first, header: 'First Name',
259
+ to_csv: %i[name first],
260
+ to_object: ->(o) { { first: o['First Name'] } }
261
+ end
262
+
263
+ objects = Bumblebee.parse_csv(data) do |t|
264
+ t.column :id, header: 'ID #',
265
+ to_object: ->(o) { o['ID #'].to_i }
266
+
267
+ t.column :first, header: 'First Name',
268
+ to_csv: %i[name first],
269
+ to_object: ->(o) { { first: o['First Name'] } }
270
+ end
271
+ ````
272
+
273
+ ##### Interacting Directly With ::Bumblebee::Template
274
+
275
+ You can also choose to interact/build templates directly instead of going through the top-level API:
276
+
277
+ ````ruby
278
+ template = Bumblebee::Template.new(columns)
279
+
280
+ # or
281
+
282
+ template = Bumblebee::Template.new do |t|
283
+ t.column :id, header: 'ID #',
284
+ to_object: ->(o) { o['ID #'].to_i }
285
+
286
+ t.column :first, header: 'First Name',
287
+ to_csv: %i[name first],
288
+ to_object: ->(o) { { first: o['First Name'] } }
289
+ end
290
+ ````
291
+
292
+ Template class has the same top-level methods:
293
+
294
+ ````ruby
295
+ csv = template.generate_csv(objects)
296
+
297
+ objects = template.parse_csv(data)
298
+ ````
299
+
300
+ ##### Subclassing ::Bumblebee::Template
301
+
302
+ Another option is to subclass Template and declare your columns at the class-level:
303
+
304
+ ````ruby
305
+ class PersonTemplate < Bumblebee::Template
306
+ column :id, header: 'ID #',
307
+ to_object: ->(o) { o['ID #'].to_i }
308
+
309
+ column :first, header: 'First Name',
310
+ to_csv: %i[name first],
311
+ to_object: ->(o) { { first: o['First Name'] } }
312
+ end
313
+
314
+ # Usage
315
+
316
+ template = PersonTemplate.new
317
+ csv = template.generate_csv(objects)
318
+ objects = template.parse_csv(data)
319
+ ````
320
+
321
+ ##### Column Precedence
322
+
323
+ The preceding examples showed three ways to declare columns, and each is additive to the next (in the following order):
324
+
325
+ 1. Class level (parent-first)
326
+ 2. Argument level (passed into constructor)
327
+ 3. Block level
328
+
329
+ To illustrate all three:
330
+
331
+ ````ruby
332
+ class PersonTemplate < Bumblebee::Template # first
333
+ column :id, header: 'ID #',
334
+ to_object: ->(o) { o['ID #'].to_i }
335
+
336
+ column :first, header: 'First Name',
337
+ to_csv: %i[name first],
338
+ to_object: ->(o) { { first: o['First Name'] } }
339
+ end
340
+
341
+ # Usage
342
+
343
+ template = PersonTemplate.new({ field: :middle, header: 'Middle Name' }) do |t| # second
344
+ t.column :last, header: 'Last Name' # third
345
+ end
346
+
347
+ ````
348
+
349
+ When executed to generate a CSV, the columns would be (in order): ```ID #, First Name, Middle Name, Last Name.```
350
+
247
351
  ## Contributing
248
352
 
249
353
  ### Development Environment Configuration
@@ -25,6 +25,7 @@ Gem::Specification.new do |s|
25
25
  s.add_dependency('acts_as_hashable', '~>1.0')
26
26
 
27
27
  s.add_development_dependency('guard-rspec', '~>4.7')
28
+ s.add_development_dependency('pry')
28
29
  s.add_development_dependency('rspec', '~> 3.8')
29
30
  s.add_development_dependency('rubocop', '~>0.63.1')
30
31
  s.add_development_dependency('simplecov', '~>0.16.1')
@@ -19,12 +19,56 @@ require_relative 'template'
19
19
  # procedural way using these.
20
20
  module Bumblebee
21
21
  class << self
22
- def generate_csv(columns, objects, options = {})
23
- ::Bumblebee::Template.new(columns).generate_csv(objects, options)
22
+ # Two signatures for consumption:
23
+ #
24
+ # ::Bumblebee.generate_csv(columns = [], objects = [], options = {})
25
+ #
26
+ # or
27
+ #
28
+ # ::Bumblebee.generate_csv(objects = [], options = {}) do |t|
29
+ # t.column :id, header: 'ID #'
30
+ # t.column :first, header: 'First Name'
31
+ # end
32
+ def generate_csv(*args, &block)
33
+ if block_given?
34
+ objects = args[0] || []
35
+ options = args[1] || {}
36
+ else
37
+ objects = args[1] || []
38
+ options = args[2] || {}
39
+ end
40
+
41
+ template(args, &block).generate_csv(objects, options)
42
+ end
43
+
44
+ # Two signatures for consumption:
45
+ #
46
+ # ::Bumblebee.parse_csv(columns = [], string = '', options = {})
47
+ #
48
+ # or
49
+ #
50
+ # ::Bumblebee.parse_csv(string = '', options = {}) do |t|
51
+ # t.column :id, header: 'ID #'
52
+ # t.column :first, header: 'First Name'
53
+ # end
54
+ def parse_csv(*args, &block)
55
+ if block_given?
56
+ string = args[0] || ''
57
+ options = args[1] || {}
58
+ else
59
+ string = args[1] || ''
60
+ options = args[2] || {}
61
+ end
62
+
63
+ template(args, &block).parse_csv(string, options)
24
64
  end
25
65
 
26
- def parse_csv(columns, string, options = {})
27
- ::Bumblebee::Template.new(columns).parse_csv(string, options)
66
+ private
67
+
68
+ def template(args, &block)
69
+ columns = block_given? ? [] : (args[0] || [])
70
+
71
+ ::Bumblebee::Template.new(columns, &block)
28
72
  end
29
73
  end
30
74
  end
@@ -12,10 +12,42 @@ module Bumblebee
12
12
  # generate_csv: take in an array of objects and return a string (CSV contents)
13
13
  # parse_csv: take in a string and return an array of OpenStruct objects
14
14
  class Template
15
+ class << self
16
+ def columns
17
+ @columns ||= []
18
+ end
19
+
20
+ def column(field, opts = {})
21
+ columns << ::Bumblebee::Column.make(opts.merge(field: field))
22
+
23
+ self
24
+ end
25
+
26
+ def all_columns
27
+ ancestors.reverse_each.inject([]) do |arr, ancestor|
28
+ ancestor < ::Bumblebee::Template ? arr + ancestor.columns : arr
29
+ end
30
+ end
31
+ end
32
+
15
33
  attr_reader :columns
16
34
 
17
- def initialize(columns = [])
18
- @columns = ::Bumblebee::Column.array(columns)
35
+ def initialize(columns = [], &block)
36
+ @columns = self.class.all_columns + ::Bumblebee::Column.array(columns)
37
+
38
+ return unless block_given?
39
+
40
+ if block.arity == 1
41
+ yield self
42
+ else
43
+ instance_eval(&block)
44
+ end
45
+ end
46
+
47
+ # New DSL method to use for adding columns
48
+ def column(field, opts = {})
49
+ @columns << ::Bumblebee::Column.make(opts.merge(field: field))
50
+ self
19
51
  end
20
52
 
21
53
  # Return array of strings (headers)
@@ -8,5 +8,5 @@
8
8
  #
9
9
 
10
10
  module Bumblebee
11
- VERSION = '2.0.1'
11
+ VERSION = '2.1.0'
12
12
  end
@@ -35,12 +35,22 @@ describe ::Bumblebee do
35
35
 
36
36
  let(:quoted_csv) { "\"name\",\"dob\"\n\"Matt\",\"1901-01-03\"\n\"Nathan\",\"1931-09-03\"\n" }
37
37
 
38
- it 'should generate a csv' do
38
+ it 'should generate a csv using column argument' do
39
39
  actual = Bumblebee.generate_csv(columns, people)
40
40
 
41
41
  expect(actual).to eq(csv)
42
42
  end
43
43
 
44
+ it 'should generate a csv using block' do
45
+ actual = Bumblebee.generate_csv(people) do |t|
46
+ columns.each do |column|
47
+ t.column column[:field]
48
+ end
49
+ end
50
+
51
+ expect(actual).to eq(csv)
52
+ end
53
+
44
54
  it 'should generate a csv and accept options' do
45
55
  options = {
46
56
  force_quotes: true
@@ -51,12 +61,22 @@ describe ::Bumblebee do
51
61
  expect(actual).to eq(quoted_csv)
52
62
  end
53
63
 
54
- it 'should parse a csv' do
64
+ it 'should parse a csv using columns argument' do
55
65
  objects = Bumblebee.parse_csv(columns, csv)
56
66
 
57
67
  expect(objects).to eq(people)
58
68
  end
59
69
 
70
+ it 'should parse a csv using columns block' do
71
+ objects = Bumblebee.parse_csv(csv) do |t|
72
+ columns.each do |column|
73
+ t.column column[:field]
74
+ end
75
+ end
76
+
77
+ expect(objects).to eq(people)
78
+ end
79
+
60
80
  it 'should parse a csv with columns in different order than headers' do
61
81
  objects = ::Bumblebee.parse_csv(reverse_columns, csv)
62
82
 
@@ -0,0 +1,72 @@
1
+ # frozen_string_literal: true
2
+
3
+ #
4
+ # Copyright (c) 2018-present, Blue Marble Payroll, LLC
5
+ #
6
+ # This source code is licensed under the MIT license found in the
7
+ # LICENSE file in the root directory of this source tree.
8
+ #
9
+
10
+ require 'spec_helper'
11
+
12
+ describe ::Bumblebee::Template do
13
+ let(:field) { :id }
14
+ let(:opts) { { header: 'ID #' } }
15
+
16
+ context 'with a blank template' do
17
+ let(:template) { ::Bumblebee::Template.new }
18
+
19
+ subject { template }
20
+
21
+ it '#column should add a column' do
22
+ subject.column(field, opts)
23
+
24
+ expect(subject.columns.length).to eq(1)
25
+ expect(subject.columns.first.field).to eq(field)
26
+ expect(subject.columns.first.header).to eq(opts[:header])
27
+ end
28
+ end
29
+
30
+ describe '#initialize' do
31
+ specify 'that initialization accepts a block (with arity) for column creation' do
32
+ template = ::Bumblebee::Template.new do |t|
33
+ t.column field, opts
34
+ end
35
+
36
+ expect(template.columns.length).to eq(1)
37
+ expect(template.columns.first.field).to eq(field)
38
+ expect(template.columns.first.header).to eq(opts[:header])
39
+ end
40
+
41
+ specify 'that initialization accepts a block (without arity) for column creation' do
42
+ template = ::Bumblebee::Template.new do
43
+ column :id, header: 'ID #'
44
+ end
45
+
46
+ expect(template.columns.length).to eq(1)
47
+ expect(template.columns.first.field).to eq(field)
48
+ expect(template.columns.first.header).to eq(opts[:header])
49
+ end
50
+ end
51
+
52
+ describe 'subclassing' do
53
+ class PersonTemplate < ::Bumblebee::Template
54
+ column :id, header: 'ID #'
55
+ end
56
+
57
+ class CompletePersonTemplate < PersonTemplate
58
+ column :first, header: 'First Name'
59
+ end
60
+
61
+ it 'should use class-level declared columns in the correct parenting hierarchical order' do
62
+ template = CompletePersonTemplate.new
63
+
64
+ expect(template.columns.length).to eq(2)
65
+ expect(template.columns.first.field).to eq(:id)
66
+ expect(template.columns.first.header).to eq('ID #')
67
+
68
+ expect(template.columns.last.field).to eq(:first)
69
+ expect(template.columns.last.header).to eq('First Name')
70
+ end
71
+ end
72
+ end
@@ -8,6 +8,7 @@
8
8
  #
9
9
 
10
10
  require 'stringio'
11
+ require 'pry'
11
12
 
12
13
  require 'simplecov'
13
14
  require 'simplecov-console'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bumblebee
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.1
4
+ version: 2.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Matthew Ruggio
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-02-05 00:00:00.000000000 Z
11
+ date: 2019-03-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: acts_as_hashable
@@ -38,6 +38,20 @@ dependencies:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
40
  version: '4.7'
41
+ - !ruby/object:Gem::Dependency
42
+ name: pry
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
41
55
  - !ruby/object:Gem::Dependency
42
56
  name: rspec
43
57
  requirement: !ruby/object:Gem::Requirement
@@ -124,6 +138,7 @@ files:
124
138
  - lib/bumblebee/version.rb
125
139
  - spec/bumblebee/bumblebee_spec.rb
126
140
  - spec/bumblebee/column_spec.rb
141
+ - spec/bumblebee/template_spec.rb
127
142
  - spec/fixtures/custom_readme_example.csv
128
143
  - spec/fixtures/simple_readme_example.csv
129
144
  - spec/spec_helper.rb
@@ -153,6 +168,7 @@ summary: Object/CSV Mapper
153
168
  test_files:
154
169
  - spec/bumblebee/bumblebee_spec.rb
155
170
  - spec/bumblebee/column_spec.rb
171
+ - spec/bumblebee/template_spec.rb
156
172
  - spec/fixtures/custom_readme_example.csv
157
173
  - spec/fixtures/simple_readme_example.csv
158
174
  - spec/spec_helper.rb