morfo 0.3.0 → 0.4.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 3500e5ec94def95ffed72498a8dcfee478e10e80
4
- data.tar.gz: b543a2e81a8032f6bc5736b42761dbb08b822ab7
3
+ metadata.gz: 87b740fa3940052dc425842ec2f8a8c1b39a8955
4
+ data.tar.gz: ce6d9032e4b76325233bcad0e4ed2a29dba17c15
5
5
  SHA512:
6
- metadata.gz: 7a373305e8dfd3add0b3070c66e1d357dde9b453746942f3b03afaa3c68b99e5124dac54147e499cf08c05c8489e79f8cbfa3538c5f36164213cb592f077f8e1
7
- data.tar.gz: 5cde3c3dd8d6082817b1976c070e673045d9b1ff496b45c36330311888747910dc62de4ef1bb92a77d27154d99e4658b77cd04dbda9e1289ac04fae72057ae63
6
+ metadata.gz: f0baa0e37cf6809e502bed94eb4da771d3572b51970918d9666d1ea4bdcc2c9872b046f78df3f2035727da35a33affbe3daa3c51c9d050864c61cd6361580aa8
7
+ data.tar.gz: e1e50f08391db40f95d7ecb81908c19e9e3774d996ca0fa0da757e1f7cd4a1f3c582bbc34cdb0b86ca2ab3dcc840f9b715f24aafb37c05a7bc3f6dd4a395196e
@@ -2,6 +2,6 @@
2
2
 
3
3
  1. Fork it
4
4
  2. Create your feature branch (`git checkout -b my-new-feature`)
5
- 3. Commit your changes (`git commit -am 'Add some feature'`)
5
+ 3. Commit your changes (`git commit -am "Add some feature"`)
6
6
  4. Push to the branch (`git push origin my-new-feature`)
7
7
  5. Create new Pull Request
data/Gemfile CHANGED
@@ -1,19 +1,19 @@
1
- source 'https://rubygems.org'
1
+ source "https://rubygems.org"
2
2
 
3
3
  # Specify your gem's dependencies in morfo.gemspec
4
4
  gemspec
5
5
 
6
6
  group :test, :development do
7
- gem 'coveralls', require: false
8
- gem 'guard'
9
- gem 'guard-rspec'
10
- gem 'simplecov'
11
- gem 'pry'
12
- gem 'rubinius-coverage', platform: :rbx
7
+ gem "coveralls", require: false
8
+ gem "guard"
9
+ gem "guard-rspec"
10
+ gem "simplecov"
11
+ gem "pry"
12
+ gem "rubinius-coverage", platform: :rbx
13
13
 
14
- gem 'rb-inotify', require: false
15
- gem 'rb-fsevent', require: false
16
- gem 'rb-fchange', require: false
14
+ gem "rb-inotify", require: false
15
+ gem "rb-fsevent", require: false
16
+ gem "rb-fchange", require: false
17
17
  end
18
18
 
19
- gem 'json'
19
+ gem "json"
data/Guardfile CHANGED
@@ -1,8 +1,8 @@
1
1
  # A sample Guardfile
2
2
  # More info at https://github.com/guard/guard#readme
3
3
 
4
- guard :rspec, cmd: 'bundle exec 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
- watch('spec/spec_helper.rb') { 'spec' }
7
+ watch("spec/spec_helper.rb") { "spec" }
8
8
  end
