morfo 0.0.2 → 0.0.3

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: da9245950288c66e6403a6351f8de547e8e591e2
4
- data.tar.gz: 76a83cf32310c31d041c1e88894b18cd7e32cda7
3
+ metadata.gz: 435026b5435920e085878e500852cef28210364a
4
+ data.tar.gz: 358f66a812811a70b7e7d6f9791d5462a578c4a7
5
5
  SHA512:
6
- metadata.gz: a655cf8606dc55e13bad00313a421babcdb5a795580060c94157f1b3c12e23c0d0c76d60ff99ac2c4b4c4bb67bd73d5ab7b1e1932d5e623a7c9a97c0c000a0d1
7
- data.tar.gz: 7a90010c98d8b83a6d79f84718fa5c6be90a6637363ea7c8b9105dafe8aa86429a91d3b530c97510b4acd9a184cc1d772b35e057a2acb90fd27dbd89c283203d
6
+ metadata.gz: 382af73b1c1953b0660c7c255b6f1276bc295448654df87e47f9dca16a2d98743d09544e172917c22ed1034877faffc947e07324da114c6b64960dcf080cc4dc
7
+ data.tar.gz: 7fce9a8d94b8b1e4d67d27157a9a01a5211b05203f7d072bc28eb0d3c052e52730f30d08d5a600807a86efe1756a6b5b3e8b54676677203b6c34418648976f3c
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- # Morfo
1
+ # El Morfo
2
2
 
