bumblebee 2.1.0 → 3.0.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 +4 -4
- data/.rubocop.yml +2 -2
- data/.travis.yml +1 -1
- data/CHANGELOG.md +6 -0
- data/Gemfile.lock +1 -1
- data/README.md +172 -138
- data/bin/console +2 -6
- data/lib/bumblebee/bumblebee.rb +16 -62
- data/lib/bumblebee/column.rb +41 -63
- data/lib/bumblebee/column_dsl.rb +38 -0
- data/lib/bumblebee/column_set.rb +83 -0
- data/lib/bumblebee/converter.rb +97 -0
- data/lib/bumblebee/core_ext/hash.rb +21 -0
- data/lib/bumblebee/mutator.rb +54 -0
- data/lib/bumblebee/null_converter.rb +17 -0
- data/lib/bumblebee/object_interface.rb +66 -0
- data/lib/bumblebee/simple_converter.rb +109 -0
- data/lib/bumblebee/template.rb +23 -37
- data/lib/bumblebee/version.rb +1 -1
- data/spec/bumblebee/simple_converter_spec.rb +29 -0
- data/spec/bumblebee/template_spec.rb +151 -36
- data/spec/examples/converter_test_case.rb +113 -0
- data/spec/examples/person_template.rb +66 -0
- data/spec/examples/simple_object.rb +27 -0
- data/spec/fixtures/people/data.csv +3 -0
- data/spec/fixtures/people/data.yml +46 -0
- data/spec/fixtures/registrations/columns.yml +35 -0
- data/spec/fixtures/registrations/data.csv +3 -0
- data/spec/fixtures/registrations/data.yml +26 -0
- data/spec/fixtures/simple/columns.yml +4 -0
- data/spec/fixtures/{custom_readme_example.csv → simple/data.csv} +1 -1
- data/spec/fixtures/simple/data.yml +12 -0
- data/spec/spec_helper.rb +29 -3
- metadata +34 -10
- data/spec/bumblebee/bumblebee_spec.rb +0 -167
- data/spec/bumblebee/column_spec.rb +0 -213
- data/spec/fixtures/simple_readme_example.csv +0 -4
@@ -0,0 +1,54 @@
|
|
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
|
+
module Bumblebee
|
11
|
+
# A Mutator is a composition of a converter with hash value setting. It can be a straight
|
12
|
+
# converter, or it can be new types which are not directly defined as 'converters.'
|
13
|
+
class Mutator
|
14
|
+
module Types
|
15
|
+
IGNORE = :ignore
|
16
|
+
end
|
17
|
+
include ::Bumblebee::Mutator::Types
|
18
|
+
|
19
|
+
attr_reader :converter, :type
|
20
|
+
|
21
|
+
def initialize(arg)
|
22
|
+
if arg.nil?
|
23
|
+
@type = nil
|
24
|
+
@converter = ::Bumblebee::NullConverter.new
|
25
|
+
elsif mutator?(arg)
|
26
|
+
@type = ::Bumblebee::Mutator::Types.const_get(arg.to_s.upcase.to_sym)
|
27
|
+
@converter = ::Bumblebee::NullConverter.new
|
28
|
+
else
|
29
|
+
@type = nil
|
30
|
+
@converter = ::Bumblebee::SimpleConverter.new(arg)
|
31
|
+
end
|
32
|
+
|
33
|
+
freeze
|
34
|
+
end
|
35
|
+
|
36
|
+
def set(object, key, val)
|
37
|
+
return object if ignore?
|
38
|
+
|
39
|
+
::Bumblebee::ObjectInterface.set(object, key, converter.convert(val))
|
40
|
+
end
|
41
|
+
|
42
|
+
private
|
43
|
+
|
44
|
+
def ignore?
|
45
|
+
type == IGNORE
|
46
|
+
end
|
47
|
+
|
48
|
+
def mutator?(arg)
|
49
|
+
return false unless arg.is_a?(String) || arg.is_a?(Symbol)
|
50
|
+
|
51
|
+
::Bumblebee::Mutator::Types.constants.include?(arg.to_s.upcase.to_sym)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,17 @@
|
|
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
|
+
module Bumblebee
|
11
|
+
# Base converter using the Null Object Pattern. Use this when a custom converter is not needed.
|
12
|
+
class NullConverter
|
13
|
+
def convert(val)
|
14
|
+
val
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,66 @@
|
|
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
|
+
module Bumblebee
|
11
|
+
# Provides methods for interacting with custom objects.
|
12
|
+
class ObjectInterface
|
13
|
+
class << self
|
14
|
+
def traverse(object, through)
|
15
|
+
pointer = object
|
16
|
+
|
17
|
+
through.each do |t|
|
18
|
+
next unless pointer
|
19
|
+
|
20
|
+
pointer = get(pointer, t)
|
21
|
+
end
|
22
|
+
|
23
|
+
pointer
|
24
|
+
end
|
25
|
+
|
26
|
+
def build(object, through)
|
27
|
+
pointer = object
|
28
|
+
|
29
|
+
through.each do |t|
|
30
|
+
pointer = get(pointer, t) || get(set(pointer, t, pointer.class.new), t)
|
31
|
+
end
|
32
|
+
|
33
|
+
pointer
|
34
|
+
end
|
35
|
+
|
36
|
+
def set(object, key, val)
|
37
|
+
object.tap do |o|
|
38
|
+
setter_method = "#{key}="
|
39
|
+
if o.respond_to?(setter_method)
|
40
|
+
o.send(setter_method, val)
|
41
|
+
elsif o.respond_to?(:[])
|
42
|
+
o[key] = val
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
def get(object, key)
|
48
|
+
if object.is_a?(Hash)
|
49
|
+
indifferent_hash_get(object, key)
|
50
|
+
elsif object.respond_to?(key)
|
51
|
+
object.send(key)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
private
|
56
|
+
|
57
|
+
def indifferent_hash_get(hash, key)
|
58
|
+
if hash.key?(key.to_s)
|
59
|
+
hash[key.to_s]
|
60
|
+
elsif hash.key?(key.to_s.to_sym)
|
61
|
+
hash[key.to_s.to_sym]
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,109 @@
|
|
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
|
+
module Bumblebee
|
11
|
+
# Subclass of Converter that provides a simple implementation for each Type.
|
12
|
+
class SimpleConverter < ::Bumblebee::Converter
|
13
|
+
DEFAULT_DATE = '1900-01-01'
|
14
|
+
DEFAULT_BIG_DECIMAL = 0
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def process_pluck_join(val)
|
19
|
+
raise ArgumentError, 'sub_property is required for a pluck_join' unless sub_property
|
20
|
+
|
21
|
+
Array(val).map { |h| per.convert(h.is_a?(Hash) ? h[sub_property] : nil) }
|
22
|
+
.join(separator)
|
23
|
+
end
|
24
|
+
|
25
|
+
def process_pluck_split(val)
|
26
|
+
raise ArgumentError, 'sub_property is required for a pluck_split' unless sub_property
|
27
|
+
|
28
|
+
process_split(val).map do |v|
|
29
|
+
object_class.new.tap { |h| ::Bumblebee::ObjectInterface.set(h, sub_property, v) }
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def process_ignore(_val)
|
34
|
+
nil
|
35
|
+
end
|
36
|
+
|
37
|
+
def process_join(val)
|
38
|
+
Array(val).map { |v| per.convert(v) }.join(separator)
|
39
|
+
end
|
40
|
+
|
41
|
+
def process_split(val)
|
42
|
+
val.to_s.split(separator).map { |v| per.convert(v) }
|
43
|
+
end
|
44
|
+
|
45
|
+
def process_function(val)
|
46
|
+
raise ArgumentError, 'function is required for function type' unless function
|
47
|
+
|
48
|
+
function.call(val)
|
49
|
+
end
|
50
|
+
|
51
|
+
def process_date(val)
|
52
|
+
return nil if nullable? && null_or_empty?(val)
|
53
|
+
|
54
|
+
Date.strptime(null_or_empty_default(val, DEFAULT_DATE).to_s, date_format)
|
55
|
+
end
|
56
|
+
|
57
|
+
def process_string(val)
|
58
|
+
return nil if nullable? && null_or_empty?(val)
|
59
|
+
|
60
|
+
val.to_s
|
61
|
+
end
|
62
|
+
|
63
|
+
def process_integer(val)
|
64
|
+
return nil if nullable? && null_or_empty?(val)
|
65
|
+
|
66
|
+
val.to_i
|
67
|
+
end
|
68
|
+
|
69
|
+
def process_float(val)
|
70
|
+
return nil if nullable? && null_or_empty?(val)
|
71
|
+
|
72
|
+
val.to_f
|
73
|
+
end
|
74
|
+
|
75
|
+
def process_bigdecimal(val)
|
76
|
+
return nil if nullable? && null_or_empty?(val)
|
77
|
+
|
78
|
+
BigDecimal(null_or_empty_default(val, DEFAULT_BIG_DECIMAL).to_s)
|
79
|
+
end
|
80
|
+
|
81
|
+
def process_boolean(val)
|
82
|
+
if nullable? && nully?(val)
|
83
|
+
nil
|
84
|
+
elsif truthy?(val)
|
85
|
+
true
|
86
|
+
else
|
87
|
+
false
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
def null_or_empty_default(val, default)
|
92
|
+
null_or_empty?(val) ? default : val
|
93
|
+
end
|
94
|
+
|
95
|
+
def null_or_empty?(val)
|
96
|
+
val.nil? || val.to_s.empty?
|
97
|
+
end
|
98
|
+
|
99
|
+
# rubocop:disable Style/DoubleNegation
|
100
|
+
def nully?(val)
|
101
|
+
null_or_empty?(val) || !!(val.to_s =~ /(nil|null)$/i)
|
102
|
+
end
|
103
|
+
|
104
|
+
def truthy?(val)
|
105
|
+
!!(val.to_s =~ /(true|t|yes|y|1)$/i)
|
106
|
+
end
|
107
|
+
# rubocop:enable Style/DoubleNegation
|
108
|
+
end
|
109
|
+
end
|
data/lib/bumblebee/template.rb
CHANGED
@@ -10,30 +10,20 @@
|
|
10
10
|
module Bumblebee
|
11
11
|
# Wraps up columns and provides to main methods:
|
12
12
|
# generate_csv: take in an array of objects and return a string (CSV contents)
|
13
|
-
# parse_csv: take in a string and return an array of
|
13
|
+
# parse_csv: take in a string and return an array of hashes
|
14
14
|
class Template
|
15
|
-
|
16
|
-
|
17
|
-
@columns ||= []
|
18
|
-
end
|
15
|
+
extend Forwardable
|
16
|
+
extend ::Bumblebee::ColumnDsl
|
19
17
|
|
20
|
-
|
21
|
-
columns << ::Bumblebee::Column.make(opts.merge(field: field))
|
18
|
+
def_delegators :column_set, :headers, :columns
|
22
19
|
|
23
|
-
|
24
|
-
end
|
20
|
+
attr_reader :object_class
|
25
21
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
end
|
30
|
-
end
|
31
|
-
end
|
32
|
-
|
33
|
-
attr_reader :columns
|
22
|
+
def initialize(columns: nil, object_class: Hash, &block)
|
23
|
+
@column_set = ::Bumblebee::ColumnSet.new(self.class.all_columns)
|
24
|
+
@object_class = object_class
|
34
25
|
|
35
|
-
|
36
|
-
@columns = self.class.all_columns + ::Bumblebee::Column.array(columns)
|
26
|
+
column_set.add(columns)
|
37
27
|
|
38
28
|
return unless block_given?
|
39
29
|
|
@@ -44,43 +34,39 @@ module Bumblebee
|
|
44
34
|
end
|
45
35
|
end
|
46
36
|
|
47
|
-
|
48
|
-
|
49
|
-
@columns << ::Bumblebee::Column.make(opts.merge(field: field))
|
50
|
-
self
|
51
|
-
end
|
37
|
+
def column(header, opts = {})
|
38
|
+
column_set.column(header, opts)
|
52
39
|
|
53
|
-
|
54
|
-
def headers
|
55
|
-
columns.map(&:header)
|
40
|
+
self
|
56
41
|
end
|
57
42
|
|
58
|
-
def
|
43
|
+
def generate(objects, options = {})
|
59
44
|
objects = objects.is_a?(Hash) ? [objects] : Array(objects)
|
60
45
|
|
61
46
|
write_options = options.merge(headers: headers, write_headers: true)
|
62
47
|
|
63
48
|
CSV.generate(write_options) do |csv|
|
64
49
|
objects.each do |object|
|
65
|
-
|
66
|
-
|
67
|
-
|
50
|
+
csv << columns.each_with_object({}) do |column, hash|
|
51
|
+
column.csv_set(object, hash)
|
52
|
+
end
|
68
53
|
end
|
69
54
|
end
|
70
55
|
end
|
71
56
|
|
72
|
-
def
|
57
|
+
def parse(string, options = {})
|
73
58
|
csv = CSV.new(string, options.merge(headers: true))
|
74
59
|
|
75
|
-
# Drop the first record, it is the header record
|
76
60
|
csv.to_a.map do |row|
|
77
61
|
# Build up a hash using the column one at a time
|
78
|
-
|
79
|
-
|
62
|
+
columns.each_with_object(object_class.new) do |column, object|
|
63
|
+
column.object_set(row, object)
|
80
64
|
end
|
81
|
-
|
82
|
-
extracted_hash
|
83
65
|
end
|
84
66
|
end
|
67
|
+
|
68
|
+
private
|
69
|
+
|
70
|
+
attr_reader :column_set
|
85
71
|
end
|
86
72
|
end
|
data/lib/bumblebee/version.rb
CHANGED
@@ -0,0 +1,29 @@
|
|
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
|
+
require './spec/examples/converter_test_case'
|
12
|
+
|
13
|
+
describe ::Bumblebee::SimpleConverter do
|
14
|
+
describe '#convert' do
|
15
|
+
ConverterTestCase.all.each do |test_case|
|
16
|
+
it "should convert: #{test_case.arg}" do
|
17
|
+
converter = ::Bumblebee::SimpleConverter.new(test_case.arg)
|
18
|
+
|
19
|
+
test_case.convert_cases.each do |convert_case|
|
20
|
+
input = convert_case.first
|
21
|
+
output = convert_case.last
|
22
|
+
|
23
|
+
expect(converter.convert(input)).to eq(output)
|
24
|
+
expect(converter.convert(input).class).to eq(output.class)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -8,65 +8,180 @@
|
|
8
8
|
#
|
9
9
|
|
10
10
|
require 'spec_helper'
|
11
|
+
require 'examples/person_template'
|
12
|
+
require 'examples/simple_object'
|
11
13
|
|
12
14
|
describe ::Bumblebee::Template do
|
13
|
-
|
14
|
-
|
15
|
+
describe 'array/string-based columns and symbol based object keys' do
|
16
|
+
let(:data_objects) { yaml_fixture('simple', 'data.yml').map(&:symbolize_keys) }
|
15
17
|
|
16
|
-
|
17
|
-
let(:template) { ::Bumblebee::Template.new }
|
18
|
+
let(:csv_file) { fixture('simple', 'data.csv') }
|
18
19
|
|
19
|
-
|
20
|
+
let(:columns) { yaml_fixture('simple', 'columns.yml') }
|
20
21
|
|
21
|
-
|
22
|
-
subject.column(field, opts)
|
22
|
+
subject { ::Bumblebee::Template.new(columns: columns) }
|
23
23
|
|
24
|
-
|
25
|
-
|
26
|
-
|
24
|
+
specify '#generate_csv properly builds a CSV-formatted string' do
|
25
|
+
actual = subject.generate(data_objects)
|
26
|
+
|
27
|
+
expect(actual).to eq(csv_file)
|
28
|
+
end
|
29
|
+
|
30
|
+
specify '#parse_csv properly builds objects' do
|
31
|
+
actual = subject.parse(csv_file)
|
32
|
+
|
33
|
+
actual = actual.map(&:symbolize_keys)
|
34
|
+
|
35
|
+
expect(actual).to eq(data_objects)
|
27
36
|
end
|
28
37
|
end
|
29
38
|
|
30
|
-
describe '
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
39
|
+
describe 'array/string-based columns and OpenStruct objects' do
|
40
|
+
let(:data_objects) do
|
41
|
+
yaml_fixture('simple', 'data.yml').map { |h| OpenStruct.new(h.symbolize_keys) }
|
42
|
+
end
|
43
|
+
|
44
|
+
let(:csv_file) { fixture('simple', 'data.csv') }
|
35
45
|
|
36
|
-
|
37
|
-
|
38
|
-
|
46
|
+
let(:columns) { yaml_fixture('simple', 'columns.yml') }
|
47
|
+
|
48
|
+
subject { ::Bumblebee::Template.new(columns: columns, object_class: OpenStruct) }
|
49
|
+
|
50
|
+
specify '#generate_csv properly builds a CSV-formatted string' do
|
51
|
+
actual = subject.generate(data_objects)
|
52
|
+
|
53
|
+
expect(actual).to eq(csv_file)
|
54
|
+
end
|
55
|
+
|
56
|
+
specify '#parse_csv properly builds objects' do
|
57
|
+
actual = subject.parse(csv_file)
|
58
|
+
|
59
|
+
expect(actual).to eq(data_objects)
|
39
60
|
end
|
61
|
+
end
|
62
|
+
|
63
|
+
describe 'array/string-based columns and custom objects' do
|
64
|
+
let(:data_objects) do
|
65
|
+
yaml_fixture('simple', 'data.yml').map { |h| SimpleObject.new(h.symbolize_keys) }
|
66
|
+
end
|
67
|
+
|
68
|
+
let(:csv_file) { fixture('simple', 'data.csv') }
|
69
|
+
|
70
|
+
let(:columns) { yaml_fixture('simple', 'columns.yml') }
|
71
|
+
|
72
|
+
subject { ::Bumblebee::Template.new(columns: columns, object_class: SimpleObject) }
|
73
|
+
|
74
|
+
specify '#generate_csv properly builds a CSV-formatted string' do
|
75
|
+
actual = subject.generate(data_objects)
|
76
|
+
|
77
|
+
expect(actual).to eq(csv_file)
|
78
|
+
end
|
79
|
+
|
80
|
+
specify '#parse_csv properly builds objects' do
|
81
|
+
actual = subject.parse(csv_file)
|
82
|
+
|
83
|
+
expect(actual).to eq(data_objects)
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
describe 'config-based columns' do
|
88
|
+
let(:data_objects) { yaml_fixture('registrations', 'data.yml') }
|
89
|
+
|
90
|
+
let(:csv_file) { fixture('registrations', 'data.csv') }
|
91
|
+
|
92
|
+
let(:columns) { yaml_fixture('registrations', 'columns.yml') }
|
93
|
+
|
94
|
+
subject { ::Bumblebee::Template.new(columns: columns) }
|
40
95
|
|
41
|
-
specify '
|
42
|
-
|
43
|
-
|
96
|
+
specify '#generate_csv properly builds a CSV-formatted string' do
|
97
|
+
actual = subject.generate(data_objects)
|
98
|
+
|
99
|
+
expect(actual).to eq(csv_file)
|
100
|
+
end
|
101
|
+
|
102
|
+
specify '#parse_csv properly builds objects' do
|
103
|
+
actual = subject.parse(csv_file)
|
104
|
+
|
105
|
+
expect(actual).to eq(data_objects)
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
describe 'block-based (with local context) columns' do
|
110
|
+
let(:data_objects) { yaml_fixture('registrations', 'data.yml') }
|
111
|
+
|
112
|
+
let(:csv_file) { fixture('registrations', 'data.csv') }
|
113
|
+
|
114
|
+
let(:columns) { yaml_fixture('registrations', 'columns.yml') }
|
115
|
+
|
116
|
+
subject do
|
117
|
+
::Bumblebee::Template.new do |t|
|
118
|
+
columns.each do |header, opts|
|
119
|
+
t.column(header, opts)
|
120
|
+
end
|
44
121
|
end
|
122
|
+
end
|
123
|
+
|
124
|
+
specify '#generate_csv properly builds a CSV-formatted string' do
|
125
|
+
actual = subject.generate(data_objects)
|
126
|
+
|
127
|
+
expect(actual).to eq(csv_file)
|
128
|
+
end
|
129
|
+
|
130
|
+
specify '#parse_csv properly builds objects' do
|
131
|
+
actual = subject.parse(csv_file)
|
45
132
|
|
46
|
-
expect(
|
47
|
-
expect(template.columns.first.field).to eq(field)
|
48
|
-
expect(template.columns.first.header).to eq(opts[:header])
|
133
|
+
expect(actual).to eq(data_objects)
|
49
134
|
end
|
50
135
|
end
|
51
136
|
|
52
|
-
describe '
|
53
|
-
|
54
|
-
|
137
|
+
describe 'block-based (without local context) columns' do
|
138
|
+
let(:data_objects) { yaml_fixture('registrations', 'data.yml') }
|
139
|
+
|
140
|
+
let(:csv_file) { fixture('registrations', 'data.csv') }
|
141
|
+
|
142
|
+
subject do
|
143
|
+
::Bumblebee::Template.new do
|
144
|
+
columns = yaml_fixture('registrations', 'columns.yml')
|
145
|
+
columns.each do |header, opts|
|
146
|
+
column(header, opts)
|
147
|
+
end
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
specify '#generate_csv properly builds a CSV-formatted string' do
|
152
|
+
actual = subject.generate(data_objects)
|
153
|
+
|
154
|
+
expect(actual).to eq(csv_file)
|
55
155
|
end
|
56
156
|
|
57
|
-
|
58
|
-
|
157
|
+
specify '#parse_csv properly builds objects' do
|
158
|
+
actual = subject.parse(csv_file)
|
159
|
+
|
160
|
+
expect(actual).to eq(data_objects)
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
describe 'class-based columns' do
|
165
|
+
let(:data_objects) { yaml_fixture('people', 'data.yml') }
|
166
|
+
|
167
|
+
let(:csv_file) { fixture('people', 'data.csv') }
|
168
|
+
|
169
|
+
subject { PersonTemplate.new }
|
170
|
+
|
171
|
+
specify '#generate_csv properly builds a CSV-formatted string' do
|
172
|
+
template = PersonTemplate.new
|
173
|
+
|
174
|
+
actual = template.generate(data_objects)
|
175
|
+
|
176
|
+
expect(actual).to eq(csv_file)
|
59
177
|
end
|
60
178
|
|
61
|
-
|
62
|
-
template =
|
179
|
+
specify '#parse_csv properly builds objects' do
|
180
|
+
template = PersonTemplate.new
|
63
181
|
|
64
|
-
|
65
|
-
expect(template.columns.first.field).to eq(:id)
|
66
|
-
expect(template.columns.first.header).to eq('ID #')
|
182
|
+
actual = template.parse(csv_file)
|
67
183
|
|
68
|
-
expect(
|
69
|
-
expect(template.columns.last.header).to eq('First Name')
|
184
|
+
expect(actual).to eq(data_objects)
|
70
185
|
end
|
71
186
|
end
|
72
187
|
end
|