nokogiri-happymapper 0.5.3 → 0.5.4

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,13 @@
1
+ ## 0.5.4/ 2012-09-25
2
+
3
+ * #wrap method allows you to better model xml content that is buried deep
4
+ within the xml. This implementation addresses issues with calling #to_xml
5
+ with content that was parsed from an xpath. (zrob)
6
+
7
+ * Parent HappyMapper classes may dictate the name of the tag for the child
8
+ HappyMapper instances. (zrob)
9
+
10
+ ## 0.5.3/ 2012-09-23
11
+
12
+ * String is the default type for parsed fields. (crv)
13
+ * Update the attributes of an existing HappyMapper instance with new XML (benoist)
@@ -7,12 +7,15 @@ class XmlContent; end
7
7
 
8
8
  module HappyMapper
9
9
 
10
+ VERSION = "0.5.4"
11
+
10
12
  DEFAULT_NS = "happymapper"
11
13
 
12
14
  def self.included(base)
13
15
  base.instance_variable_set("@attributes", {})
14
16
  base.instance_variable_set("@elements", {})
15
17
  base.instance_variable_set("@registered_namespaces", {})
18
+ base.instance_variable_set("@wrapper_anonymous_classes", {})
16
19
 
17
20
  base.extend ClassMethods
18
21
  end
@@ -196,6 +199,38 @@ module HappyMapper
196
199
  def tag_name
197
200
  @tag_name ||= to_s.split('::')[-1].downcase
198
201
  end
202
+
203
+ # There is an XML tag that needs to be known for parsing and should be generated
204
+ # during a to_xml. But it doesn't need to be a class and the contained elements should
205
+ # be made available on the parent class
206
+ #
207
+ # @param [String] name the name of the element that is just a place holder
208
+ # @param [Proc] blk the element definitions inside the place holder tag
209
+ #
210
+ def wrap(name, &blk)
211
+ # Get an anonymous HappyMapper that has 'name' as its tag and defined
212
+ # in '&blk'. Then save that to a class instance variable for later use
213
+ wrapper = AnonymousWrapperClassFactory.get(name, &blk)
214
+ @wrapper_anonymous_classes[wrapper.inspect] = wrapper
215
+
216
+ # Create getter/setter for each element and attribute defined on the anonymous HappyMapper
217
+ # onto this class. They get/set the value by passing thru to the anonymous class.
218
+ passthrus = wrapper.attributes + wrapper.elements
219
+ passthrus.each do |item|
220
+ class_eval %{
221
+ def #{item.method_name}
222
+ @#{name} ||= self.class.instance_variable_get('@wrapper_anonymous_classes')['#{wrapper.inspect}'].new
223
+ @#{name}.#{item.method_name}
224
+ end
225
+ def #{item.method_name}=(value)
226
+ @#{name} ||= self.class.instance_variable_get('@wrapper_anonymous_classes')['#{wrapper.inspect}'].new
227
+ @#{name}.#{item.method_name} = value
228
+ end
229
+ }
230
+ end
231
+
232
+ has_one name, wrapper
233
+ end
199
234
 
200
235
  #
201
236
  # @param [Nokogiri::XML::Node,Nokogiri:XML::Document,String] xml the XML
@@ -389,13 +424,17 @@ module HappyMapper
389
424
  # is being used when called recursively.
390
425
  # @param [String] default_namespace the name of the namespace which is the
391
426
  # default for the xml being produced; this is specified by the element
392
- # declaration when calling #to_xml recursively.
427
+ # declaration when calling #to_xml recursively.
428
+ # @param [String] tag_from_parent the xml tag to use on the element when being
429
+ # called recursively. This lets the parent doc define its own structure.
430
+ # Otherwise the element uses the tag it has defined for itself. Should only
431
+ # apply when calling a child HappyMapper element.
393
432
  #
394
433
  # @return [String,Nokogiri::XML::Builder] return XML representation of the
395
434
  # HappyMapper object; when called recursively this is going to return
396
435
  # and Nokogiri::XML::Builder object.
397
436
  #
398
- def to_xml(builder = nil,default_namespace = nil)
437
+ def to_xml(builder = nil,default_namespace = nil,tag_from_parent = nil)
399
438
 
400
439
  #
401
440
  # If to_xml has been called without a passed in builder instance that
@@ -454,12 +493,13 @@ module HappyMapper
454
493
  end.flatten
455
494
 
456
495
  attributes = Hash[ *attributes ]
457
-
496
+
458
497
  #
