nokogiri-happymapper 0.5.3 → 0.5.4

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.
@@ -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