morfo 0.2.0 → 0.3.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/.travis.yml +3 -2
- data/CONTRIBUTING.md +7 -0
- data/Guardfile +1 -1
- data/README.md +0 -9
- data/benchmarks/data.rb +4 -4
- data/benchmarks/run.rb +2 -0
- data/lib/morfo.rb +9 -7
- data/lib/morfo/version.rb +1 -1
- data/spec/lib/morfo_spec.rb +160 -62
- metadata +39 -38
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3500e5ec94def95ffed72498a8dcfee478e10e80
|
4
|
+
data.tar.gz: b543a2e81a8032f6bc5736b42761dbb08b822ab7
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7a373305e8dfd3add0b3070c66e1d357dde9b453746942f3b03afaa3c68b99e5124dac54147e499cf08c05c8489e79f8cbfa3538c5f36164213cb592f077f8e1
|
7
|
+
data.tar.gz: 5cde3c3dd8d6082817b1976c070e673045d9b1ff496b45c36330311888747910dc62de4ef1bb92a77d27154d99e4658b77cd04dbda9e1289ac04fae72057ae63
|
data/.travis.yml
CHANGED
data/CONTRIBUTING.md
ADDED
data/Guardfile
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
# A sample Guardfile
|
2
2
|
# More info at https://github.com/guard/guard#readme
|
3
3
|
|
4
|
-
guard :rspec, all_on_start: true do
|
4
|
+
guard :rspec, cmd: 'bundle exec rspec', all_on_start: true do
|
5
5
|
watch(%r{^spec/.+_spec\.rb$})
|
6
6
|
watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
|
7
7
|
watch('spec/spec_helper.rb') { 'spec' }
|
data/README.md
CHANGED
@@ -112,12 +112,3 @@ If the value of your field should be based on multiple fields of the input row,
|
|
112
112
|
# {:name=>"Robin Hood", :status=>"Best Friend"},
|
113
113
|
# {:name=>"Sherlock Holmes", :status=>'Best Friend'}
|
114
114
|
# ]
|
115
|
-
|
116
|
-
|
117
|
-
## Contributing
|
118
|
-
|
119
|
-
1. Fork it
|
120
|
-
2. Create your feature branch (`git checkout -b my-new-feature`)
|
121
|
-
3. Commit your changes (`git commit -am 'Add some feature'`)
|
122
|
-
4. Push to the branch (`git push origin my-new-feature`)
|
123
|
-
5. Create new Pull Request
|
data/benchmarks/data.rb
CHANGED
@@ -46,20 +46,20 @@ module BenchmarkData
|
|
46
46
|
|
47
47
|
class SimpleMorferSymbol < Morfo::Base
|
48
48
|
BenchmarkData.row.keys.each do |field|
|
49
|
-
field(:"#{field}_mapped"
|
49
|
+
field(:"#{field}_mapped").from(field)
|
50
50
|
end
|
51
51
|
end
|
52
52
|
|
53
53
|
class SimpleMorferString < Morfo::Base
|
54
54
|
BenchmarkData.row_string_keys.keys.each do |field|
|
55
|
-
field("#{field}_mapped"
|
55
|
+
field("#{field}_mapped").from(field)
|
56
56
|
end
|
57
57
|
end
|
58
58
|
|
59
59
|
class NestedMorferSymbol < Morfo::Base
|
60
60
|
BenchmarkData.row_nested.each do |key, value|
|
61
61
|
value.keys.each do |field|
|
62
|
-
field(:"#{field}_mapped"
|
62
|
+
field(:"#{field}_mapped").from(key, field)
|
63
63
|
end
|
64
64
|
end
|
65
65
|
end
|
@@ -67,7 +67,7 @@ module BenchmarkData
|
|
67
67
|
class NestedMorferString < Morfo::Base
|
68
68
|
BenchmarkData.row_nested_string_keys.each do |key, value|
|
69
69
|
value.keys.each do |field|
|
70
|
-
field("#{field}_mapped"
|
70
|
+
field("#{field}_mapped").from(key, field)
|
71
71
|
end
|
72
72
|
end
|
73
73
|
end
|
data/benchmarks/run.rb
CHANGED
@@ -34,6 +34,7 @@ definitions.each do |defintition|
|
|
34
34
|
)
|
35
35
|
end
|
36
36
|
|
37
|
+
puts "running on: #{RUBY_ENGINE}:"
|
37
38
|
Benchmark.bm(20) do |x|
|
38
39
|
definitions.each do |defintition|
|
39
40
|
x.report(defintition[:label]) do
|
@@ -43,4 +44,5 @@ Benchmark.bm(20) do |x|
|
|
43
44
|
end
|
44
45
|
end
|
45
46
|
end
|
47
|
+
puts "===="
|
46
48
|
|
data/lib/morfo.rb
CHANGED
@@ -10,13 +10,15 @@ module Morfo
|
|
10
10
|
end
|
11
11
|
|
12
12
|
def self.morf input
|
13
|
-
input.map {|row|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
13
|
+
input.map { |row| morf_single(row) }
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.morf_single input
|
17
|
+
output = {}
|
18
|
+
mapping_actions.each do |field_path, action|
|
19
|
+
deep_merge!(output, store_value(action.execute(input), field_path))
|
20
|
+
end
|
21
|
+
output
|
20
22
|
end
|
21
23
|
|
22
24
|
private
|
data/lib/morfo/version.rb
CHANGED
data/spec/lib/morfo_spec.rb
CHANGED
@@ -30,27 +30,40 @@ describe Morfo::Base do
|
|
30
30
|
]
|
31
31
|
end
|
32
32
|
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
33
|
+
let(:single_input) do
|
34
|
+
input.first
|
35
|
+
end
|
36
|
+
|
37
|
+
context 'errors' do
|
38
|
+
subject(:no_from) do
|
39
|
+
class NilMorfer < Morfo::Base
|
40
|
+
field(:my_field)
|
40
41
|
end
|
42
|
+
NilMorfer
|
43
|
+
end
|
44
|
+
|
45
|
+
describe '#morf' do
|
41
46
|
it 'raises error for nil field' do
|
42
47
|
expect{no_from.morf([{my_field: :something}])}.to raise_error(ArgumentError)
|
43
48
|
end
|
44
49
|
end
|
45
50
|
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
51
|
+
describe '#morf_single' do
|
52
|
+
it 'raises error for nil field' do
|
53
|
+
expect{no_from.morf_single({my_field: :something})}.to raise_error(ArgumentError)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
context '1 to 1 conversion' do
|
59
|
+
subject do
|
60
|
+
class TitleMorfer < Morfo::Base
|
61
|
+
field(:tv_show_title).from(:title)
|
52
62
|
end
|
63
|
+
TitleMorfer
|
64
|
+
end
|
53
65
|
|
66
|
+
describe '#morf' do
|
54
67
|
it 'maps title correctly' do
|
55
68
|
expected_output = input.map{|v| {tv_show_title: v[:title]} }
|
56
69
|
expect(subject.morf(input)).to eq(expected_output)
|
@@ -63,58 +76,91 @@ describe Morfo::Base do
|
|
63
76
|
end
|
64
77
|
end
|
65
78
|
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
end
|
71
|
-
NumCastMorfer
|
79
|
+
describe '#morf_single' do
|
80
|
+
it 'maps title correctly' do
|
81
|
+
expected_output = { tv_show_title: single_input[:title] }
|
82
|
+
expect(subject.morf_single(single_input)).to eq(expected_output)
|
72
83
|
end
|
73
84
|
|
85
|
+
it 'leaves out nil values in result' do
|
86
|
+
expected_output = {}
|
87
|
+
modified_input = single_input.reject { |k, v| k == :title }
|
88
|
+
expect(subject.morf_single(modified_input)).to eq(expected_output)
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
context '1 to 1 conversion with transformation' do
|
94
|
+
subject do
|
95
|
+
class NumCastMorfer < Morfo::Base
|
96
|
+
field(:cast_num).from(:cast).transformed{|v| v.size}
|
97
|
+
end
|
98
|
+
NumCastMorfer
|
99
|
+
end
|
100
|
+
|
101
|
+
describe '#morf' do
|
74
102
|
it 'calls transformation correctly' do
|
75
103
|
expected_output = input.map{|v| {cast_num: v[:cast].size} }
|
76
104
|
expect(subject.morf(input)).to eq(expected_output)
|
77
105
|
end
|
78
106
|
end
|
79
107
|
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
field(:also_title).from(:title)
|
85
|
-
end
|
86
|
-
MutliTitleMorfer
|
108
|
+
describe '#morf_single' do
|
109
|
+
it 'calls transformation correctly' do
|
110
|
+
expected_output = { cast_num: single_input[:cast].size }
|
111
|
+
expect(subject.morf_single(single_input)).to eq(expected_output)
|
87
112
|
end
|
113
|
+
end
|
114
|
+
end
|
88
115
|
|
116
|
+
context '1 to many conversion' do
|
117
|
+
subject do
|
118
|
+
class MutliTitleMorfer < Morfo::Base
|
119
|
+
field(:title).from(:title)
|
120
|
+
field(:also_title).from(:title)
|
121
|
+
end
|
122
|
+
MutliTitleMorfer
|
123
|
+
end
|
124
|
+
|
125
|
+
describe '#morf' do
|
89
126
|
it 'maps title to multiple fields' do
|
90
127
|
expected_output = input.map{|v| {title: v[:title], also_title: v[:title]} }
|
91
128
|
expect(subject.morf(input)).to eq(expected_output)
|
92
129
|
end
|
93
130
|
end
|
94
131
|
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
132
|
+
describe '#morf_single' do
|
133
|
+
it 'maps title to multiple fields' do
|
134
|
+
expected_output = {title: single_input[:title], also_title: single_input[:title]}
|
135
|
+
expect(subject.morf_single(single_input)).to eq(expected_output)
|
136
|
+
end
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
context 'nested conversion' do
|
141
|
+
context 'nested source' do
|
142
|
+
subject(:valid_path) do
|
143
|
+
class ImdbRatingMorfer < Morfo::Base
|
144
|
+
field(:rating).from(:ratings, :imdb)
|
102
145
|
end
|
146
|
+
ImdbRatingMorfer
|
147
|
+
end
|
103
148
|
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
end
|
108
|
-
ImdbRatingMorferWithTransformation
|
149
|
+
subject(:valid_path_with_transformation) do
|
150
|
+
class ImdbRatingMorferWithTransformation < Morfo::Base
|
151
|
+
field(:rating).from(:ratings, :imdb).transformed {|v| "Rating: #{v}"}
|
109
152
|
end
|
153
|
+
ImdbRatingMorferWithTransformation
|
154
|
+
end
|
110
155
|
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
end
|
115
|
-
InvalidImdbRatingMorfer
|
156
|
+
subject(:invalid_path) do
|
157
|
+
class InvalidImdbRatingMorfer < Morfo::Base
|
158
|
+
field(:rating).from(:very, :long, :path, :that, :might, :not, :exist)
|
116
159
|
end
|
160
|
+
InvalidImdbRatingMorfer
|
161
|
+
end
|
117
162
|
|
163
|
+
describe '#morf' do
|
118
164
|
it 'maps nested attributes' do
|
119
165
|
expected_output = input.map{|v| {rating: v[:ratings][:imdb]} }
|
120
166
|
expect(valid_path.morf(input)).to eq(expected_output)
|
@@ -131,15 +177,34 @@ describe Morfo::Base do
|
|
131
177
|
end
|
132
178
|
end
|
133
179
|
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
180
|
+
describe '#morf_single' do
|
181
|
+
it 'maps nested attributes' do
|
182
|
+
expected_output = {rating: single_input[:ratings][:imdb]}
|
183
|
+
expect(valid_path.morf_single(single_input)).to eq(expected_output)
|
184
|
+
end
|
185
|
+
|
186
|
+
it 'maps nested attributes with transformation' do
|
187
|
+
expected_output = {rating: "Rating: #{single_input[:ratings][:imdb]}"}
|
188
|
+
expect(valid_path_with_transformation.morf_single(single_input)).to eq(expected_output)
|
189
|
+
end
|
190
|
+
|
191
|
+
it 'doesn\'t raise error for invalid path' do
|
192
|
+
expected_output = { }
|
193
|
+
expect(invalid_path.morf_single(single_input)).to eq(expected_output)
|
141
194
|
end
|
195
|
+
end
|
196
|
+
end
|
142
197
|
|
198
|
+
context 'nested destination' do
|
199
|
+
subject do
|
200
|
+
class WrapperMorfer < Morfo::Base
|
201
|
+
field(:tv_show, :title).from(:title)
|
202
|
+
field(:tv_show, :channel).from(:channel).transformed {|v| "Channel: #{v}"}
|
203
|
+
end
|
204
|
+
WrapperMorfer
|
205
|
+
end
|
206
|
+
|
207
|
+
describe '#morf' do
|
143
208
|
it 'maps to nested destination' do
|
144
209
|
expected_output = input.map{|v|
|
145
210
|
{
|
@@ -152,16 +217,30 @@ describe Morfo::Base do
|
|
152
217
|
expect(subject.morf(input)).to eq(expected_output)
|
153
218
|
end
|
154
219
|
end
|
155
|
-
end
|
156
220
|
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
221
|
+
describe '#morf_single' do
|
222
|
+
it 'maps to nested destination' do
|
223
|
+
expected_output = {
|
224
|
+
tv_show: {
|
225
|
+
title: single_input[:title],
|
226
|
+
channel: "Channel: #{single_input[:channel]}",
|
227
|
+
}
|
228
|
+
}
|
229
|
+
expect(subject.morf_single(single_input)).to eq(expected_output)
|
161
230
|
end
|
162
|
-
TitlePrefixMorfer
|
163
231
|
end
|
232
|
+
end
|
233
|
+
end
|
234
|
+
|
235
|
+
context 'calculations' do
|
236
|
+
subject do
|
237
|
+
class TitlePrefixMorfer < Morfo::Base
|
238
|
+
field(:title_with_channel).calculated{|r| "#{r[:title]}, (#{r[:channel]})"}
|
239
|
+
end
|
240
|
+
TitlePrefixMorfer
|
241
|
+
end
|
164
242
|
|
243
|
+
describe '#morf' do
|
165
244
|
it 'maps calculation correctly' do
|
166
245
|
expected_output = input.map{|r|
|
167
246
|
{
|
@@ -172,18 +251,37 @@ describe Morfo::Base do
|
|
172
251
|
end
|
173
252
|
end
|
174
253
|
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
254
|
+
describe '#morf_single' do
|
255
|
+
it 'maps calculation correctly' do
|
256
|
+
expected_output = {
|
257
|
+
title_with_channel: "#{single_input[:title]}, (#{single_input[:channel]})"
|
258
|
+
}
|
259
|
+
|
260
|
+
expect(subject.morf_single(single_input)).to eq(expected_output)
|
181
261
|
end
|
262
|
+
end
|
263
|
+
end
|
264
|
+
|
265
|
+
context 'static values' do
|
266
|
+
subject do
|
267
|
+
class StaticTitleMorfer < Morfo::Base
|
268
|
+
field(:new_title).calculated{ 'Static Title' }
|
269
|
+
end
|
270
|
+
StaticTitleMorfer
|
271
|
+
end
|
182
272
|
|
273
|
+
describe '#morf' do
|
183
274
|
it 'maps static value correctly' do
|
184
275
|
expected_output = input.map{|r| {new_title: 'Static Title'} }
|
185
276
|
expect(subject.morf(input)).to eq(expected_output)
|
186
277
|
end
|
187
278
|
end
|
279
|
+
|
280
|
+
describe '#morf_single' do
|
281
|
+
it 'maps static value correctly' do
|
282
|
+
expected_output = { new_title: 'Static Title' }
|
283
|
+
expect(subject.morf_single(single_input)).to eq(expected_output)
|
284
|
+
end
|
285
|
+
end
|
188
286
|
end
|
189
287
|
end
|
metadata
CHANGED
@@ -1,77 +1,77 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: morfo
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Leif Gensert
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-
|
11
|
+
date: 2014-10-28 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake
|
15
|
-
version_requirements: !ruby/object:Gem::Requirement
|
16
|
-
requirements:
|
17
|
-
- - '>='
|
18
|
-
- !ruby/object:Gem::Version
|
19
|
-
version: '0'
|
20
15
|
requirement: !ruby/object:Gem::Requirement
|
21
16
|
requirements:
|
22
|
-
- -
|
17
|
+
- - ">="
|
23
18
|
- !ruby/object:Gem::Version
|
24
19
|
version: '0'
|
25
|
-
prerelease: false
|
26
20
|
type: :runtime
|
27
|
-
|
28
|
-
name: json
|
21
|
+
prerelease: false
|
29
22
|
version_requirements: !ruby/object:Gem::Requirement
|
30
23
|
requirements:
|
31
|
-
- -
|
24
|
+
- - ">="
|
32
25
|
- !ruby/object:Gem::Version
|
33
26
|
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: json
|
34
29
|
requirement: !ruby/object:Gem::Requirement
|
35
30
|
requirements:
|
36
|
-
- -
|
31
|
+
- - ">="
|
37
32
|
- !ruby/object:Gem::Version
|
38
33
|
version: '0'
|
39
|
-
prerelease: false
|
40
34
|
type: :runtime
|
41
|
-
|
42
|
-
name: bundler
|
35
|
+
prerelease: false
|
43
36
|
version_requirements: !ruby/object:Gem::Requirement
|
44
37
|
requirements:
|
45
|
-
- -
|
38
|
+
- - ">="
|
46
39
|
- !ruby/object:Gem::Version
|
47
|
-
version: '
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: bundler
|
48
43
|
requirement: !ruby/object:Gem::Requirement
|
49
44
|
requirements:
|
50
|
-
- - ~>
|
45
|
+
- - "~>"
|
51
46
|
- !ruby/object:Gem::Version
|
52
47
|
version: '1.3'
|
53
|
-
prerelease: false
|
54
48
|
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '1.3'
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
56
|
name: rspec
|
57
|
-
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
58
|
requirements:
|
59
|
-
- -
|
59
|
+
- - ">="
|
60
60
|
- !ruby/object:Gem::Version
|
61
61
|
version: '2.14'
|
62
|
-
- - <
|
62
|
+
- - "<"
|
63
63
|
- !ruby/object:Gem::Version
|
64
64
|
version: '4.0'
|
65
|
-
|
65
|
+
type: :development
|
66
|
+
prerelease: false
|
67
|
+
version_requirements: !ruby/object:Gem::Requirement
|
66
68
|
requirements:
|
67
|
-
- -
|
69
|
+
- - ">="
|
68
70
|
- !ruby/object:Gem::Version
|
69
71
|
version: '2.14'
|
70
|
-
- - <
|
72
|
+
- - "<"
|
71
73
|
- !ruby/object:Gem::Version
|
72
74
|
version: '4.0'
|
73
|
-
prerelease: false
|
74
|
-
type: :development
|
75
75
|
description: This gem provides a DSL for converting one hash into another
|
76
76
|
email:
|
77
77
|
- leif@propertybase.com
|
@@ -79,9 +79,10 @@ executables: []
|
|
79
79
|
extensions: []
|
80
80
|
extra_rdoc_files: []
|
81
81
|
files:
|
82
|
-
- .gitignore
|
83
|
-
- .rspec
|
84
|
-
- .travis.yml
|
82
|
+
- ".gitignore"
|
83
|
+
- ".rspec"
|
84
|
+
- ".travis.yml"
|
85
|
+
- CONTRIBUTING.md
|
85
86
|
- Gemfile
|
86
87
|
- Guardfile
|
87
88
|
- LICENSE.txt
|
@@ -99,24 +100,24 @@ homepage: ''
|
|
99
100
|
licenses:
|
100
101
|
- MIT
|
101
102
|
metadata: {}
|
102
|
-
post_install_message:
|
103
|
+
post_install_message:
|
103
104
|
rdoc_options: []
|
104
105
|
require_paths:
|
105
106
|
- lib
|
106
107
|
required_ruby_version: !ruby/object:Gem::Requirement
|
107
108
|
requirements:
|
108
|
-
- -
|
109
|
+
- - ">="
|
109
110
|
- !ruby/object:Gem::Version
|
110
111
|
version: '0'
|
111
112
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
112
113
|
requirements:
|
113
|
-
- -
|
114
|
+
- - ">="
|
114
115
|
- !ruby/object:Gem::Version
|
115
116
|
version: '0'
|
116
117
|
requirements: []
|
117
|
-
rubyforge_project:
|
118
|
-
rubygems_version: 2.
|
119
|
-
signing_key:
|
118
|
+
rubyforge_project:
|
119
|
+
rubygems_version: 2.2.2
|
120
|
+
signing_key:
|
120
121
|
specification_version: 4
|
121
122
|
summary: Inspired by ActiveImporter, this gem generically converts an array of hashes
|
122
123
|
test_files:
|