3
3
  [![Build Status](https://travis-ci.org/leifg/morfo.png?branch=master)](https://travis-ci.org/leifg/morfo) [![Coverage Status](https://coveralls.io/repos/leifg/morfo/badge.png?branch=master)](https://coveralls.io/r/leifg/morfo) [![Code Climate](https://codeclimate.com/github/leifg/morfo.png)](https://codeclimate.com/github/leifg/morfo) [![Dependency Status](https://gemnasium.com/leifg/morfo.png)](https://gemnasium.com/leifg/morfo) [![Gem Version](https://badge.fury.io/rb/morfo.png)](http://badge.fury.io/rb/morfo)
4
4
 
@@ -30,7 +30,7 @@ In order to morf the hashes you have to provide a class that extends `Morf::Base
30
30
 
31
31
  Use the `map` method to specify what field you map to another field:
32
32
 
33
- class TitleMorfer < Morfo::Base
33
+ class Title < Morfo::Base
34
34
  map :title, :tv_show_title
35
35
  end
36
36
 
@@ -46,6 +46,23 @@ Afterwards use the `morf` method to morf all hashes in one array to the end resu
46
46
  # {tv_show_title: 'Breaking Bad'},
47
47
  # ]
48
48
 
49
+ It is also possible to map fields to multiple other fields
50
+
51
+ class MultiTitle < Morfo::Base
52
+ map :title, :tv_show_title
53
+ map :title, :show_title
54
+ end
55
+
56
+ MultiTitle.morf([
57
+ {title: 'The Walking Dead'} ,
58
+ {title: 'Breaking Bad'},
59
+ ])
60
+
61
+ # [
62
+ # {tv_show_title: 'The Walking Dead', show_title: 'The Walking Dead'},
63
+ # {tv_show_title: 'Breaking Bad', show_title: 'Breaking Bad'},
64
+ # ]
65
+
49
66
  ## Transformations
50
67
 
51
68
  For each mapping you can define a block, that will be called on every input:
@@ -71,7 +88,7 @@ For each mapping you can define a block, that will be called on every input:
71
88
  You can directly access nested values in the hashes:
72
89
 
73
90
  class Name < Morfo::Base
74
- map [:name, :firs], :first_name
91
+ map [:name, :first], :first_name
75
92
  map [:name, :last], :last_name
76
93
  end
77
94
 
@@ -92,9 +109,28 @@ You can directly access nested values in the hashes:
92
109
 
93
110
  # [
94
111
  # {first_name: 'Clark',last_name: 'Kent'},
95
- # {first_name: 'Bruce',last_name: 'Wayne'},,
112
+ # {first_name: 'Bruce',last_name: 'Wayne'},
96
113
  # ]
97
114
 
115
+
116
+ It is also possible to store values in a nested hash:
117
+
118
+ class Wrapper < Morfo::Base
119
+ map :first_name, [:superhero, :name, :first]
120
+ map :last_name, [:superhero, :name, :last]
121
+ end
122
+
123
+ Name.morf([
124
+ {first_name: 'Clark',last_name: 'Kent'},
125
+ {first_name: 'Bruce',last_name: 'Wayne'},,
126
+ ])
127
+
128
+ # [
129
+ # { superhero: {name: { first: 'Clark', last: 'Kent'}}},
130
+ # { superhero: {name: { first: 'Bruce', last: 'Wayne'}}},
131
+ # ]
132
+
133
+
98
134
  ## Contributing
99
135
 
100
136
  1. Fork it
data/lib/morfo/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Morfo
2
- VERSION = '0.0.2'
2
+ VERSION = '0.0.3'
3
3
  end
data/lib/morfo.rb CHANGED
@@ -3,35 +3,71 @@ require 'morfo/version'
3
3
  module Morfo
4
4
  class Base
5
5
  def self.map from, to, &transformation
6
- mapping_actions << [from, to, transformation]
6
+ mapping_actions << MapAction.new(from, to, transformation)
7
7
  end
8
8
 
9
9
  def self.morf input
10
- input.map do |value|
11
- mapping_actions.inject({}) do |output, (from, to, transformation)|
12
- resulting_value = apply_transformation(
13
- extract_value(value, from),
14
- transformation
15
- )
16
- output.merge!(to => resulting_value) if resulting_value
17
- output
10
+ input.map do |row|
11
+ mapping_actions.inject({}) do |output, action|
12
+ deep_merge!(output, action.execute(row))
18
13
  end
19
14
  end
20
15
  end
21
16
 
22
17
  private
23
- def self.extract_value value, from
24
- Array(from).inject(value) do |resulting_value, key|
18
+ def self.mapping_actions
19
+ @actions ||= []
20
+ end
21
+
22
+ def self.deep_merge! hash, other_hash, &block
23
+ other_hash.each_pair do |k,v|
24
+ tv = hash[k]
25
+ if tv.is_a?(Hash) && v.is_a?(Hash)
26
+ hash[k] = deep_merge!(tv, v, &block)
27
+ else
28
+ hash[k] = block && tv ? block.call(k, tv, v) : v
29
+ end
30
+ end
31
+ hash
32
+ end
33
+ end
34
+
35
+ class MapAction
36
+ attr_reader :from
37
+ attr_reader :to
38
+ attr_reader :transformation
39
+
40
+ def initialize from, to, transformation
41
+ @from = from
42
+ @to = to
43
+ @transformation = transformation
44
+ end
45
+
46
+ def execute row
47
+ resulting_value = apply_transformation(extract_value(row))
48
+ resulting_value ? store_value(to, resulting_value) : {}
49
+ end
50
+
51
+ private
52
+ def extract_value row
53
+ Array(from).inject(row) do |resulting_value, key|
25
54
  resulting_value ? resulting_value[key] : nil
26
55
  end
27
56
  end
28
57
 
29
- def self.apply_transformation value, transformation
30
- transformation ? transformation.call(value) : value
58
+ def apply_transformation row
59
+ transformation ? transformation.call(row) : row
31
60
  end
32
61
 
33
- def self.mapping_actions
34
- @actions ||= []
62
+ def store_value to, value
63
+ Array(to).reverse.inject({}) do |hash, key|
64
+ if hash.keys.first.nil?
65
+ hash.merge!(key => value)
66
+ else
67
+ { key => hash }
68
+ end
69
+ end
70
+ #{ to => value }
35
71
  end
36
72
  end
37
73
  end
@@ -67,29 +67,68 @@ describe Morfo::Base do
67
67
  end
68
68
  end
69
69
 
70
- context 'nested conversion' do
71
- subject(:valid_path) do
72
- class ImdbRatingMapper < Morfo::Base
73
- map [:ratings, :imdb], :rating
70
+ context '1 to many conversion' do
71
+ subject do
72
+ class MutliTitleMapper < Morfo::Base
73
+ map :title, :title
74
+ map :title, :also_title
74
75
  end
75
- ImdbRatingMapper
76
+ MutliTitleMapper
76
77
  end
77
78
 
78
- subject(:invalid_path) do
79
- class InvalidImdbRatingMapper < Morfo::Base
80
- map [:very, :long, :path, :that, :might, :not, :exist], :rating
81
- end
82
- InvalidImdbRatingMapper
79
+ it 'maps title to multiple fields' do
80
+ expected_output = input.map{|v| {title: v[:title], also_title: v[:title]} }
81
+ expect(subject.morf(input)).to eq(expected_output)
83
82
  end
83
+ end
84
+
85
+ context 'nested conversion' do
86
+ context 'nested source' do
87
+ subject(:valid_path) do
88
+ class ImdbRatingMapper < Morfo::Base
89
+ map [:ratings, :imdb], :rating
90
+ end
91
+ ImdbRatingMapper
92
+ end
93
+
94
+ subject(:invalid_path) do
95
+ class InvalidImdbRatingMapper < Morfo::Base
96
+ map [:very, :long, :path, :that, :might, :not, :exist], :rating
97
+ end
98
+ InvalidImdbRatingMapper
99
+ end
84
100
 
85
- it 'maps nested attributes' do
86
- expected_output = input.map{|v| {rating: v[:ratings][:imdb]} }
87
- expect(valid_path.morf(input)).to eq(expected_output)
101
+ it 'maps nested attributes' do
102
+ expected_output = input.map{|v| {rating: v[:ratings][:imdb]} }
103
+ expect(valid_path.morf(input)).to eq(expected_output)
104
+ end
105
+
106
+ it 'doesn\'t raise error for invalid path' do
107
+ expected_output = [{},{}]
108
+ expect(invalid_path.morf(input)).to eq(expected_output)
109
+ end
88
110
  end
89
111
 
90
- it 'doesn\'t raise error for invalid path' do
91
- expected_output = [{},{}]
92
- expect(invalid_path.morf(input)).to eq(expected_output)
112
+ context 'nested destination' do
113
+ subject do
114
+ class WrapperMapper < Morfo::Base
115
+ map :title, [:tv_show, :title]
116
+ map :channel, [:tv_show, :channel]
117
+ end
118
+ WrapperMapper
119
+ end
120
+
121
+ it 'maps to nested destination' do
122
+ expected_output = input.map{|v|
123
+ {
124
+ tv_show: {
125
+ title: v[:title],
126
+ channel: v[:channel],
127
+ }
128
+ }
129
+ }
130
+ expect(subject.morf(input)).to eq(expected_output)
131
+ end
93
132
  end
94
133
  end
95
134
  end
metadata CHANGED
@@ -1,61 +1,61 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: morfo
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 0.0.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Leif Gensert
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2013-12-20 00:00:00.000000000 Z
11
+ date: 2014-01-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - '>='
17
+ - - ">="
18
18
  - !ruby/object:Gem::Version
19
19
  version: '0'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - '>='
24
+ - - ">="
25
25
  - !ruby/object:Gem::Version
26
26
  version: '0'
27
27
  - !ruby/object:Gem::Dependency
28
28
  name: bundler
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - ~>
31
+ - - "~>"
32
32
  - !ruby/object:Gem::Version
33
33
  version: '1.3'
34
34
  type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
- - - ~>
38
+ - - "~>"
39
39
  - !ruby/object:Gem::Version
40
40
  version: '1.3'
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: rspec
43
43
  requirement: !ruby/object:Gem::Requirement
44
44
  requirements:
45
- - - '>='
45
+ - - ">="
46
46
  - !ruby/object:Gem::Version
47
47
  version: '2.14'
48
- - - <
48
+ - - "<"
49
49
  - !ruby/object:Gem::Version
50
50
  version: '4.0'
51
51
  type: :development
52
52
  prerelease: false
53
53
  version_requirements: !ruby/object:Gem::Requirement
54
54
  requirements:
55
- - - '>='
55
+ - - ">="
56
56
  - !ruby/object:Gem::Version
57
57
  version: '2.14'
58
- - - <
58
+ - - "<"
59
59
  - !ruby/object:Gem::Version
60
60
  version: '4.0'
61
61
  description: This gem provides a DSL for converting one hash into another
@@ -65,9 +65,9 @@ executables: []
65
65
  extensions: []
66
66
  extra_rdoc_files: []
67
67
  files:
68
- - .gitignore
69
- - .rspec
70
- - .travis.yml
68
+ - ".gitignore"
69
+ - ".rspec"
70
+ - ".travis.yml"
71
71
  - Gemfile
72
72
  - Guardfile
73
73
  - LICENSE.txt
@@ -88,17 +88,17 @@ require_paths:
88
88
  - lib
89
89
  required_ruby_version: !ruby/object:Gem::Requirement
90
90
  requirements:
91
- - - '>='
91
+ - - ">="
92
92
  - !ruby/object:Gem::Version
93
93
  version: '0'
94
94
  required_rubygems_version: !ruby/object:Gem::Requirement
95
95
  requirements:
96
- - - '>='
96
+ - - ">="
97
97
  - !ruby/object:Gem::Version
98
98
  version: '0'
99
99
  requirements: []
100
100
  rubyforge_project:
101
- rubygems_version: 2.0.14
101
+ rubygems_version: 2.2.0
102
102
  signing_key:
103
103
  specification_version: 4
104
104
  summary: Inspired by ActiveImporter, this gem generically converts an array of hashes