morfo 0.1.0 → 0.2.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 +4 -3
- data/Gemfile +3 -0
- data/README.md +12 -10
- data/lib/morfo/actions.rb +70 -35
- data/lib/morfo/version.rb +1 -1
- data/lib/morfo.rb +23 -15
- data/morfo.gemspec +2 -0
- data/spec/lib/morfo_spec.rb +15 -15
- metadata +43 -30
- data/lib/morfo/actions/base.rb +0 -0
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 69e889d25298c9a89daa889b8f7f406e5849aace
|
4
|
+
data.tar.gz: 84167fea094d1c085e0c6328f44dcf7e174557b4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d22983ba7d6abfbd603dd924985495aaa29b3f580bf683971b1408ca0aeab062a14fa917a7830b623f70f63ce548bf71e352b8ef964627904b717f0ccfeac0f6
|
7
|
+
data.tar.gz: 02ab5712dfc027729f4d433adc23f9c54785569aeaecfeb211f8b3a159867b5f65f755dd0349501c6b4ef2a962475b912828823944e4c4e3d791218031ac8af0
|
data/.travis.yml
CHANGED
@@ -3,14 +3,15 @@ cache: bundler
|
|
3
3
|
env: JRUBY_OPTS=--2.0
|
4
4
|
rvm:
|
5
5
|
- 2.0.0
|
6
|
-
-
|
6
|
+
- 2.1.0
|
7
|
+
- jruby-1.7.10
|
7
8
|
- ruby-head
|
8
9
|
- jruby-head
|
9
|
-
- rbx-2.2.
|
10
|
+
- rbx-2.2.3
|
10
11
|
matrix:
|
11
12
|
allow_failures:
|
12
13
|
- rvm: ruby-head
|
13
14
|
- rvm: jruby-head
|
14
|
-
- rvm: rbx-2.2.
|
15
|
+
- rvm: rbx-2.2.3
|
15
16
|
script:
|
16
17
|
- bundle exec rake spec
|
data/Gemfile
CHANGED
@@ -9,8 +9,11 @@ group :test, :development do
|
|
9
9
|
gem 'guard-rspec'
|
10
10
|
gem 'simplecov'
|
11
11
|
gem 'pry'
|
12
|
+
gem 'rubinius-coverage', platform: :rbx
|
12
13
|
|
13
14
|
gem 'rb-inotify', require: false
|
14
15
|
gem 'rb-fsevent', require: false
|
15
16
|
gem 'rb-fchange', require: false
|
16
17
|
end
|
18
|
+
|
19
|
+
gem 'json'
|
data/README.md
CHANGED
@@ -30,10 +30,10 @@ Use the `field` method to specify what fields exist and where they will get thei
|
|
30
30
|
|
31
31
|
### Simple Mapping
|
32
32
|
|
33
|
-
The most basic form is
|
33
|
+
The most basic form is copying the value from another field.
|
34
34
|
|
35
35
|
class Title < Morfo::Base
|
36
|
-
field
|
36
|
+
field(:tv_show_title)from(:title)
|
37
37
|
end
|
38
38
|
|
39
39
|
Afterwards use the `morf` method to morf all hashes in one array to the end result:
|
@@ -48,12 +48,12 @@ Afterwards use the `morf` method to morf all hashes in one array to the end resu
|
|
48
48
|
# {tv_show_title: 'Breaking Bad'},
|
49
49
|
# ]
|
50
50
|
|
51
|
-
If you want to have access to nested values,
|
51
|
+
If you want to have access to nested values, just provide the path to that field comma separated.
|
52
52
|
|
53
53
|
|
54
54
|
class Name < Morfo::Base
|
55
|
-
field
|
56
|
-
field
|
55
|
+
field(:first_name).from(:name, :first)
|
56
|
+
field(:last_name).from(:name, :last)
|
57
57
|
end
|
58
58
|
|
59
59
|
Name.morf([
|
@@ -78,10 +78,10 @@ If you want to have access to nested values, you'll have to provide an array as
|
|
78
78
|
|
79
79
|
## Transformations
|
80
80
|
|
81
|
-
|
81
|
+
It's also possible to transform the value in any way ruby lets you transform a value. just provide a block in the `transformed` method.
|
82
82
|
|
83
83
|
class AndZombies < Morfo::Base
|
84
|
-
field(:title
|
84
|
+
field(:title).from(title).transformed {|title| "#{title} and Zombies"}
|
85
85
|
end
|
86
86
|
|
87
87
|
AndZombies.morf([
|
@@ -94,11 +94,13 @@ Every field can also take a transformation block, so that the original input can
|
|
94
94
|
# {title: 'Fifty Shades of Grey and Zombies'},
|
95
95
|
# ]
|
96
96
|
|
97
|
-
|
97
|
+
## Calculations
|
98
|
+
|
99
|
+
If the value of your field should be based on multiple fields of the input row, yoy can specify a calculation block via the `calculated` method. As an argument the whole input row is passed in.
|
98
100
|
|
99
101
|
class NameConcatenator < Morfo::Base
|
100
|
-
field(:name) {|
|
101
|
-
field(:status) {
|
102
|
+
field(:name).calculated {|row| "#{row[:first_name]} #{row[:last_name]}"}
|
103
|
+
field(:status).calculated {'Best Friend'}
|
102
104
|
end
|
103
105
|
|
104
106
|
NameConcatenator.morf([
|
data/lib/morfo/actions.rb
CHANGED
@@ -1,56 +1,91 @@
|
|
1
1
|
module Morfo
|
2
2
|
module Actions
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
3
|
+
class Field
|
4
|
+
attr_reader :field_path
|
5
|
+
attr_reader :actions
|
6
|
+
|
7
|
+
def initialize field_path, actions
|
8
|
+
@field_path = field_path
|
9
|
+
@actions = actions
|
8
10
|
end
|
9
11
|
|
10
|
-
def
|
11
|
-
|
12
|
+
def from *from_field_path
|
13
|
+
act = FromAction.new self, from_field_path
|
14
|
+
actions[field_path] = act
|
15
|
+
act
|
16
|
+
end
|
12
17
|
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
{ key => hash }
|
18
|
-
end
|
19
|
-
end
|
18
|
+
def calculated &calculate_blk
|
19
|
+
act = CalculationAction.new self, field_path, calculate_blk
|
20
|
+
actions[field_path] = act
|
21
|
+
act
|
20
22
|
end
|
21
|
-
end
|
22
23
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
24
|
+
def execute row
|
25
|
+
raise ArgumentError,
|
26
|
+
"No field to get value from is specified for #{field_path.inspect}"
|
27
|
+
end
|
28
|
+
end
|
27
29
|
|
28
|
-
|
29
|
-
|
30
|
-
@
|
30
|
+
class CalculationAction
|
31
|
+
def initialize field, from_field_path, calculate_blk
|
32
|
+
@field = field
|
33
|
+
@from_field_path = from_field_path
|
34
|
+
@calculate_blk = calculate_blk
|
31
35
|
end
|
32
36
|
|
33
37
|
def execute row
|
34
|
-
|
38
|
+
calculate_blk.call(row)
|
35
39
|
end
|
40
|
+
|
41
|
+
private
|
42
|
+
attr_reader :field
|
43
|
+
attr_reader :from_field_path
|
44
|
+
attr_reader :calculate_blk
|
36
45
|
end
|
37
46
|
|
38
|
-
class
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
47
|
+
class FromAction
|
48
|
+
def initialize field, from_field_path
|
49
|
+
@field = field
|
50
|
+
@from_field_path = from_field_path
|
51
|
+
end
|
43
52
|
|
44
|
-
def
|
45
|
-
|
46
|
-
|
47
|
-
|
53
|
+
def transformed &blk
|
54
|
+
act = TransformAction.new self, from_field_path, blk
|
55
|
+
field.actions[field.field_path] = act
|
56
|
+
act
|
48
57
|
end
|
49
58
|
|
50
59
|
def execute row
|
51
|
-
|
52
|
-
store_value(to, transformation.call(resulting_value,row))
|
60
|
+
extract_value(from_field_path, row)
|
53
61
|
end
|
62
|
+
|
63
|
+
private
|
64
|
+
attr_reader :field
|
65
|
+
attr_reader :from_field_path
|
66
|
+
|
67
|
+
def extract_value from, row
|
68
|
+
from.inject(row) do |resulting_value, key|
|
69
|
+
resulting_value ? resulting_value[key] : nil
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
class TransformAction
|
75
|
+
def initialize previous_action, from_field_path, transform_blk
|
76
|
+
@previous_action = previous_action
|
77
|
+
@from_field_path = from_field_path
|
78
|
+
@transform_blk = transform_blk
|
79
|
+
end
|
80
|
+
|
81
|
+
def execute row
|
82
|
+
transform_blk.call(previous_action.execute(row))
|
83
|
+
end
|
84
|
+
|
85
|
+
private
|
86
|
+
attr_reader :previous_action
|
87
|
+
attr_reader :from_field_path
|
88
|
+
attr_reader :transform_blk
|
54
89
|
end
|
55
90
|
end
|
56
|
-
end
|
91
|
+
end
|
data/lib/morfo/version.rb
CHANGED
data/lib/morfo.rb
CHANGED
@@ -3,29 +3,37 @@ require 'morfo/actions'
|
|
3
3
|
|
4
4
|
module Morfo
|
5
5
|
class Base
|
6
|
-
def self.field
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
raise(
|
11
|
-
ArgumentError,
|
12
|
-
"No field to get value from is specified for #{field_name.inspect}"
|
13
|
-
) unless definition[:from]
|
14
|
-
mapping_actions << Morfo::Actions::MapAction.new(definition[:from], field_name)
|
15
|
-
end
|
6
|
+
def self.field *field_path
|
7
|
+
act = Morfo::Actions::Field.new(field_path, mapping_actions)
|
8
|
+
mapping_actions[field_path] = act
|
9
|
+
act
|
16
10
|
end
|
17
11
|
|
18
12
|
def self.morf input
|
19
|
-
input.map
|
20
|
-
|
21
|
-
|
13
|
+
input.map {|row|
|
14
|
+
output_row = {}
|
15
|
+
mapping_actions.each do |field_path, action|
|
16
|
+
deep_merge!(output_row, store_value(action.execute(row), field_path))
|
22
17
|
end
|
23
|
-
|
18
|
+
output_row
|
19
|
+
}
|
24
20
|
end
|
25
21
|
|
26
22
|
private
|
27
23
|
def self.mapping_actions
|
28
|
-
@actions ||=
|
24
|
+
@actions ||= {}
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.store_value value, to
|
28
|
+
return {} if value.nil?
|
29
|
+
|
30
|
+
to.reverse.inject({}) do |hash, key|
|
31
|
+
if hash.keys.first.nil?
|
32
|
+
hash.merge!(key => value)
|
33
|
+
else
|
34
|
+
{ key => hash }
|
35
|
+
end
|
36
|
+
end
|
29
37
|
end
|
30
38
|
|
31
39
|
def self.deep_merge! hash, other_hash, &block
|
data/morfo.gemspec
CHANGED
@@ -19,6 +19,8 @@ Gem::Specification.new do |spec|
|
|
19
19
|
spec.require_paths = ['lib']
|
20
20
|
|
21
21
|
spec.add_dependency 'rake'
|
22
|
+
spec.add_dependency 'json'
|
23
|
+
spec.add_dependency 'rubysl' if RUBY_ENGINE == 'rbx'
|
22
24
|
|
23
25
|
spec.add_development_dependency 'bundler', '~> 1.3'
|
24
26
|
spec.add_development_dependency 'rspec', '>= 2.14', '< 4.0'
|
data/spec/lib/morfo_spec.rb
CHANGED
@@ -34,19 +34,19 @@ describe Morfo::Base do
|
|
34
34
|
context 'errors' do
|
35
35
|
subject(:no_from) do
|
36
36
|
class NilMorfer < Morfo::Base
|
37
|
-
field
|
37
|
+
field(:my_field)
|
38
38
|
end
|
39
39
|
NilMorfer
|
40
40
|
end
|
41
41
|
it 'raises error for nil field' do
|
42
|
-
expect{no_from.morf([])}.to raise_error(ArgumentError)
|
42
|
+
expect{no_from.morf([{my_field: :something}])}.to raise_error(ArgumentError)
|
43
43
|
end
|
44
44
|
end
|
45
45
|
|
46
46
|
context '1 to 1 conversion' do
|
47
47
|
subject do
|
48
48
|
class TitleMorfer < Morfo::Base
|
49
|
-
field
|
49
|
+
field(:tv_show_title).from(:title)
|
50
50
|
end
|
51
51
|
TitleMorfer
|
52
52
|
end
|
@@ -66,7 +66,7 @@ describe Morfo::Base do
|
|
66
66
|
context '1 to 1 conversion with transformation' do
|
67
67
|
subject do
|
68
68
|
class NumCastMorfer < Morfo::Base
|
69
|
-
field(:cast_num
|
69
|
+
field(:cast_num).from(:cast).transformed{|v| v.size}
|
70
70
|
end
|
71
71
|
NumCastMorfer
|
72
72
|
end
|
@@ -80,8 +80,8 @@ describe Morfo::Base do
|
|
80
80
|
context '1 to many conversion' do
|
81
81
|
subject do
|
82
82
|
class MutliTitleMorfer < Morfo::Base
|
83
|
-
field
|
84
|
-
field
|
83
|
+
field(:title).from(:title)
|
84
|
+
field(:also_title).from(:title)
|
85
85
|
end
|
86
86
|
MutliTitleMorfer
|
87
87
|
end
|
@@ -96,21 +96,21 @@ describe Morfo::Base do
|
|
96
96
|
context 'nested source' do
|
97
97
|
subject(:valid_path) do
|
98
98
|
class ImdbRatingMorfer < Morfo::Base
|
99
|
-
field
|
99
|
+
field(:rating).from(:ratings, :imdb)
|
100
100
|
end
|
101
101
|
ImdbRatingMorfer
|
102
102
|
end
|
103
103
|
|
104
104
|
subject(:valid_path_with_transformation) do
|
105
|
-
class
|
106
|
-
field(:rating
|
105
|
+
class ImdbRatingMorferWithTransformation < Morfo::Base
|
106
|
+
field(:rating).from(:ratings, :imdb).transformed {|v| "Rating: #{v}"}
|
107
107
|
end
|
108
|
-
|
108
|
+
ImdbRatingMorferWithTransformation
|
109
109
|
end
|
110
110
|
|
111
111
|
subject(:invalid_path) do
|
112
112
|
class InvalidImdbRatingMorfer < Morfo::Base
|
113
|
-
field
|
113
|
+
field(:rating).from(:very, :long, :path, :that, :might, :not, :exist)
|
114
114
|
end
|
115
115
|
InvalidImdbRatingMorfer
|
116
116
|
end
|
@@ -134,8 +134,8 @@ describe Morfo::Base do
|
|
134
134
|
context 'nested destination' do
|
135
135
|
subject do
|
136
136
|
class WrapperMorfer < Morfo::Base
|
137
|
-
field(
|
138
|
-
field(
|
137
|
+
field(:tv_show, :title).from(:title)
|
138
|
+
field(:tv_show, :channel).from(:channel).transformed {|v| "Channel: #{v}"}
|
139
139
|
end
|
140
140
|
WrapperMorfer
|
141
141
|
end
|
@@ -157,7 +157,7 @@ describe Morfo::Base do
|
|
157
157
|
context 'calculations' do
|
158
158
|
subject do
|
159
159
|
class TitlePrefixMorfer < Morfo::Base
|
160
|
-
field(:title_with_channel){|
|
160
|
+
field(:title_with_channel).calculated{|r| "#{r[:title]}, (#{r[:channel]})"}
|
161
161
|
end
|
162
162
|
TitlePrefixMorfer
|
163
163
|
end
|
@@ -175,7 +175,7 @@ describe Morfo::Base do
|
|
175
175
|
context 'static values' do
|
176
176
|
subject do
|
177
177
|
class StaticTitleMorfer < Morfo::Base
|
178
|
-
field(:new_title){ 'Static Title' }
|
178
|
+
field(:new_title).calculated{ 'Static Title' }
|
179
179
|
end
|
180
180
|
StaticTitleMorfer
|
181
181
|
end
|
metadata
CHANGED
@@ -1,63 +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.2.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-01-
|
11
|
+
date: 2014-01-16 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'
|
15
20
|
requirement: !ruby/object:Gem::Requirement
|
16
21
|
requirements:
|
17
|
-
- -
|
22
|
+
- - '>='
|
18
23
|
- !ruby/object:Gem::Version
|
19
24
|
version: '0'
|
20
|
-
type: :runtime
|
21
25
|
prerelease: false
|
26
|
+
type: :runtime
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: json
|
22
29
|
version_requirements: !ruby/object:Gem::Requirement
|
23
30
|
requirements:
|
24
|
-
- -
|
31
|
+
- - '>='
|
25
32
|
- !ruby/object:Gem::Version
|
26
33
|
version: '0'
|
27
|
-
- !ruby/object:Gem::Dependency
|
28
|
-
name: bundler
|
29
34
|
requirement: !ruby/object:Gem::Requirement
|
30
35
|
requirements:
|
31
|
-
- -
|
36
|
+
- - '>='
|
32
37
|
- !ruby/object:Gem::Version
|
33
|
-
version: '
|
34
|
-
type: :development
|
38
|
+
version: '0'
|
35
39
|
prerelease: false
|
40
|
+
type: :runtime
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: bundler
|
36
43
|
version_requirements: !ruby/object:Gem::Requirement
|
37
44
|
requirements:
|
38
|
-
- -
|
45
|
+
- - ~>
|
39
46
|
- !ruby/object:Gem::Version
|
40
47
|
version: '1.3'
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
requirements:
|
50
|
+
- - ~>
|
51
|
+
- !ruby/object:Gem::Version
|
52
|
+
version: '1.3'
|
53
|
+
prerelease: false
|
54
|
+
type: :development
|
41
55
|
- !ruby/object:Gem::Dependency
|
42
56
|
name: rspec
|
43
|
-
|
57
|
+
version_requirements: !ruby/object:Gem::Requirement
|
44
58
|
requirements:
|
45
|
-
- -
|
59
|
+
- - '>='
|
46
60
|
- !ruby/object:Gem::Version
|
47
61
|
version: '2.14'
|
48
|
-
- -
|
62
|
+
- - <
|
49
63
|
- !ruby/object:Gem::Version
|
50
64
|
version: '4.0'
|
51
|
-
|
52
|
-
prerelease: false
|
53
|
-
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirement: !ruby/object:Gem::Requirement
|
54
66
|
requirements:
|
55
|
-
- -
|
67
|
+
- - '>='
|
56
68
|
- !ruby/object:Gem::Version
|
57
69
|
version: '2.14'
|
58
|
-
- -
|
70
|
+
- - <
|
59
71
|
- !ruby/object:Gem::Version
|
60
72
|
version: '4.0'
|
73
|
+
prerelease: false
|
74
|
+
type: :development
|
61
75
|
description: This gem provides a DSL for converting one hash into another
|
62
76
|
email:
|
63
77
|
- leif@propertybase.com
|
@@ -65,9 +79,9 @@ executables: []
|
|
65
79
|
extensions: []
|
66
80
|
extra_rdoc_files: []
|
67
81
|
files:
|
68
|
-
-
|
69
|
-
-
|
70
|
-
-
|
82
|
+
- .gitignore
|
83
|
+
- .rspec
|
84
|
+
- .travis.yml
|
71
85
|
- Gemfile
|
72
86
|
- Guardfile
|
73
87
|
- LICENSE.txt
|
@@ -77,7 +91,6 @@ files:
|
|
77
91
|
- benchmarks/run.rb
|
78
92
|
- lib/morfo.rb
|
79
93
|
- lib/morfo/actions.rb
|
80
|
-
- lib/morfo/actions/base.rb
|
81
94
|
- lib/morfo/version.rb
|
82
95
|
- morfo.gemspec
|
83
96
|
- spec/lib/morfo_spec.rb
|
@@ -86,24 +99,24 @@ homepage: ''
|
|
86
99
|
licenses:
|
87
100
|
- MIT
|
88
101
|
metadata: {}
|
89
|
-
post_install_message:
|
102
|
+
post_install_message:
|
90
103
|
rdoc_options: []
|
91
104
|
require_paths:
|
92
105
|
- lib
|
93
106
|
required_ruby_version: !ruby/object:Gem::Requirement
|
94
107
|
requirements:
|
95
|
-
- -
|
108
|
+
- - '>='
|
96
109
|
- !ruby/object:Gem::Version
|
97
110
|
version: '0'
|
98
111
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
99
112
|
requirements:
|
100
|
-
- -
|
113
|
+
- - '>='
|
101
114
|
- !ruby/object:Gem::Version
|
102
115
|
version: '0'
|
103
116
|
requirements: []
|
104
|
-
rubyforge_project:
|
105
|
-
rubygems_version: 2.
|
106
|
-
signing_key:
|
117
|
+
rubyforge_project:
|
118
|
+
rubygems_version: 2.1.9
|
119
|
+
signing_key:
|
107
120
|
specification_version: 4
|
108
121
|
summary: Inspired by ActiveImporter, this gem generically converts an array of hashes
|
109
122
|
test_files:
|
data/lib/morfo/actions/base.rb
DELETED
File without changes
|