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 CHANGED
@@ -1 +1 @@
1
- 0.4.2
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(xml_path.nil? ? {} : { :xml_path => xml_path }) do |hash, mapping|
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
@@ -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[:xml_path]
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.4.2"
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{2010-12-02}
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
- - 4
9
- - 2
10
- version: 0.4.2
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: 2010-12-02 00:00:00 +01:00
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