459
- # Create a tag in the builder that matches the class's tag name and append
498
+ # Create a tag in the builder that matches the class's tag name unless a tag was passed
499
+ # in a recursive call from the parent doc. Then append
460
500
  # any attributes to the element that were defined above.
461
501
  #
462
- builder.send("#{self.class.tag_name}_",attributes) do |xml|
502
+ builder.send("#{tag_from_parent || self.class.tag_name}_",attributes) do |xml|
463
503
 
464
504
  #
465
505
  # Add all the registered namespaces to the root element.
@@ -575,7 +615,7 @@ module HappyMapper
575
615
  # process should have their contents retrieved and attached
576
616
  # to the builder structure
577
617
  #
578
- item.to_xml(xml,element.options[:namespace])
618
+ item.to_xml(xml,element.options[:namespace],element.options[:tag] || nil)
579
619
 
580
620
  elsif item
581
621
 
@@ -624,11 +664,24 @@ module HappyMapper
624
664
  # Params and return are the same as the class parse() method above.
625
665
  def parse(xml, options = {})
626
666
  self.class.parse(xml, options.merge!(:update => self))
667
+ end
668
+
669
+ private
670
+
671
+ # Factory for creating anonmyous HappyMappers
672
+ class AnonymousWrapperClassFactory
673
+ def self.get(name, &blk)
674
+ Class.new do
675
+ include HappyMapper
676
+ tag name
677
+ instance_eval &blk
678
+ end
679
+ end
627
680
  end
628
681
 
629
682
  end
630
683
 
