xml_mapper 0.4.2 → 0.5.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.
- data/VERSION +1 -1
- data/lib/xml_mapper.rb +6 -5
- data/lib/xml_mapper_hash.rb +24 -0
- data/spec/xml_mapper_hash_spec.rb +72 -0
- data/spec/xml_mapper_spec.rb +75 -21
- data/xml_mapper.gemspec +5 -2
- metadata +7 -4
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.5.0
|
data/lib/xml_mapper.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
require "nokogiri"
|
2
|
+
require "xml_mapper_hash"
|
2
3
|
|
3
4
|
class XmlMapper
|
4
5
|
attr_accessor :mappings, :after_map_block, :within_xpath
|
@@ -118,12 +119,12 @@ class XmlMapper
|
|
118
119
|
|
119
120
|
def attributes_from_xml(xml_or_doc, xml_path = nil)
|
120
121
|
if xml_or_doc.is_a?(Array)
|
121
|
-
xml_or_doc.map { |doc| attributes_from_xml(doc) }
|
122
|
+
xml_or_doc.map { |doc| attributes_from_xml(doc, xml_path) }
|
122
123
|
else
|
123
124
|
doc = xml_or_doc.is_a?(Nokogiri::XML::Node) ? xml_or_doc : Nokogiri::XML(xml_or_doc)
|
124
125
|
doc = doc.root if doc.respond_to?(:root)
|
125
|
-
atts = self.mappings.inject(
|
126
|
-
if (value = value_from_doc_and_mapping(doc, mapping)) != :not_found
|
126
|
+
atts = self.mappings.inject(XmlMapperHash.from_path_and_node(xml_path, doc)) do |hash, mapping|
|
127
|
+
if (value = value_from_doc_and_mapping(doc, mapping, xml_path)) != :not_found
|
127
128
|
add_value_to_hash(hash, mapping[:key], value)
|
128
129
|
end
|
129
130
|
end
|
@@ -142,9 +143,9 @@ class XmlMapper
|
|
142
143
|
hash
|
143
144
|
end
|
144
145
|
|
145
|
-
def value_from_doc_and_mapping(doc, mapping)
|
146
|
+
def value_from_doc_and_mapping(doc, mapping, xml_path = nil)
|
146
147
|
if mapping[:type] == :many
|
147
|
-
mapping[:options][:mapper].attributes_from_xml(doc.search(mapping[:xpath]).to_a)
|
148
|
+
mapping[:options][:mapper].attributes_from_xml(doc.search(mapping[:xpath]).to_a, xml_path)
|
148
149
|
else
|
149
150
|
node = mapping[:xpath].length == 0 ? doc : doc.xpath(mapping[:xpath]).first
|
150
151
|
if mapping[:type] == :exists
|
@@ -0,0 +1,24 @@
|
|
1
|
+
class XmlMapper
|
2
|
+
class XmlMapperHash < Hash
|
3
|
+
attr_accessor :xml_path, :node
|
4
|
+
|
5
|
+
def self.from_path_and_node(new_path, new_node)
|
6
|
+
hash = self.new
|
7
|
+
hash.xml_path = new_path
|
8
|
+
hash.node = new_node
|
9
|
+
hash
|
10
|
+
end
|
11
|
+
|
12
|
+
def clone_attributes_into!(to_be_cloned_attributes, into_keys)
|
13
|
+
hashes_from_into_keys(into_keys).each do |sub_attributes|
|
14
|
+
[to_be_cloned_attributes].flatten.each do |clone_key, clone_value|
|
15
|
+
sub_attributes[clone_key.to_sym] ||= self[clone_key.to_sym] if self.has_key?(clone_key.to_sym)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def hashes_from_into_keys(into_keys)
|
21
|
+
[into_keys].flatten.map { |key| self[key] }.flatten.compact
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
|
+
|
3
|
+
describe XmlMapper::XmlMapperHash do
|
4
|
+
describe "#from_path_and_node" do
|
5
|
+
it "sets the correct xml_path" do
|
6
|
+
hash = XmlMapper::XmlMapperHash.from_path_and_node("/some/path.xml", nil)
|
7
|
+
hash.xml_path.should == "/some/path.xml"
|
8
|
+
end
|
9
|
+
|
10
|
+
it "sets the correct node" do
|
11
|
+
node = double("node")
|
12
|
+
hash = XmlMapper::XmlMapperHash.from_path_and_node("/some/path.xml", node)
|
13
|
+
hash.node.should == node
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
describe "#clone_attributes_into" do
|
18
|
+
it "does not break when track_attributes are nil" do
|
19
|
+
hash = XmlMapper::XmlMapperHash.new.merge(:upc => "1234")
|
20
|
+
hash.clone_attributes_into!([:upc], :tracks_attributes)
|
21
|
+
hash.should == { :upc => "1234" }
|
22
|
+
end
|
23
|
+
|
24
|
+
it "does not change anything when album does not have selected attributes" do
|
25
|
+
hash = XmlMapper::XmlMapperHash.new.merge(:upc => "12343", :tracks_attributes => [:track_number => 1])
|
26
|
+
hash.clone_attributes_into!([:artist_name], :tracks_attributes)
|
27
|
+
hash.should == {
|
28
|
+
:upc => "12343", :tracks_attributes => [:track_number => 1]
|
29
|
+
}
|
30
|
+
end
|
31
|
+
|
32
|
+
it "clones all selected attributes" do
|
33
|
+
hash = XmlMapper::XmlMapperHash.new.merge(:artist_name => "Mos Def", :title => "Some Title", :upc => "12343",
|
34
|
+
:tracks_attributes => [{ :track_number => 1 }, { :track_number => 2 }]
|
35
|
+
)
|
36
|
+
hash.clone_attributes_into!([:artist_name, :upc], :tracks_attributes)
|
37
|
+
hash.should == {
|
38
|
+
:artist_name => "Mos Def", :title => "Some Title", :upc => "12343",
|
39
|
+
:tracks_attributes => [
|
40
|
+
{ :track_number => 1, :artist_name => "Mos Def", :upc => "12343" },
|
41
|
+
{ :track_number => 2, :artist_name => "Mos Def", :upc => "12343" }
|
42
|
+
]
|
43
|
+
}
|
44
|
+
end
|
45
|
+
|
46
|
+
it "allows cloning of attributes into multiple arrays" do
|
47
|
+
hash = XmlMapper::XmlMapperHash.new.merge(:upc => "12343",
|
48
|
+
:tracks_attributes => [{ :track_number => 1 }, { :track_number => 2 }],
|
49
|
+
:videos_attributes => [{ :video_number => 1 }, { :video_number => 2 }]
|
50
|
+
)
|
51
|
+
hash.clone_attributes_into!(:upc, [:tracks_attributes, :videos_attributes])
|
52
|
+
hash.should == {
|
53
|
+
:upc => "12343",
|
54
|
+
:tracks_attributes => [{ :track_number => 1, :upc => "12343" }, { :track_number => 2, :upc => "12343" }],
|
55
|
+
:videos_attributes => [{ :video_number => 1, :upc => "12343" }, { :video_number => 2, :upc => "12343" }]
|
56
|
+
}
|
57
|
+
end
|
58
|
+
|
59
|
+
it "does not overwrite already set attributes" do
|
60
|
+
hash = XmlMapper::XmlMapperHash.new.merge(:artist_name => "Mos Def", :title => "Some Title", :upc => "12343",
|
61
|
+
:tracks_attributes => [
|
62
|
+
{ :track_number => 1 }, { :track_number => 2, :artist_name => "Mos and Talib" }
|
63
|
+
]
|
64
|
+
)
|
65
|
+
hash.clone_attributes_into!([:artist_name, :upc], :tracks_attributes)
|
66
|
+
hash.should == { :artist_name => "Mos Def", :title => "Some Title", :upc => "12343", :tracks_attributes => [
|
67
|
+
{ :track_number => 1, :artist_name => "Mos Def", :upc => "12343" }, { :track_number => 2, :artist_name => "Mos and Talib", :upc => "12343" }
|
68
|
+
]
|
69
|
+
}
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
data/spec/xml_mapper_spec.rb
CHANGED
@@ -1,6 +1,16 @@
|
|
1
1
|
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
2
|
|
3
3
|
describe "XmlMapper" do
|
4
|
+
def create_class(base_class = "XmlMapper")
|
5
|
+
class_name = "TestMapping#{Time.now.to_f.to_s.gsub(".", "")}"
|
6
|
+
str = %(
|
7
|
+
class #{class_name} < #{base_class}
|
8
|
+
end
|
9
|
+
)
|
10
|
+
eval(str)
|
11
|
+
eval(class_name)
|
12
|
+
end
|
13
|
+
|
4
14
|
before(:each) do
|
5
15
|
@mapper = XmlMapper.new
|
6
16
|
end
|
@@ -278,12 +288,6 @@ describe "XmlMapper" do
|
|
278
288
|
File.stub(:read).and_return @xml
|
279
289
|
end
|
280
290
|
|
281
|
-
it "sets the xml_path" do
|
282
|
-
@mapper.attributes_from_xml_path("/some/path.xml").should == {
|
283
|
-
:title => "Black on Both Sides", :xml_path => "/some/path.xml"
|
284
|
-
}
|
285
|
-
end
|
286
|
-
|
287
291
|
it "calls File.read with correct parameters" do
|
288
292
|
File.should_receive(:read).with("/some/path.xml").and_return @xml
|
289
293
|
@mapper.attributes_from_xml_path("/some/path.xml")
|
@@ -291,7 +295,7 @@ describe "XmlMapper" do
|
|
291
295
|
|
292
296
|
it "allows using the xml_path in after_map block" do
|
293
297
|
@mapper.after_map do
|
294
|
-
self[:new_xml_path] = self
|
298
|
+
self[:new_xml_path] = self.xml_path
|
295
299
|
end
|
296
300
|
@mapper.attributes_from_xml_path("/some/path.xml")[:new_xml_path].should == "/some/path.xml"
|
297
301
|
end
|
@@ -324,6 +328,68 @@ describe "XmlMapper" do
|
|
324
328
|
:upc => "1234"
|
325
329
|
}
|
326
330
|
end
|
331
|
+
|
332
|
+
describe "using xml_path and node" do
|
333
|
+
before(:each) do
|
334
|
+
xml = %(
|
335
|
+
<album>
|
336
|
+
<tracks>
|
337
|
+
<track><title>First Track</title></track>
|
338
|
+
<track><title>Second Track Track</title></track>
|
339
|
+
</tracks>
|
340
|
+
</album>
|
341
|
+
)
|
342
|
+
File.stub(:read).and_return xml
|
343
|
+
end
|
344
|
+
|
345
|
+
it "allows accessing xml_path in after_map block" do
|
346
|
+
@mapper.after_map do
|
347
|
+
self[:new_path] = self.xml_path
|
348
|
+
end
|
349
|
+
@mapper.attributes_from_xml_path("/some/other/path.xml").should == { :new_path => "/some/other/path.xml" }
|
350
|
+
end
|
351
|
+
|
352
|
+
it "allows using node in after_map block" do
|
353
|
+
@mapper.after_map do
|
354
|
+
self[:tracks_count] = self.node.search("tracks/track").count
|
355
|
+
end
|
356
|
+
@mapper.attributes_from_xml_path("/some/other/path.xml").should == { :tracks_count => 2 }
|
357
|
+
end
|
358
|
+
|
359
|
+
it "allows using xml_path in subnodes" do
|
360
|
+
clazz = create_class
|
361
|
+
clazz.many "tracks/track" => :tracks do
|
362
|
+
after_map do
|
363
|
+
self[:new_path] = self.xml_path
|
364
|
+
end
|
365
|
+
end
|
366
|
+
clazz.attributes_from_xml_path("/some/other/path.xml").should == { :tracks =>
|
367
|
+
[
|
368
|
+
{ :new_path => "/some/other/path.xml" },
|
369
|
+
{ :new_path => "/some/other/path.xml" }
|
370
|
+
]
|
371
|
+
}
|
372
|
+
end
|
373
|
+
|
374
|
+
it "allows using node in subnodes" do
|
375
|
+
clazz = create_class
|
376
|
+
clazz.many "tracks/track" => :tracks do
|
377
|
+
after_map do
|
378
|
+
self[:title_count] = self.node.search("title").count
|
379
|
+
end
|
380
|
+
end
|
381
|
+
clazz.after_map do
|
382
|
+
self[:title_count] = self.node.search("title").count
|
383
|
+
end
|
384
|
+
|
385
|
+
clazz.attributes_from_xml_path("/some/other/path.xml").should == { :title_count => 2,
|
386
|
+
:tracks => [
|
387
|
+
{ :title_count => 1 },
|
388
|
+
{ :title_count => 1 }
|
389
|
+
]
|
390
|
+
}
|
391
|
+
end
|
392
|
+
end
|
327
393
|
end
|
328
394
|
|
329
395
|
describe "converting strings" do
|
@@ -340,16 +406,6 @@ describe "XmlMapper" do
|
|
340
406
|
end
|
341
407
|
|
342
408
|
describe "defining a DSL" do
|
343
|
-
def create_class(base_class = "XmlMapper")
|
344
|
-
class_name = "TestMapping#{Time.now.to_f.to_s.gsub(".", "")}"
|
345
|
-
str = %(
|
346
|
-
class #{class_name} < #{base_class}
|
347
|
-
end
|
348
|
-
)
|
349
|
-
eval(str)
|
350
|
-
eval(class_name)
|
351
|
-
end
|
352
|
-
|
353
409
|
before(:each) do
|
354
410
|
# so that we have a new class in each spec
|
355
411
|
@clazz = create_class
|
@@ -378,8 +434,7 @@ describe "XmlMapper" do
|
|
378
434
|
File.stub(:read).and_return %(<album><title>Test Title</title></album>)
|
379
435
|
@clazz.text(:title)
|
380
436
|
@clazz.attributes_from_xml_path("/some/path.xml").should == {
|
381
|
-
:title => "Test Title"
|
382
|
-
:xml_path => "/some/path.xml"
|
437
|
+
:title => "Test Title"
|
383
438
|
}
|
384
439
|
end
|
385
440
|
|
@@ -574,8 +629,7 @@ describe "XmlMapper" do
|
|
574
629
|
File.stub!(:read).and_return xml
|
575
630
|
subclazz.attributes_from_xml_path("/some_path/album.xml").should == {
|
576
631
|
:artist_name => "Mos Def",
|
577
|
-
:title => "Black on Both Sides"
|
578
|
-
:xml_path => "/some_path/album.xml"
|
632
|
+
:title => "Black on Both Sides"
|
579
633
|
}
|
580
634
|
end
|
581
635
|
end
|
data/xml_mapper.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{xml_mapper}
|
8
|
-
s.version = "0.
|
8
|
+
s.version = "0.5.0"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Tobias Schwab"]
|
12
|
-
s.date = %q{
|
12
|
+
s.date = %q{2011-01-10}
|
13
13
|
s.description = %q{Declarative XML to Ruby mapping}
|
14
14
|
s.email = %q{tobias.schwab@dynport.de}
|
15
15
|
s.extra_rdoc_files = [
|
@@ -31,10 +31,12 @@ Gem::Specification.new do |s|
|
|
31
31
|
"features/support/env.rb",
|
32
32
|
"features/xml_mapper.feature",
|
33
33
|
"lib/xml_mapper.rb",
|
34
|
+
"lib/xml_mapper_hash.rb",
|
34
35
|
"spec/example_spec.rb",
|
35
36
|
"spec/fixtures/base.xml",
|
36
37
|
"spec/my_mapper.rb",
|
37
38
|
"spec/spec_helper.rb",
|
39
|
+
"spec/xml_mapper_hash_spec.rb",
|
38
40
|
"spec/xml_mapper_spec.rb",
|
39
41
|
"xml_mapper.gemspec"
|
40
42
|
]
|
@@ -47,6 +49,7 @@ Gem::Specification.new do |s|
|
|
47
49
|
"spec/example_spec.rb",
|
48
50
|
"spec/my_mapper.rb",
|
49
51
|
"spec/spec_helper.rb",
|
52
|
+
"spec/xml_mapper_hash_spec.rb",
|
50
53
|
"spec/xml_mapper_spec.rb"
|
51
54
|
]
|
52
55
|
|
metadata
CHANGED
@@ -5,9 +5,9 @@ version: !ruby/object:Gem::Version
|
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 0
|
8
|
-
-
|
9
|
-
-
|
10
|
-
version: 0.
|
8
|
+
- 5
|
9
|
+
- 0
|
10
|
+
version: 0.5.0
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Tobias Schwab
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date:
|
18
|
+
date: 2011-01-10 00:00:00 +01:00
|
19
19
|
default_executable:
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|
@@ -174,10 +174,12 @@ files:
|
|
174
174
|
- features/support/env.rb
|
175
175
|
- features/xml_mapper.feature
|
176
176
|
- lib/xml_mapper.rb
|
177
|
+
- lib/xml_mapper_hash.rb
|
177
178
|
- spec/example_spec.rb
|
178
179
|
- spec/fixtures/base.xml
|
179
180
|
- spec/my_mapper.rb
|
180
181
|
- spec/spec_helper.rb
|
182
|
+
- spec/xml_mapper_hash_spec.rb
|
181
183
|
- spec/xml_mapper_spec.rb
|
182
184
|
- xml_mapper.gemspec
|
183
185
|
has_rdoc: true
|
@@ -218,4 +220,5 @@ test_files:
|
|
218
220
|
- spec/example_spec.rb
|
219
221
|
- spec/my_mapper.rb
|
220
222
|
- spec/spec_helper.rb
|
223
|
+
- spec/xml_mapper_hash_spec.rb
|
221
224
|
- spec/xml_mapper_spec.rb
|