hash_mapper 0.0.8 → 0.0.9
Sign up to get free protection for your applications and to get access to all the features.
- 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
|