morfo 0.3.0 → 0.4.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: 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