631
- require 'happymapper/item'
632
- require 'happymapper/attribute'
633
- require 'happymapper/element'
634
- require 'happymapper/text_node'
684
+ require File.dirname(__FILE__) + '/happymapper/item'
685
+ require File.dirname(__FILE__) + '/happymapper/attribute'
686
+ require File.dirname(__FILE__) + '/happymapper/element'
687
+ require File.dirname(__FILE__) + '/happymapper/text_node'
@@ -0,0 +1,11 @@
1
+ <root attr1="somevalue">
2
+ <name>myname</name>
3
+ <mywraptag>
4
+ <description>some description</description>
5
+ <subclass myattr='attrvalue'>
6
+ <item>item1</item>
7
+ <item>item2</item>
8
+ </subclass>
9
+ </mywraptag>
10
+ <number>12345</number>
11
+ </root>
@@ -0,0 +1,92 @@
1
+ require File.dirname(__FILE__) + '/spec_helper.rb'
2
+
3
+
4
+ generic_class_xml = %{
5
+ <root>
6
+ <description>some description</description>
7
+ <blarg name='blargname1' href='http://blarg.com'/>
8
+ <blarg name='blargname2' href='http://blarg.com'/>
9
+ <jello name='jelloname' href='http://jello.com'/>
10
+ <subelement>
11
+ <jello name='subjelloname' href='http://ohnojello.com' other='othertext'/>
12
+ </subelement>
13
+ </root>
14
+ }
15
+
16
+ module GenericBase
17
+ class Base
18
+ include HappyMapper
19
+ tag '*'
20
+ attribute :name, String
21
+ attribute :href, String
22
+ attribute :other, String
23
+ end
24
+ class Sub
25
+ include HappyMapper
26
+ tag 'subelement'
27
+ has_one :jello, Base, :tag => 'jello'
28
+ end
29
+ class Root
30
+ include HappyMapper
31
+ tag 'root'
32
+ element :description, String
33
+ has_many :blargs, Base, :tag => 'blarg', :xpath => '.'
34
+ has_many :jellos, Base, :tag => 'jello', :xpath => '.'
35
+ has_many :subjellos, Base, :tag => 'jello', :xpath => 'subelement/.', :read_only => true
36
+ has_one :sub_element, Sub
37
+ end
38
+ end
39
+
40
+
41
+ describe HappyMapper do
42
+ describe "can have generic classes using tag '*'" do
43
+
44
+ before(:all) do
45
+ @root = GenericBase::Root.parse(generic_class_xml)
46
+ @xml = Nokogiri::XML(@root.to_xml)
47
+ end
48
+
49
+ it 'should map different elements to same class' do
50
+ @root.blargs.should_not be_nil
51
+ @root.jellos.should_not be_nil
52
+ end
53
+
54
+ it 'should filter on xpath appropriately' do
55
+ @root.blargs.should have(2).items
56
+ @root.jellos.should have(1).items
57
+ @root.subjellos.should have(1).items
58
+ end
59
+
60
+ it 'should parse correct values onto generic class' do
61
+ @root.blargs[0].name.should == 'blargname1'
62
+ @root.blargs[0].href.should == 'http://blarg.com'
63
+ @root.blargs[0].other.should be_nil
64
+ @root.blargs[1].name.should == 'blargname2'
65
+ @root.blargs[1].href.should == 'http://blarg.com'
66
+ @root.blargs[1].other.should be_nil
67
+ @root.jellos[0].name.should == 'jelloname'
68
+ @root.jellos[0].href.should == 'http://jello.com'
69
+ @root.jellos[0].other.should be_nil
70
+ @root.subjellos[0].name.should == 'subjelloname'
71
+ @root.subjellos[0].href.should == 'http://ohnojello.com'
72
+ @root.subjellos[0].other.should == 'othertext'
73
+ end
74
+
75
+ it 'should #to_xml using parent element tag name' do
76
+ @xml.xpath('/root/description').text.should == 'some description'
77
+ @xml.xpath('/root/blarg[1]/@name').text.should == 'blargname1'
78
+ @xml.xpath('/root/blarg[1]/@href').text.should == 'http://blarg.com'
79
+ @xml.xpath('/root/blarg[1]/@other').text.should be_empty
80
+ @xml.xpath('/root/blarg[2]/@name').text.should == 'blargname2'
81
+ @xml.xpath('/root/blarg[2]/@href').text.should == 'http://blarg.com'
82
+ @xml.xpath('/root/blarg[2]/@other').text.should be_empty
83
+ @xml.xpath('/root/jello[1]/@name').text.should == 'jelloname'
84
+ @xml.xpath('/root/jello[1]/@href').text.should == 'http://jello.com'
85
+ @xml.xpath('/root/jello[1]/@other').text.should be_empty
86
+ end
87
+
88
+ it "should properly respect child HappyMapper tags if tag isn't provided on the element defintion" do
89
+ @xml.xpath('root/subelement').should have(1).item
90
+ end
91
+ end
92
+ end
@@ -0,0 +1,69 @@
1
+ require File.dirname(__FILE__) + '/spec_helper.rb'
2
+
3
+ module Wrap
4
+ class SubClass
5
+ include HappyMapper
6
+ tag 'subclass'
7
+ attribute :myattr, String
8
+ has_many :items, String, :tag => 'item'
9
+ end
10
+ class Root
11
+ include HappyMapper
12
+ tag 'root'
13
+ attribute :attr1, String
14
+ element :name, String
15
+ wrap 'mywraptag' do
16
+ element :description, String
17
+ has_one :subclass, SubClass
18
+ end
19
+ element :number, Integer
20
+ end
21
+ end
22
+
23
+ describe HappyMapper do
24
+ describe "can parse and #to_xml taking into account a holder tag that won't be defined as a HappyMapper class" do
25
+
26
+ it 'should parse xml' do
27
+ root = Wrap::Root.parse(fixture_file('wrapper.xml'))
28
+ root.attr1.should == 'somevalue'
29
+ root.name.should == 'myname'
30
+ root.description.should == 'some description'
31
+ root.subclass.myattr.should == 'attrvalue'
32
+ root.subclass.items.should have(2).items
33
+ root.subclass.items[0].should == 'item1'
34
+ root.subclass.items[1].should == 'item2'
35
+ root.number.should == 12345
36
+ end
37
+
38
+ it "should initialize anonymous classes so nil class values don't occur" do
39
+ root = Wrap::Root.new
40
+ lambda { root.description = 'anything' }.should_not raise_error
41
+ end
42
+
43
+ it 'should #to_xml with wrapped tag' do
44
+ root = Wrap::Root.new
45
+ root.attr1 = 'somevalue'
46
+ root.name = 'myname'
47
+ root.description = 'some description'
48
+ root.number = 12345
49
+
50
+ subclass = Wrap::SubClass.new
51
+ subclass.myattr = 'attrvalue'
52
+ subclass.items = []
53
+ subclass.items << 'item1'
54
+ subclass.items << 'item2'
55
+
56
+ root.subclass = subclass
57
+
58
+ xml = Nokogiri::XML(root.to_xml)
59
+ xml.xpath('/root/@attr1').text.should == 'somevalue'
60
+ xml.xpath('/root/name').text.should == 'myname'
61
+ xml.xpath('/root/mywraptag/description').text.should == 'some description'
62
+ xml.xpath('/root/mywraptag/subclass/@myattr').text.should == 'attrvalue'
63
+ xml.xpath('/root/mywraptag/subclass/item').should have(2).items
64
+ xml.xpath('/root/mywraptag/subclass/item[1]').text.should == 'item1'
65
+ xml.xpath('/root/mywraptag/subclass/item[2]').text.should == 'item2'
66
+ xml.xpath('/root/number').text.should == '12345'
67
+ end
68
+ end
69
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: nokogiri-happymapper
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.3
4
+ version: 0.5.4
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -14,7 +14,7 @@ authors:
14
14
  autorequire:
