morfo 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 7bb20ae90a7b011588d8e096694b69fab5664684
4
- data.tar.gz: 00b3eb367ac96a797105118974ca2562a35d4163
3
+ metadata.gz: 69e889d25298c9a89daa889b8f7f406e5849aace
4
+ data.tar.gz: 84167fea094d1c085e0c6328f44dcf7e174557b4
5
5
  SHA512:
6
- metadata.gz: c84f9323b71740ee3056033a25974a7daefedd3e29e92b40138bf5591e1b3a186349527d4cf13865c8a91bcbd260f01587857917dae74eca157351250de3f321
7
- data.tar.gz: d052cce267ede1514bb6bb70c2db3eabbc3c4f01273d337c95b399986a683f0516ea2175fc43b0ad6fbf9003a1789fc62054ac498d6cc5747a886c564985db9e
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
- - jruby-1.7.9
6
+ - 2.1.0
7
+ - jruby-1.7.10
7
8
  - ruby-head
8
9
  - jruby-head
9
- - rbx-2.2.1
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.1
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, just define another field from the input hash. The value will just be copied.
33
+ The most basic form is copying the value from another field.
34
34
 
35
35
  class Title < Morfo::Base
36
- field :tv_show_title, from: :title
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, you'll have to provide an array as the key:
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 :first_name, from: [:name, :first]
56
- field :last_name, from: [:name, :last]
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
- Every field can also take a transformation block, so that the original input can be transformed.
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, from: :title) {|title| "#{title} and Zombies"}
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
- As the second argument, the whole row is passed into the block. So you can even do transformation based on the whole row. Or you can leave out all the arguments and return a static value.
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) {|_, row| "#{row[:first_name]} #{row[:last_name]}"}
101
- field(:status) { 'Best Friend' }
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
- module ValueMethods
4
- def extract_value from, row
5
- Array(from).inject(row) do |resulting_value, key|
6
- resulting_value ? resulting_value[key] : nil
7
- end
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 store_value to, value
11
- return {} if value.nil?
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
- Array(to).reverse.inject({}) do |hash, key|
14
- if hash.keys.first.nil?
15
- hash.merge!(key => value)
16
- else
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
- class MapAction
24
- include ValueMethods
25
- attr_reader :from
26
- attr_reader :to
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
- def initialize from, to
29
- @from = from
30
- @to = to
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
- store_value(to, extract_value(from, row))
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 TransformationAction
39
- include ValueMethods
40
- attr_reader :to
41
- attr_reader :from
42
- attr_reader :transformation
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 initialize from, to, transformation
45
- @from = from
46
- @to = to
47
- @transformation = transformation
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
- resulting_value = from ? extract_value(from, row) : nil
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
@@ -1,3 +1,3 @@
1
1
  module Morfo
2
- VERSION = '0.1.0'
2
+ VERSION = '0.2.0'
3
3
  end
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 field_name, definition={}, &blk
7
- if blk
8
- mapping_actions << Morfo::Actions::TransformationAction.new(definition[:from], field_name, blk)
9
- else
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 do |row|
20
- mapping_actions.inject({}) do |output, action|
21
- deep_merge!(output, action.execute(row))
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
- end
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'
@@ -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 :my_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 :tv_show_title, from: :title
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, from: :cast){|v,r| v.size}
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 :title, from: :title
84
- field :also_title, from: :title
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 :rating, from: [:ratings, :imdb]
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 ImdbRatingMorfer < Morfo::Base
106
- field(:rating, from: [:ratings, :imdb]){|v| "Rating: #{v}"}
105
+ class ImdbRatingMorferWithTransformation < Morfo::Base
106
+ field(:rating).from(:ratings, :imdb).transformed {|v| "Rating: #{v}"}
107
107
  end
108
- ImdbRatingMorfer
108
+ ImdbRatingMorferWithTransformation
109
109
  end
110
110
 
111
111
  subject(:invalid_path) do
112
112
  class InvalidImdbRatingMorfer < Morfo::Base
113
- field :rating, from: [:very, :long, :path, :that, :might, :not, :exist]
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([:tv_show, :title], from: :title)
138
- field([:tv_show, :channel], from: :channel){|v| "Channel: #{v}"}
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){|v,r| "#{r[:title]}, (#{r[: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.1.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-13 00:00:00.000000000 Z
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: '1.3'
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
- requirement: !ruby/object:Gem::Requirement
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
- type: :development
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
- - ".gitignore"
69
- - ".rspec"
70
- - ".travis.yml"
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.2.0
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:
File without changes