morfo 0.0.2 → 0.0.3

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 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