data/README.md CHANGED
@@ -12,7 +12,7 @@ This gem is currently only tested on Ruby 2.0 (including 2.0 mode of JRuby and R
12
12
 
13
13
  Add this line to your application's Gemfile:
14
14
 
15
- gem 'morfo'
15
+ gem "morfo"
16
16
 
17
17
  And then execute:
18
18
 
@@ -32,83 +32,199 @@ Use the `field` method to specify what fields exist and where they will get thei
32
32
 
33
33
  The most basic form is copying the value from another field.
34
34
 
35
- class Title < Morfo::Base
36
- field(:tv_show_title)from(:title)
37
- end
35
+ ```ruby
36
+ class Title < Morfo::Base
37
+ field(:tv_show_title)from(:title)
38
+ end
39
+ ```
38
40
 
39
41
  Afterwards use the `morf` method to morf all hashes in one array to the end result:
40
42
 
41
- Title.morf([
42
- {title: 'The Walking Dead'} ,
43
- {title: 'Breaking Bad'},
44
- ])
43
+ ```ruby
44
+ Title.morf([
45
+ { title: "The Walking Dead" },
46
+ { title: "Breaking Bad" },
47
+ ])
45
48
 
46
- # [
47
- # {tv_show_title: 'The Walking Dead'},
48
- # {tv_show_title: 'Breaking Bad'},
49
- # ]
49
+ # [
50
+ # { tv_show_title: "The Walking Dead" },
51
+ # { tv_show_title: "Breaking Bad" },
52
+ # ]
53
+ ```
50
54
 
51
55
  If you want to have access to nested values, just provide the path to that field comma separated.
52
56
 
53
-
54
- class Name < Morfo::Base
55
- field(:first_name).from(:name, :first)
56
- field(:last_name).from(:name, :last)
57
- end
58
-
59
- Name.morf([
60
- {
61
- name: {
62
- first: 'Clark',
63
- last: 'Kent',
64
- },
65
- },
66
- {
67
- name: {
68
- first: 'Bruce',
69
- last: 'Wayne',
70
- },
71
- },
72
- ])
73
-
74
- # [
75
- # {first_name: 'Clark',last_name: 'Kent'},
76
- # {first_name: 'Bruce',last_name: 'Wayne'},
77
- # ]
78
-
79
- ## Transformations
57
+ ```ruby
58
+ class Name < Morfo::Base
59
+ field(:first_name).from(:name, :first)
60
+ field(:last_name).from(:name, :last)
61
+ end
62
+
63
+ Name.morf([
64
+ {
65
+ name: {
66
+ first: "Clark",
67
+ last: "Kent",
68
+ },
69
+ },
70
+ {
71
+ name: {
72
+ first: "Bruce",
73
+ last: "Wayne",
74
+ },
75
+ },
76
+ ])
77
+
78
+ # [
79
+ # { first_name: "Clark", last_name: "Kent" },
80
+ # { first_name: "Bruce", last_name: "Wayne" },
81
+ # ]
82
+ ```
83
+
84
+ ### Transformations
80
85
 
81
86
  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
87
 
83
- class AndZombies < Morfo::Base
84
- field(:title).from(title).transformed {|title| "#{title} and Zombies"}
85
- end
88
+ ```ruby
89
+ class AndZombies < Morfo::Base
90
+ field(:title).from(title).transformed {|title| "#{title} and Zombies"}
91
+ end
86
92
 
87
- AndZombies.morf([
88
- {title: 'Pride and Prejudice'},
89
- {title: 'Fifty Shades of Grey'},
90
- ])
93
+ AndZombies.morf([
94
+ { title: "Pride and Prejudice" },
95
+ { title: "Fifty Shades of Grey" },
96
+ ])
91
97
 
92
- # [
93
- # {title: 'Pride and Prejudice and Zombies'},
94
- # {title: 'Fifty Shades of Grey and Zombies'},
95
- # ]
98
+ # [
99
+ # { title: "Pride and Prejudice and Zombies" },
100
+ # { title: "Fifty Shades of Grey and Zombies" },
101
+ # ]
102
+ ```
96
103
 
97
- ## Calculations
104
+ ### Calculations
98
105
 
99
106
  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.
100
107
 
101
- class NameConcatenator < Morfo::Base
102
- field(:name).calculated {|row| "#{row[:first_name]} #{row[:last_name]}"}
103
- field(:status).calculated {'Best Friend'}
104
- end
105
-
106
- NameConcatenator.morf([
107
- {first_name: 'Robin', last_name: 'Hood'},
108
- {first_name: 'Sherlock', last_name: 'Holmes'},
109
- ])
108
+ ```ruby
109
+ class NameConcatenator < Morfo::Base
110
+ field(:name).calculated {|row| "#{row[:first_name]} #{row[:last_name]}"}
111
+ field(:status).calculated {"Best Friend"}
112
+ end
113
+
114
+ NameConcatenator.morf([
115
+ { first_name: "Robin", last_name: "Hood" },
116
+ { first_name: "Sherlock", last_name: "Holmes" },
117
+ ])
118
+
119
+ # [
120
+ # { name: "Robin Hood", status: "Best Friend" },
121
+ # { name: "Sherlock Holmes", status: "Best Friend" }
122
+ # ]
123
+ ```
124
+
125
+ ### Builder
126
+
127
+ On top of creating transformers with Ruby classes, it is also possible to build transformers with a hash syntax (which could then be serialized as json and stored somewhere else).
128
+
129
+ ```ruby
130
+ morfer = Morfo::Builder.new([
131
+ { field: :first_name, from: [:name, :first] },
132
+ { field: :last_name, from: [:name, :last] },
133
+ ])
134
+
135
+ morfer.morf([
136
+ {
137
+ name: {
138
+ first: "Clark",
139
+ last: "Kent",
140
+ },
141
+ },
142
+ {
143
+ name: {
144
+ first: "Bruce",
145
+ last: "Wayne",
146
+ },
147
+ },
148
+ ])
149
+
150
+ # [
151
+ # { first_name: "Clark", last_name: "Kent" },
152
+ # { first_name: "Bruce", last_name: "Wayne" },
153
+ # ]
154
+ ```
155
+
156
+ The builder includes all other features such as calculation and transformation
157
+
158
+ #### Builder Transformations
159
+
160
+ To transform a value, use the placeholder %{value}
161
+
162
+ ```ruby
163
+ class AndZombies < Morfo::Base
164
+ field(:title).from(title).transformed {|title| "#{title} and Zombies"}
165
+ end
166
+
167
+ morfer = Morfo::Builder.new([
168
+ { field: :title, from: :title, transformed: "%{title} and Zombies" },
169
+ ])
170
+
171
+ morfer.morf([
172
+ { title: "Pride and Prejudice" },
173
+ { title: "Fifty Shades of Grey" },
174
+ ])
175
+
176
+ # [
177
+ # { title: "Pride and Prejudice and Zombies" },
178
+ # { title: "Fifty Shades of Grey and Zombies" },
179
+ # ]
180
+ ```
181
+
182
+ #### Builder Calculations
183
+
184
+ To get access to the other fields use the [ruby string format syntax](http://ruby-doc.org/core-2.2.0/String.html#method-i-25).
185
+
186
+ ```ruby
187
+ morfer = Morfo::Builder.new([
188
+ { field: :name, calculated: "%{first_name} %{last_name}" },
189
+ { field: :status, calculated: "Best Friend" },
190
+ ])
191
+
192
+ morfer.morf([
193
+ { first_name: "Robin", last_name: "Hood" },
194
+ { first_name: "Sherlock", last_name: "Holmes" },
195
+ ])
196
+
197
+ # [
198
+ # { name: "Robin Hood", status: "Best Friend" },
199
+ # { name: "Sherlock Holmes", status: "Best Friend" }
200
+ # ]
201
+ ```
202
+
203
+ It's even possible to get access to nested keys, using a dot as separator:
204
+
205
+ ```ruby
206
+ morfer = Morfo::Builder.new([
207
+ { field: :name, calculated: "%{name.first} %{name.last}" },
208
+ ])
209
+
210
+ morfer.morf([
211
+ {
212
+ name: {
213
+ first: "Clark",
214
+ last: "Kent",
215
+ },
216
+ },
217
+ {
218
+ name: {
219
+ first: "Bruce",
220
+ last: "Wayne",
221
+ },
222
+ },
223
+ ])
224
+
225
+ # [
226
+ # { name: "Clark Kent" },
227
+ # { name: "Bruce Wayne" },
228
+ # ]
229
+ ```
110
230
 
111
- # [
112
- # {:name=>"Robin Hood", :status=>"Best Friend"},
113
- # {:name=>"Sherlock Holmes", :status=>'Best Friend'}
114
- # ]
data/Rakefile CHANGED
@@ -1,4 +1,4 @@
1
- require 'bundler/gem_tasks'
2
- require 'rspec/core/rake_task'
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
3
 
4
4
  RSpec::Core::RakeTask.new(:spec)
@@ -7,16 +7,16 @@ module BenchmarkData
7
7
 
8
8
  def row
9
9
  {
10
- first_name: 'Jazmyn',
11
- last_name: 'Willms',
12
- gender: 'female',
13
- phone_number: '485-675-9228',
14
- cell_phone: '1-172-435-9402 x4907',
15
- street_name: 'Becker Inlet',
16
- street_number: '15a',
17
- city: 'Carolynchester',
18
- zip: '38189',
19
- country: 'USA',
10
+ first_name: "Jazmyn",
11
+ last_name: "Willms",
12
+ gender: "female",
13
+ phone_number: "485-675-9228",
14
+ cell_phone: "1-172-435-9402 x4907",
15
+ street_name: "Becker Inlet",
16
+ street_number: "15a",
17
+ city: "Carolynchester",
18
+ zip: "38189",
19
+ country: "USA",
20
20
  }
21
21
  end
22
22
 
@@ -1,28 +1,28 @@
1
- require 'morfo'
2
- require 'benchmark'
3
- require './benchmarks/data'
1
+ require "morfo"
2
+ require "benchmark"
3
+ require "./benchmarks/data"
4
4
 
5
5
  iterations = 100
6
6
  batch_size = 10000
7
7
 
8
8
  definitions = [
9
9
  {
10
- label: 'Simple (strings)',
10
+ label: "Simple (strings)",
11
11
  row: BenchmarkData.row_string_keys,
12
12
  morf_class: BenchmarkData::SimpleMorferString
13
13
  },
14
14
  {
15
- label: 'Simple (symbols)',
15
+ label: "Simple (symbols)",
16
16
  row: BenchmarkData.row,
17
17
  morf_class: BenchmarkData::SimpleMorferSymbol
18
18
  },
19
19
  {
20
- label: 'Nested (strings)',
20
+ label: "Nested (strings)",
21
21
  row: BenchmarkData.row_nested_string_keys,
22
22
  morf_class: BenchmarkData::NestedMorferString
23
23
  },
24
24
  {
25
- label: 'Nested (symbols)',
25
+ label: "Nested (symbols)",
26
26
  row: BenchmarkData.row_nested,
27
27
  morf_class: BenchmarkData::NestedMorferSymbol
28
28
  },
@@ -1,5 +1,8 @@
1
- require 'morfo/version'
2
- require 'morfo/actions'
1
+ require "active_support/core_ext/hash"
2
+ require "morfo/version"
3
+ require "morfo/tools"
4
+ require "morfo/actions"
5
+ require "morfo/builder"
3
6
 
4
7
  module Morfo
5
8
  class Base
@@ -16,7 +19,7 @@ module Morfo
16
19
  def self.morf_single input
17
20
  output = {}
18
21
  mapping_actions.each do |field_path, action|
19
- deep_merge!(output, store_value(action.execute(input), field_path))
22
+ output.deep_merge!(store_value(action.execute(input), field_path))
20
23
  end
21
24
  output
22
25
  end
@@ -37,17 +40,5 @@ module Morfo
37
40
  end
38
41
  end
39
42
  end
40
-
41
- def self.deep_merge! hash, other_hash, &block
42
- other_hash.each_pair do |k,v|
43
- tv = hash[k]
44
- if tv.is_a?(Hash) && v.is_a?(Hash)
45
- hash[k] = deep_merge!(tv, v, &block)
46
- else
47
- hash[k] = block && tv ? block.call(k, tv, v) : v
48
- end
49
- end
50
- hash
51
- end
52
43
  end
53
44
  end
@@ -0,0 +1,34 @@
1
+ module Morfo
2
+ class Builder
3
+ def initialize(definitions)
4
+ @definitions = definitions
5
+ end
6
+
7
+ def build
8
+ # WTF??? `definitions` is not accessible inside class
9
+ # so this javascript technique is necesseray
10
+ tmp_definitions = definitions.map { |h| h.symbolize_keys }
11
+ Class.new(Morfo::Base) do
12
+ tmp_definitions.each do |definition|
13
+ f = field(*definition[:field])
14
+
15
+ if definition[:from]
16
+ f = f.from(*definition[:from])
17
+ end
18
+
19
+ if definition[:calculated]
20
+ f = f.calculated { |r| definition[:calculated] % Morfo::Tools::FlattenHashKeys.new(r).flatten }
21
+ end
22
+
23
+ if definition[:transformed]
24
+ f = f.transformed { |v| definition[:transformed] % {value: v} }
25
+ end
26
+ end
27
+ end
28
+ end
29
+
30
+ private
31
+
32
+ attr_reader :definitions
33
+ end
34
+ end