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.
- data/CHANGELOG.md +13 -0
- data/lib/happymapper.rb +63 -10
- data/spec/fixtures/wrapper.xml +11 -0
- data/spec/happymapper_generic_base_spec.rb +92 -0
- data/spec/happymapper_wrap_spec.rb +69 -0
- metadata +17 -4
data/CHANGELOG.md
ADDED
@@ -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)
|
data/lib/happymapper.rb
CHANGED
@@ -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
|
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,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.
|
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:
|
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
|