hash_mapper 0.0.8 → 0.0.9
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.
- data/README.rdoc +9 -8
- data/Rakefile +22 -28
- data/VERSION +1 -0
- data/hash_mapper.gemspec +54 -0
- data/lib/hash_mapper.rb +59 -36
- data/spec/hash_mapper_spec.rb +0 -2
- metadata +15 -39
data/README.rdoc
CHANGED
@@ -123,6 +123,15 @@ Just use the denormalize() method instead:
|
|
123
123
|
This will work with your block filters and even nested mappers (see below).
|
124
124
|
|
125
125
|
=== Advanced usage
|
126
|
+
==== Array access
|
127
|
+
You want:
|
128
|
+
|
129
|
+
{:names => ['Ismael', 'Celis']} converted to {:first_name => 'Ismael', :last_name => 'Celis'}
|
130
|
+
|
131
|
+
Do this:
|
132
|
+
|
133
|
+
map from('/names[0]'), to('/first_name')
|
134
|
+
map from('/names[1]'), to('/last_name')
|
126
135
|
==== Nested mappers
|
127
136
|
|
128
137
|
You want to map nested structures delegating to different mappers:
|
@@ -209,15 +218,7 @@ Note also that 'output' is correct at the time of the filter, i.e. before_normal
|
|
209
218
|
== REQUIREMENTS:
|
210
219
|
|
211
220
|
== TODO:
|
212
|
-
==== Array access
|
213
|
-
You want:
|
214
|
-
|
215
|
-
{:names => ['Ismael', 'Celis']} converted to {:first_name => 'Ismael', :last_name => 'Celis'}
|
216
221
|
|
217
|
-
Do this:
|
218
|
-
|
219
|
-
map from('/names[0]'), to('/first_name')
|
220
|
-
map from('/names[1]'), to('/last_name')
|
221
222
|
|
222
223
|
==== Optimizations
|
223
224
|
|
data/Rakefile
CHANGED
@@ -1,28 +1,22 @@
|
|
1
|
-
|
2
|
-
require File.dirname(__FILE__) + '/lib/hash_mapper'
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
end
|
23
|
-
|
24
|
-
require 'newgem/tasks' # load /tasks/*.rake
|
25
|
-
Dir['tasks/**/*.rake'].each { |t| load t }
|
26
|
-
|
27
|
-
# TODO - want other tests/tasks run by default? Add them to the list
|
28
|
-
task :default => [:spec]
|
1
|
+
require 'rubygems'
|
2
|
+
require File.dirname(__FILE__) + '/lib/hash_mapper'
|
3
|
+
|
4
|
+
Dir['tasks/**/*.rake'].each { |t| load t }
|
5
|
+
|
6
|
+
# TODO - want other tests/tasks run by default? Add them to the list
|
7
|
+
task :default => [:spec]
|
8
|
+
|
9
|
+
|
10
|
+
begin
|
11
|
+
require 'jeweler'
|
12
|
+
Jeweler::Tasks.new do |gemspec|
|
13
|
+
gemspec.name = "hash_mapper"
|
14
|
+
gemspec.summary = "Maps values from hashes with different structures and/or key names. Ideal for normalizing arbitrary data to be consumed by your applications, or to prepare your data for different display formats (ie. json)"
|
15
|
+
gemspec.description = "Tiny module that allows you to easily adapt from one hash structure to another with a simple declarative DSL."
|
16
|
+
gemspec.email = "ismaelct@gmail.com"
|
17
|
+
gemspec.homepage = "http://github.com/ismasan/hash_mapper"
|
18
|
+
gemspec.authors = ["Ismael Celis"]
|
19
|
+
end
|
20
|
+
rescue LoadError
|
21
|
+
puts "Jeweler not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
|
22
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.0.9
|
data/hash_mapper.gemspec
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run `rake gemspec`
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = %q{hash_mapper}
|
8
|
+
s.version = "0.0.9"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = ["Ismael Celis"]
|
12
|
+
s.date = %q{2009-10-29}
|
13
|
+
s.description = %q{Tiny module that allows you to easily adapt from one hash structure to another with a simple declarative DSL.}
|
14
|
+
s.email = %q{ismaelct@gmail.com}
|
15
|
+
s.extra_rdoc_files = [
|
16
|
+
"README.rdoc"
|
17
|
+
]
|
18
|
+
s.files = [
|
19
|
+
"History.txt",
|
20
|
+
"Manifest.txt",
|
21
|
+
"PostInstall.txt",
|
22
|
+
"README.rdoc",
|
23
|
+
"Rakefile",
|
24
|
+
"VERSION",
|
25
|
+
"hash_mapper.gemspec",
|
26
|
+
"lib/hash_mapper.rb",
|
27
|
+
"script/console",
|
28
|
+
"script/destroy",
|
29
|
+
"script/generate",
|
30
|
+
"spec/hash_mapper_spec.rb",
|
31
|
+
"spec/spec.opts",
|
32
|
+
"spec/spec_helper.rb",
|
33
|
+
"tasks/rspec.rake"
|
34
|
+
]
|
35
|
+
s.homepage = %q{http://github.com/ismasan/hash_mapper}
|
36
|
+
s.rdoc_options = ["--charset=UTF-8"]
|
37
|
+
s.require_paths = ["lib"]
|
38
|
+
s.rubygems_version = %q{1.3.5}
|
39
|
+
s.summary = %q{Maps values from hashes with different structures and/or key names. Ideal for normalizing arbitrary data to be consumed by your applications, or to prepare your data for different display formats (ie. json)}
|
40
|
+
s.test_files = [
|
41
|
+
"spec/hash_mapper_spec.rb",
|
42
|
+
"spec/spec_helper.rb"
|
43
|
+
]
|
44
|
+
|
45
|
+
if s.respond_to? :specification_version then
|
46
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
47
|
+
s.specification_version = 3
|
48
|
+
|
49
|
+
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
50
|
+
else
|
51
|
+
end
|
52
|
+
else
|
53
|
+
end
|
54
|
+
end
|
data/lib/hash_mapper.rb
CHANGED
@@ -40,8 +40,7 @@ unless Array.instance_methods.include?("inject_with_index")
|
|
40
40
|
end
|
41
41
|
|
42
42
|
module HashMapper
|
43
|
-
|
44
|
-
|
43
|
+
|
45
44
|
# we need this for inheritable mappers, which is annoying because it needs ActiveSupport, kinda overkill.
|
46
45
|
#
|
47
46
|
def self.extended(base)
|
@@ -50,24 +49,24 @@ module HashMapper
|
|
50
49
|
class_inheritable_accessor :maps
|
51
50
|
end
|
52
51
|
end
|
53
|
-
|
52
|
+
|
54
53
|
def map(from, to, using=nil, &filter)
|
55
54
|
self.maps << Map.new(from, to, using)
|
56
55
|
to.filter = filter if block_given? # Useful if just one block given
|
57
56
|
end
|
58
|
-
|
57
|
+
|
59
58
|
def from(path, &filter)
|
60
59
|
path_map = PathMap.new(path)
|
61
60
|
path_map.filter = filter if block_given? # Useful if two blocks given
|
62
61
|
path_map
|
63
62
|
end
|
64
|
-
|
63
|
+
|
65
64
|
alias :to :from
|
66
|
-
|
65
|
+
|
67
66
|
def using(mapper_class)
|
68
67
|
mapper_class
|
69
68
|
end
|
70
|
-
|
69
|
+
|
71
70
|
def normalize(a_hash)
|
72
71
|
perform_hash_mapping a_hash, :normalize
|
73
72
|
end
|
@@ -75,7 +74,7 @@ module HashMapper
|
|
75
74
|
def denormalize(a_hash)
|
76
75
|
perform_hash_mapping a_hash, :denormalize
|
77
76
|
end
|
78
|
-
|
77
|
+
|
79
78
|
def before_normalize(&blk)
|
80
79
|
@before_normalize = blk
|
81
80
|
end
|
@@ -91,10 +90,10 @@ module HashMapper
|
|
91
90
|
def after_denormalize(&blk)
|
92
91
|
@after_denormalize = blk
|
93
92
|
end
|
94
|
-
|
93
|
+
|
95
94
|
protected
|
96
95
|
|
97
|
-
|
96
|
+
|
98
97
|
def perform_hash_mapping(a_hash, meth)
|
99
98
|
output = {}
|
100
99
|
# Before filter
|
@@ -110,18 +109,18 @@ module HashMapper
|
|
110
109
|
# Return
|
111
110
|
output
|
112
111
|
end
|
113
|
-
|
112
|
+
|
114
113
|
# Contains PathMaps
|
115
114
|
# Makes them interact
|
116
115
|
#
|
117
116
|
class Map
|
118
|
-
|
117
|
+
|
119
118
|
attr_reader :path_from, :path_to, :delegated_mapper
|
120
|
-
|
119
|
+
|
121
120
|
def initialize(path_from, path_to, delegated_mapper = nil)
|
122
121
|
@path_from, @path_to, @delegated_mapper = path_from, path_to, delegated_mapper
|
123
122
|
end
|
124
|
-
|
123
|
+
|
125
124
|
def process_into(output, input, meth = :normalize)
|
126
125
|
path_1, path_2 = (meth == :normalize ? [path_from, path_to] : [path_to, path_from])
|
127
126
|
catch :no_value do
|
@@ -129,19 +128,22 @@ module HashMapper
|
|
129
128
|
add_value_to_hash!(output, path_2, value)
|
130
129
|
end
|
131
130
|
end
|
132
|
-
|
133
131
|
protected
|
134
|
-
|
132
|
+
|
135
133
|
def get_value_from_input(output, input, path, meth)
|
136
134
|
value = path.inject(input) do |h,e|
|
137
|
-
|
135
|
+
if h.respond_to?(:with_indifferent_access)# this does it, but uses ActiveSupport
|
136
|
+
v = h.with_indifferent_access[e]
|
137
|
+
else
|
138
|
+
v = h[e]
|
139
|
+
end
|
138
140
|
throw :no_value if v.nil?#.has_key?(e)
|
139
141
|
v
|
140
142
|
end
|
141
143
|
delegated_mapper ? delegate_to_nested_mapper(value, meth) : value
|
142
144
|
end
|
143
|
-
|
144
|
-
|
145
|
+
|
146
|
+
|
145
147
|
def delegate_to_nested_mapper(value, meth)
|
146
148
|
case value
|
147
149
|
when Array
|
@@ -152,60 +154,81 @@ module HashMapper
|
|
152
154
|
delegated_mapper.send(meth, value)
|
153
155
|
end
|
154
156
|
end
|
155
|
-
|
157
|
+
|
156
158
|
def add_value_to_hash!(hash, path, value)
|
157
159
|
path.inject_with_index(hash) do |h,e,i|
|
158
160
|
if !h[e].nil? # it can be FALSE
|
159
161
|
h[e]
|
160
162
|
else
|
161
|
-
h[e] =
|
163
|
+
h[e] = if i == path.size-1
|
164
|
+
path.apply_filter(value)
|
165
|
+
else
|
166
|
+
if path.segments[i+1].is_a? Integer
|
167
|
+
[]
|
168
|
+
else
|
169
|
+
{}
|
170
|
+
end
|
171
|
+
end
|
162
172
|
end
|
163
173
|
end
|
164
|
-
|
174
|
+
|
165
175
|
end
|
166
|
-
|
176
|
+
|
167
177
|
end
|
168
|
-
|
178
|
+
|
169
179
|
# contains array of path segments
|
170
180
|
#
|
171
181
|
class PathMap
|
172
182
|
include Enumerable
|
173
|
-
|
183
|
+
|
174
184
|
attr_reader :segments
|
175
185
|
attr_writer :filter
|
176
|
-
|
186
|
+
attr_reader :path
|
187
|
+
|
177
188
|
def initialize(path)
|
178
189
|
@path = path.dup
|
179
190
|
@segments = parse(path)
|
180
191
|
@filter = lambda{|value| value}# default filter does nothing
|
181
192
|
end
|
182
|
-
|
193
|
+
|
183
194
|
def apply_filter(value)
|
184
195
|
@filter.call(value)
|
185
196
|
end
|
186
|
-
|
197
|
+
|
187
198
|
def each(&blk)
|
188
199
|
@segments.each(&blk)
|
189
200
|
end
|
190
|
-
|
201
|
+
|
191
202
|
def first
|
192
203
|
@segments.first
|
193
204
|
end
|
194
|
-
|
205
|
+
|
195
206
|
def last
|
196
207
|
@segments.last
|
197
208
|
end
|
198
|
-
|
209
|
+
|
199
210
|
def size
|
200
211
|
@segments.size
|
201
212
|
end
|
202
|
-
|
213
|
+
|
203
214
|
private
|
204
|
-
|
215
|
+
KEY_NAME_REGEXP = /([^\[]*)(\[(\d+)+\])?/
|
216
|
+
|
205
217
|
def parse(path)
|
206
|
-
|
218
|
+
|
219
|
+
segments = path.sub(/^\//,'').split('/')
|
220
|
+
segments = segments.collect do |segment|
|
221
|
+
matches = segment.to_s.scan(KEY_NAME_REGEXP).flatten.compact
|
222
|
+
index = matches[2]
|
223
|
+
if index
|
224
|
+
[matches[0].to_sym, index.to_i]
|
225
|
+
else
|
226
|
+
segment.to_sym
|
227
|
+
end
|
228
|
+
end.flatten
|
229
|
+
segments
|
207
230
|
end
|
208
|
-
|
231
|
+
|
209
232
|
end
|
210
|
-
|
233
|
+
|
211
234
|
end
|
data/spec/hash_mapper_spec.rb
CHANGED
@@ -146,12 +146,10 @@ describe "array indexes" do
|
|
146
146
|
end
|
147
147
|
|
148
148
|
it "should extract defined array values" do
|
149
|
-
pending
|
150
149
|
WithArrays.normalize(@from).should == @to
|
151
150
|
end
|
152
151
|
|
153
152
|
it "should map the other way restoring arrays" do
|
154
|
-
pending
|
155
153
|
WithArrays.denormalize(@to).should == @from
|
156
154
|
end
|
157
155
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: hash_mapper
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.9
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ismael Celis
|
@@ -9,43 +9,17 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-10-
|
12
|
+
date: 2009-10-29 00:00:00 +00:00
|
13
13
|
default_executable:
|
14
|
-
dependencies:
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
version_requirement:
|
19
|
-
version_requirements: !ruby/object:Gem::Requirement
|
20
|
-
requirements:
|
21
|
-
- - ">="
|
22
|
-
- !ruby/object:Gem::Version
|
23
|
-
version: 1.2.3
|
24
|
-
version:
|
25
|
-
- !ruby/object:Gem::Dependency
|
26
|
-
name: hoe
|
27
|
-
type: :development
|
28
|
-
version_requirement:
|
29
|
-
version_requirements: !ruby/object:Gem::Requirement
|
30
|
-
requirements:
|
31
|
-
- - ">="
|
32
|
-
- !ruby/object:Gem::Version
|
33
|
-
version: 1.8.0
|
34
|
-
version:
|
35
|
-
description: |-
|
36
|
-
Maps values from hashes with different structures and/or key names. Ideal for normalizing arbitrary data to be consumed by your applications, or to prepare your data for different display formats (ie. json).
|
37
|
-
|
38
|
-
Tiny module that allows you to easily adapt from one hash structure to another with a simple declarative DSL.
|
39
|
-
email:
|
40
|
-
- ismaelct@gmail.com
|
14
|
+
dependencies: []
|
15
|
+
|
16
|
+
description: Tiny module that allows you to easily adapt from one hash structure to another with a simple declarative DSL.
|
17
|
+
email: ismaelct@gmail.com
|
41
18
|
executables: []
|
42
19
|
|
43
20
|
extensions: []
|
44
21
|
|
45
22
|
extra_rdoc_files:
|
46
|
-
- History.txt
|
47
|
-
- Manifest.txt
|
48
|
-
- PostInstall.txt
|
49
23
|
- README.rdoc
|
50
24
|
files:
|
51
25
|
- History.txt
|
@@ -53,6 +27,8 @@ files:
|
|
53
27
|
- PostInstall.txt
|
54
28
|
- README.rdoc
|
55
29
|
- Rakefile
|
30
|
+
- VERSION
|
31
|
+
- hash_mapper.gemspec
|
56
32
|
- lib/hash_mapper.rb
|
57
33
|
- script/console
|
58
34
|
- script/destroy
|
@@ -65,10 +41,9 @@ has_rdoc: true
|
|
65
41
|
homepage: http://github.com/ismasan/hash_mapper
|
66
42
|
licenses: []
|
67
43
|
|
68
|
-
post_install_message:
|
44
|
+
post_install_message:
|
69
45
|
rdoc_options:
|
70
|
-
- --
|
71
|
-
- README.rdoc
|
46
|
+
- --charset=UTF-8
|
72
47
|
require_paths:
|
73
48
|
- lib
|
74
49
|
required_ruby_version: !ruby/object:Gem::Requirement
|
@@ -85,10 +60,11 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
85
60
|
version:
|
86
61
|
requirements: []
|
87
62
|
|
88
|
-
rubyforge_project:
|
63
|
+
rubyforge_project:
|
89
64
|
rubygems_version: 1.3.5
|
90
65
|
signing_key:
|
91
66
|
specification_version: 3
|
92
|
-
summary: Maps values from hashes with different structures and/or key names
|
93
|
-
test_files:
|
94
|
-
|
67
|
+
summary: Maps values from hashes with different structures and/or key names. Ideal for normalizing arbitrary data to be consumed by your applications, or to prepare your data for different display formats (ie. json)
|
68
|
+
test_files:
|
69
|
+
- spec/hash_mapper_spec.rb
|
70
|
+
- spec/spec_helper.rb
|