uva-happymapper 0.4.1
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/README.md +528 -0
- data/TODO +0 -0
- data/lib/happymapper.rb +617 -0
- data/lib/happymapper/attribute.rb +3 -0
- data/lib/happymapper/element.rb +3 -0
- data/lib/happymapper/item.rb +250 -0
- data/lib/happymapper/text_node.rb +3 -0
- data/spec/fixtures/address.xml +8 -0
- data/spec/fixtures/ambigous_items.xml +22 -0
- data/spec/fixtures/analytics.xml +61 -0
- data/spec/fixtures/analytics_profile.xml +127 -0
- data/spec/fixtures/atom.xml +19 -0
- data/spec/fixtures/commit.xml +52 -0
- data/spec/fixtures/current_weather.xml +89 -0
- data/spec/fixtures/dictionary.xml +20 -0
- data/spec/fixtures/family_tree.xml +21 -0
- data/spec/fixtures/inagy.xml +86 -0
- data/spec/fixtures/lastfm.xml +355 -0
- data/spec/fixtures/multiple_namespaces.xml +170 -0
- data/spec/fixtures/multiple_primitives.xml +5 -0
- data/spec/fixtures/pita.xml +133 -0
- data/spec/fixtures/posts.xml +23 -0
- data/spec/fixtures/product_default_namespace.xml +17 -0
- data/spec/fixtures/product_no_namespace.xml +10 -0
- data/spec/fixtures/product_single_namespace.xml +10 -0
- data/spec/fixtures/quarters.xml +19 -0
- data/spec/fixtures/radar.xml +21 -0
- data/spec/fixtures/statuses.xml +422 -0
- data/spec/fixtures/subclass_namespace.xml +50 -0
- data/spec/happymapper_attribute_spec.rb +21 -0
- data/spec/happymapper_element_spec.rb +21 -0
- data/spec/happymapper_item_spec.rb +115 -0
- data/spec/happymapper_spec.rb +968 -0
- data/spec/happymapper_text_node_spec.rb +21 -0
- data/spec/happymapper_to_xml_namespaces_spec.rb +196 -0
- data/spec/happymapper_to_xml_spec.rb +196 -0
- data/spec/ignay_spec.rb +95 -0
- data/spec/spec_helper.rb +7 -0
- data/spec/xpath_spec.rb +88 -0
- metadata +118 -0
@@ -0,0 +1,21 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper.rb'
|
2
|
+
|
3
|
+
describe HappyMapper::Attribute do
|
4
|
+
describe "initialization" do
|
5
|
+
before do
|
6
|
+
@attr = HappyMapper::TextNode.new(:foo, String)
|
7
|
+
end
|
8
|
+
|
9
|
+
it 'should know that it is a text node' do
|
10
|
+
@attr.text_node?.should be_true
|
11
|
+
end
|
12
|
+
|
13
|
+
it 'should know that it is NOT an element' do
|
14
|
+
@attr.element?.should be_false
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'should know that it is NOT an attribute' do
|
18
|
+
@attr.attribute?.should be_false
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,196 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper.rb'
|
2
|
+
|
3
|
+
module ToXMLWithNamespaces
|
4
|
+
|
5
|
+
#
|
6
|
+
# Similar example as the to_xml but this time with namespacing
|
7
|
+
#
|
8
|
+
class Address
|
9
|
+
include HappyMapper
|
10
|
+
|
11
|
+
register_namespace 'address', 'http://www.company.com/address'
|
12
|
+
register_namespace 'country', 'http://www.company.com/country'
|
13
|
+
|
14
|
+
tag 'Address'
|
15
|
+
namespace 'address'
|
16
|
+
|
17
|
+
element :country, 'Country', :tag => 'country', :namespace => 'country'
|
18
|
+
|
19
|
+
attribute :location, String, :on_save => :when_saving_location
|
20
|
+
|
21
|
+
element :street, String
|
22
|
+
element :postcode, String
|
23
|
+
element :city, String
|
24
|
+
|
25
|
+
element :housenumber, String
|
26
|
+
|
27
|
+
#
|
28
|
+
# to_xml will default to the attr_accessor method and not the attribute,
|
29
|
+
# allowing for that to be overwritten
|
30
|
+
#
|
31
|
+
def housenumber
|
32
|
+
"[#{@housenumber}]"
|
33
|
+
end
|
34
|
+
|
35
|
+
def when_saving_location(loc)
|
36
|
+
loc + '-live'
|
37
|
+
end
|
38
|
+
|
39
|
+
#
|
40
|
+
# Write a empty element even if this is not specified
|
41
|
+
#
|
42
|
+
element :description, String, :state_when_nil => true
|
43
|
+
|
44
|
+
#
|
45
|
+
# Perform the on_save operation when saving
|
46
|
+
#
|
47
|
+
has_one :date_created, Time, :on_save => lambda {|time| DateTime.parse(time).strftime("%T %D") if time }
|
48
|
+
|
49
|
+
#
|
50
|
+
# Write multiple elements and call on_save when saving
|
51
|
+
#
|
52
|
+
has_many :dates_updated, Time, :on_save => lambda {|times|
|
53
|
+
times.compact.map {|time| DateTime.parse(time).strftime("%T %D") } if times }
|
54
|
+
|
55
|
+
#
|
56
|
+
# Class composition
|
57
|
+
#
|
58
|
+
|
59
|
+
def initialize(parameters)
|
60
|
+
parameters.each_pair do |property,value|
|
61
|
+
send("#{property}=",value) if respond_to?("#{property}=")
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
end
|
66
|
+
|
67
|
+
#
|
68
|
+
# Country is composed above the in Address class. Here is a demonstration
|
69
|
+
# of how to_xml will handle class composition as well as utilizing the tag
|
70
|
+
# value.
|
71
|
+
#
|
72
|
+
class Country
|
73
|
+
include HappyMapper
|
74
|
+
|
75
|
+
register_namespace 'countryName', 'http://www.company.com/countryName'
|
76
|
+
|
77
|
+
attribute :code, String, :tag => 'countryCode'
|
78
|
+
has_one :name, String, :tag => 'countryName', :namespace => 'countryName'
|
79
|
+
|
80
|
+
def initialize(parameters)
|
81
|
+
parameters.each_pair do |property,value|
|
82
|
+
send("#{property}=",value) if respond_to?("#{property}=")
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
end
|
87
|
+
|
88
|
+
|
89
|
+
#
|
90
|
+
# This class is an example of a class that has a default namespace
|
91
|
+
#xmlns="urn:eventis:prodis:onlineapi:1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"
|
92
|
+
#
|
93
|
+
class Recipe
|
94
|
+
include HappyMapper
|
95
|
+
|
96
|
+
# this is the default namespace of the document
|
97
|
+
register_namespace 'xmlns', 'urn:eventis:prodis:onlineapi:1.0'
|
98
|
+
register_namespace 'xsi', "http://www.w3.org/2001/XMLSchema-instance"
|
99
|
+
register_namespace 'xsd', "http://www.w3.org/2001/XMLSchema"
|
100
|
+
|
101
|
+
has_many :ingredients, String
|
102
|
+
|
103
|
+
def initialize(parameters)
|
104
|
+
parameters.each_pair {|property,value| send("#{property}=",value) if respond_to?("#{property}=") }
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
describe HappyMapper do
|
109
|
+
|
110
|
+
context "#to_xml", "with namespaces" do
|
111
|
+
|
112
|
+
before(:all) do
|
113
|
+
address = Address.new('street' => 'Mockingbird Lane',
|
114
|
+
'location' => 'Home',
|
115
|
+
'housenumber' => '1313',
|
116
|
+
'postcode' => '98103',
|
117
|
+
'city' => 'Seattle',
|
118
|
+
'country' => Country.new(:name => 'USA', :code => 'us'),
|
119
|
+
'date_created' => '2011-01-01 15:00:00')
|
120
|
+
|
121
|
+
|
122
|
+
address.dates_updated = ["2011-01-01 16:01:00","2011-01-02 11:30:01"]
|
123
|
+
|
124
|
+
@address_xml = Nokogiri::XML(address.to_xml).root
|
125
|
+
end
|
126
|
+
|
127
|
+
it "should save elements" do
|
128
|
+
|
129
|
+
{ 'street' => 'Mockingbird Lane',
|
130
|
+
'postcode' => '98103',
|
131
|
+
'city' => 'Seattle' }.each_pair do |property,value|
|
132
|
+
|
133
|
+
@address_xml.xpath("address:#{property}").text.should == value
|
134
|
+
|
135
|
+
end
|
136
|
+
|
137
|
+
end
|
138
|
+
|
139
|
+
it "should save the element with the result of a function call and not the value of the instance variable" do
|
140
|
+
@address_xml.xpath("address:housenumber").text.should == "[1313]"
|
141
|
+
end
|
142
|
+
|
143
|
+
it "should save attributes" do
|
144
|
+
@address_xml.xpath('@location').text.should == "Home-live"
|
145
|
+
end
|
146
|
+
|
147
|
+
context "state_when_nil options" do
|
148
|
+
|
149
|
+
it "should save an empty element" do
|
150
|
+
@address_xml.xpath('address:description').text.should == ""
|
151
|
+
end
|
152
|
+
|
153
|
+
end
|
154
|
+
|
155
|
+
context "on_save option" do
|
156
|
+
|
157
|
+
it "should save the result of the lambda" do
|
158
|
+
@address_xml.xpath('address:date_created').text.should == "15:00:00 01/01/11"
|
159
|
+
end
|
160
|
+
|
161
|
+
it "should save the result of a method" do
|
162
|
+
@address_xml.xpath('@location').text.should == "Home-live"
|
163
|
+
end
|
164
|
+
|
165
|
+
end
|
166
|
+
|
167
|
+
it "should save elements defined with the 'has_many' relationship" do
|
168
|
+
dates_updated = @address_xml.xpath('address:dates_updated')
|
169
|
+
dates_updated.length.should == 2
|
170
|
+
dates_updated.first.text.should == "16:01:00 01/01/11"
|
171
|
+
dates_updated.last.text.should == "11:30:01 01/02/11"
|
172
|
+
end
|
173
|
+
|
174
|
+
context "class types that also include HappyMapper mappings" do
|
175
|
+
|
176
|
+
it "should save attributes" do
|
177
|
+
@address_xml.xpath('country:country/@country:countryCode').text.should == "us"
|
178
|
+
end
|
179
|
+
|
180
|
+
it "should save elements" do
|
181
|
+
@address_xml.xpath('country:country/countryName:countryName').text.should == "USA"
|
182
|
+
end
|
183
|
+
|
184
|
+
end
|
185
|
+
|
186
|
+
end
|
187
|
+
|
188
|
+
context "#to_xml", "with a default namespace" do
|
189
|
+
it "should write the default namespace to xml without repeating xmlns" do
|
190
|
+
recipe = Recipe.new(:ingredients => ['One Cup Flour', 'Two Scoops of Lovin'])
|
191
|
+
recipe.to_xml.should =~ /xmlns=\"urn:eventis:prodis:onlineapi:1\.0\"/
|
192
|
+
end
|
193
|
+
end
|
194
|
+
end
|
195
|
+
|
196
|
+
end
|
@@ -0,0 +1,196 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper.rb'
|
2
|
+
|
3
|
+
module ToXML
|
4
|
+
|
5
|
+
class Address
|
6
|
+
include HappyMapper
|
7
|
+
|
8
|
+
tag 'address'
|
9
|
+
|
10
|
+
attribute :location, String, :on_save => :when_saving_location
|
11
|
+
|
12
|
+
element :street, String
|
13
|
+
element :postcode, String
|
14
|
+
element :city, String
|
15
|
+
|
16
|
+
element :housenumber, String
|
17
|
+
|
18
|
+
attribute :modified, Boolean, :read_only => true
|
19
|
+
element :temporary, Boolean, :read_only => true
|
20
|
+
#
|
21
|
+
# to_xml will default to the attr_accessor method and not the attribute,
|
22
|
+
# allowing for that to be overwritten
|
23
|
+
#
|
24
|
+
def housenumber
|
25
|
+
"[#{@housenumber}]"
|
26
|
+
end
|
27
|
+
|
28
|
+
def when_saving_location(loc)
|
29
|
+
loc + "-live"
|
30
|
+
end
|
31
|
+
|
32
|
+
#
|
33
|
+
# Write a empty element even if this is not specified
|
34
|
+
#
|
35
|
+
element :description, String, :state_when_nil => true
|
36
|
+
|
37
|
+
#
|
38
|
+
# Perform the on_save operation when saving
|
39
|
+
#
|
40
|
+
has_one :date_created, Time, :on_save => lambda {|time| DateTime.parse(time).strftime("%T %D") if time }
|
41
|
+
|
42
|
+
|
43
|
+
#
|
44
|
+
# Execute the method with the same name
|
45
|
+
|
46
|
+
#
|
47
|
+
# Write multiple elements and call on_save when saving
|
48
|
+
#
|
49
|
+
has_many :dates_updated, Time, :on_save => lambda {|times|
|
50
|
+
times.compact.map {|time| DateTime.parse(time).strftime("%T %D") } if times }
|
51
|
+
|
52
|
+
#
|
53
|
+
# Class composition
|
54
|
+
#
|
55
|
+
element :country, 'Country', :tag => 'country'
|
56
|
+
|
57
|
+
def initialize(parameters)
|
58
|
+
parameters.each_pair do |property,value|
|
59
|
+
send("#{property}=",value) if respond_to?("#{property}=")
|
60
|
+
end
|
61
|
+
@modified = @temporary = true
|
62
|
+
end
|
63
|
+
|
64
|
+
end
|
65
|
+
|
66
|
+
#
|
67
|
+
# Country is composed above the in Address class. Here is a demonstration
|
68
|
+
# of how to_xml will handle class composition as well as utilizing the tag
|
69
|
+
# value.
|
70
|
+
#
|
71
|
+
class Country
|
72
|
+
include HappyMapper
|
73
|
+
|
74
|
+
attribute :code, String, :tag => 'countryCode'
|
75
|
+
has_one :name, String, :tag => 'countryName'
|
76
|
+
has_one :description, 'Description', :tag => 'description'
|
77
|
+
|
78
|
+
#
|
79
|
+
# This inner-class here is to demonstrate saving a text node
|
80
|
+
# and optional attributes
|
81
|
+
#
|
82
|
+
class Description
|
83
|
+
include HappyMapper
|
84
|
+
text_node :description, String
|
85
|
+
attribute :category, String, :tag => 'category'
|
86
|
+
attribute :rating, String, :tag => 'rating', :state_when_nil => true
|
87
|
+
|
88
|
+
def initialize(desc)
|
89
|
+
@description = desc
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def initialize(parameters)
|
94
|
+
parameters.each_pair do |property,value|
|
95
|
+
send("#{property}=",value) if respond_to?("#{property}=")
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
end
|
100
|
+
|
101
|
+
describe HappyMapper do
|
102
|
+
|
103
|
+
context "#to_xml" do
|
104
|
+
|
105
|
+
before(:all) do
|
106
|
+
address = Address.new('street' => 'Mockingbird Lane',
|
107
|
+
'location' => 'Home',
|
108
|
+
'housenumber' => '1313',
|
109
|
+
'postcode' => '98103',
|
110
|
+
'city' => 'Seattle',
|
111
|
+
'country' => Country.new(:name => 'USA', :code => 'us', :empty_code => nil,
|
112
|
+
:description => Country::Description.new("A lovely country") ),
|
113
|
+
'date_created' => '2011-01-01 15:00:00')
|
114
|
+
|
115
|
+
|
116
|
+
address.dates_updated = ["2011-01-01 16:01:00","2011-01-02 11:30:01"]
|
117
|
+
|
118
|
+
@address_xml = Nokogiri::XML(address.to_xml).root
|
119
|
+
end
|
120
|
+
|
121
|
+
it "should save elements" do
|
122
|
+
{ 'street' => 'Mockingbird Lane',
|
123
|
+
'postcode' => '98103',
|
124
|
+
'city' => 'Seattle' }.each_pair do |property,value|
|
125
|
+
|
126
|
+
@address_xml.xpath("#{property}").text.should == value
|
127
|
+
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
it "should save the element with the result of a function call and not the value of the instance variable" do
|
132
|
+
@address_xml.xpath("housenumber").text.should == "[1313]"
|
133
|
+
end
|
134
|
+
|
135
|
+
it "should not save elements marked as read_only" do
|
136
|
+
@address_xml.xpath('temporary').should be_empty
|
137
|
+
end
|
138
|
+
|
139
|
+
it "should save attribues" do
|
140
|
+
@address_xml.xpath('@location').text.should == "Home-live"
|
141
|
+
end
|
142
|
+
|
143
|
+
it "should not save attributes marked as read_only" do
|
144
|
+
@address_xml.xpath("@modified").should be_empty
|
145
|
+
end
|
146
|
+
|
147
|
+
context "state_when_nil option" do
|
148
|
+
|
149
|
+
it "should save an empty element" do
|
150
|
+
@address_xml.xpath('description').text.should == ""
|
151
|
+
end
|
152
|
+
|
153
|
+
end
|
154
|
+
|
155
|
+
context "on_save option" do
|
156
|
+
|
157
|
+
it "should save the result of the lambda" do
|
158
|
+
@address_xml.xpath('date_created').text.should == "15:00:00 01/01/11"
|
159
|
+
end
|
160
|
+
|
161
|
+
it "should save the result of a method" do
|
162
|
+
@address_xml.xpath('@location').text.should == "Home-live"
|
163
|
+
end
|
164
|
+
|
165
|
+
end
|
166
|
+
|
167
|
+
|
168
|
+
it "should save elements defined with the 'has_many' relationship" do
|
169
|
+
dates_updated = @address_xml.xpath('dates_updated')
|
170
|
+
dates_updated.length.should == 2
|
171
|
+
dates_updated.first.text.should == "16:01:00 01/01/11"
|
172
|
+
dates_updated.last.text.should == "11:30:01 01/02/11"
|
173
|
+
end
|
174
|
+
|
175
|
+
context "class types that also contain HappyMapper mappings" do
|
176
|
+
|
177
|
+
it "should save attributes" do
|
178
|
+
@address_xml.xpath('country/@countryCode').text.should == "us"
|
179
|
+
end
|
180
|
+
|
181
|
+
it "should save elements" do
|
182
|
+
@address_xml.xpath('country/countryName').text.should == "USA"
|
183
|
+
end
|
184
|
+
|
185
|
+
it "should save elements" do
|
186
|
+
@address_xml.xpath('country/description').text.should == "A lovely country"
|
187
|
+
end
|
188
|
+
|
189
|
+
end
|
190
|
+
|
191
|
+
end
|
192
|
+
|
193
|
+
|
194
|
+
end
|
195
|
+
|
196
|
+
end
|
data/spec/ignay_spec.rb
ADDED
@@ -0,0 +1,95 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper.rb'
|
2
|
+
|
3
|
+
class CatalogTree
|
4
|
+
include HappyMapper
|
5
|
+
|
6
|
+
tag 'CatalogTree'
|
7
|
+
register_namespace 'xmlns', 'urn:eventis:prodis:onlineapi:1.0'
|
8
|
+
register_namespace 'xsi', 'http://www.w3.org/2001/XMLSchema-instance'
|
9
|
+
register_namespace 'xsd', 'http://www.w3.org/2001/XMLSchema'
|
10
|
+
|
11
|
+
attribute :code, String
|
12
|
+
|
13
|
+
has_many :nodes, 'CatalogNode', :tag => 'Node', :xpath => '.'
|
14
|
+
|
15
|
+
end
|
16
|
+
|
17
|
+
|
18
|
+
class CatalogNode
|
19
|
+
include HappyMapper
|
20
|
+
|
21
|
+
tag 'Node'
|
22
|
+
|
23
|
+
attribute :back_office_id, String, :tag => 'vodBackOfficeId'
|
24
|
+
|
25
|
+
has_one :name, String, :tag => 'Name'
|
26
|
+
# other important fields
|
27
|
+
|
28
|
+
has_many :translations, 'CatalogNode::Translations', :tag => 'Translation', :xpath => 'child::*'
|
29
|
+
|
30
|
+
class Translations
|
31
|
+
include HappyMapper
|
32
|
+
tag 'Translation'
|
33
|
+
|
34
|
+
attribute :language, String, :tag => 'Language'
|
35
|
+
has_one :name, String, :tag => 'Name'
|
36
|
+
|
37
|
+
end
|
38
|
+
|
39
|
+
has_many :nodes, CatalogNode, :tag => 'Node', :xpath => 'child::*'
|
40
|
+
|
41
|
+
end
|
42
|
+
|
43
|
+
describe HappyMapper do
|
44
|
+
|
45
|
+
it "should not be nil" do
|
46
|
+
catalog_tree.should_not be_nil
|
47
|
+
end
|
48
|
+
|
49
|
+
it "should have the attribute code" do
|
50
|
+
catalog_tree.code.should == "NLD"
|
51
|
+
end
|
52
|
+
|
53
|
+
it "should have many nodes" do
|
54
|
+
catalog_tree.nodes.should_not be_empty
|
55
|
+
catalog_tree.nodes.length.should == 2
|
56
|
+
end
|
57
|
+
|
58
|
+
context "first node" do
|
59
|
+
|
60
|
+
it "should have a name" do
|
61
|
+
first_node.name.should == "Parent 1"
|
62
|
+
end
|
63
|
+
|
64
|
+
it "should have translations" do
|
65
|
+
first_node.translations.length.should == 2
|
66
|
+
|
67
|
+
first_node.translations.first.language.should == "en-GB"
|
68
|
+
|
69
|
+
first_node.translations.last.name.should == "Parent 1 de"
|
70
|
+
end
|
71
|
+
|
72
|
+
it "should have subnodes" do
|
73
|
+
first_node.nodes.should be_kind_of(Enumerable)
|
74
|
+
first_node.nodes.should_not be_empty
|
75
|
+
first_node.nodes.length.should == 1
|
76
|
+
end
|
77
|
+
|
78
|
+
it "first node - first node name" do
|
79
|
+
first_node.nodes.first.name.should == "First"
|
80
|
+
end
|
81
|
+
|
82
|
+
def first_node
|
83
|
+
@first_node = catalog_tree.nodes.first
|
84
|
+
end
|
85
|
+
|
86
|
+
end
|
87
|
+
|
88
|
+
|
89
|
+
def catalog_tree ; @catalog_tree ; end
|
90
|
+
|
91
|
+
before(:all) do
|
92
|
+
xml_reference = "#{File.dirname(__FILE__)}/fixtures/inagy.xml"
|
93
|
+
@catalog_tree = CatalogTree.parse(File.read(xml_reference), :single => true)
|
94
|
+
end
|
95
|
+
end
|