bumblebee 2.1.0 → 3.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|