xml_mapper 0.4.2 → 0.5.0

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