15
15
  bindir: bin
16
16
  cert_chain: []
17
- date: 2012-09-23 00:00:00.000000000 Z
17
+ date: 2011-08-22 00:00:00.000000000 Z
18
18
  dependencies:
19
19
  - !ruby/object:Gem::Dependency
20
20
  name: nokogiri
@@ -50,11 +50,12 @@ dependencies:
50
50
  version: '2.8'
51
51
  description: Object to XML Mapping Library, using Nokogiri (fork from John Nunemaker's
52
52
  Happymapper)
53
- email:
53
+ email: franklin.webber@gmail.com
54
54
  executables: []
55
55
  extensions: []
56
56
  extra_rdoc_files:
57
57
  - README.md
58
+ - CHANGELOG.md
58
59
  - TODO
59
60
  files:
60
61
  - lib/happymapper.rb
@@ -63,6 +64,7 @@ files:
63
64
  - lib/happymapper/item.rb
64
65
  - lib/happymapper/text_node.rb
65
66
  - README.md
67
+ - CHANGELOG.md
66
68
  - TODO
67
69
  - spec/fixtures/address.xml
68
70
  - spec/fixtures/ambigous_items.xml
@@ -88,20 +90,28 @@ files:
88
90
  - spec/fixtures/radar.xml
89
91
  - spec/fixtures/statuses.xml
90
92
  - spec/fixtures/subclass_namespace.xml
93
+ - spec/fixtures/wrapper.xml
91
94
  - spec/happymapper_attribute_spec.rb
92
95
  - spec/happymapper_element_spec.rb
96
+ - spec/happymapper_generic_base_spec.rb
93
97
  - spec/happymapper_item_spec.rb
94
98
  - spec/happymapper_spec.rb
95
99
  - spec/happymapper_text_node_spec.rb
96
100
  - spec/happymapper_to_xml_namespaces_spec.rb
97
101
  - spec/happymapper_to_xml_spec.rb
102
+ - spec/happymapper_wrap_spec.rb
98
103
  - spec/ignay_spec.rb
99
104
  - spec/parse_instance_spec.rb
100
105
  - spec/spec_helper.rb
101
106
  - spec/xpath_spec.rb
102
107
  homepage: http://github.com/dam5s/happymapper
103
108
  licenses: []
104
- post_install_message:
109
+ post_install_message: ! "\n Thank you for installing nokogiri-happymapper 0.5.4 /
110
+ 2012-09-25.\n \n Changes:\n \n * #wrap method allows you to better model xml
111
+ content that is buried deep\n within the xml. This implementation addresses issues
112
+ with calling #to_xml\n with content that was parsed from an xpath. (zrob)\n \n
113
+ \ * Parent HappyMapper classes may dictate the name of the tag for the child\n HappyMapper
114
+ instances. (zrob)\n \n\n\n"
105
115
  rdoc_options: []
106
116
  require_paths:
107
117
  - lib
@@ -148,13 +158,16 @@ test_files:
148
158
  - spec/fixtures/radar.xml
149
159
  - spec/fixtures/statuses.xml
150
160
  - spec/fixtures/subclass_namespace.xml
161
+ - spec/fixtures/wrapper.xml
151
162
  - spec/happymapper_attribute_spec.rb
152
163
  - spec/happymapper_element_spec.rb
164
+ - spec/happymapper_generic_base_spec.rb
153
165
  - spec/happymapper_item_spec.rb
154
166
  - spec/happymapper_spec.rb
155
167
  - spec/happymapper_text_node_spec.rb
156
168
  - spec/happymapper_to_xml_namespaces_spec.rb
157
169
  - spec/happymapper_to_xml_spec.rb
170
+ - spec/happymapper_wrap_spec.rb
158
171
  - spec/ignay_spec.rb
159
172
  - spec/parse_instance_spec.rb
160
173
  - spec/spec_helper.rb