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.
Files changed (40) hide show
  1. data/README.md +528 -0
  2. data/TODO +0 -0
  3. data/lib/happymapper.rb +617 -0
  4. data/lib/happymapper/attribute.rb +3 -0
  5. data/lib/happymapper/element.rb +3 -0
  6. data/lib/happymapper/item.rb +250 -0
  7. data/lib/happymapper/text_node.rb +3 -0
  8. data/spec/fixtures/address.xml +8 -0
  9. data/spec/fixtures/ambigous_items.xml +22 -0
  10. data/spec/fixtures/analytics.xml +61 -0
  11. data/spec/fixtures/analytics_profile.xml +127 -0
  12. data/spec/fixtures/atom.xml +19 -0
  13. data/spec/fixtures/commit.xml +52 -0
  14. data/spec/fixtures/current_weather.xml +89 -0
  15. data/spec/fixtures/dictionary.xml +20 -0
  16. data/spec/fixtures/family_tree.xml +21 -0
  17. data/spec/fixtures/inagy.xml +86 -0
  18. data/spec/fixtures/lastfm.xml +355 -0
  19. data/spec/fixtures/multiple_namespaces.xml +170 -0
  20. data/spec/fixtures/multiple_primitives.xml +5 -0
  21. data/spec/fixtures/pita.xml +133 -0
  22. data/spec/fixtures/posts.xml +23 -0
  23. data/spec/fixtures/product_default_namespace.xml +17 -0
  24. data/spec/fixtures/product_no_namespace.xml +10 -0
  25. data/spec/fixtures/product_single_namespace.xml +10 -0
  26. data/spec/fixtures/quarters.xml +19 -0
  27. data/spec/fixtures/radar.xml +21 -0
  28. data/spec/fixtures/statuses.xml +422 -0
  29. data/spec/fixtures/subclass_namespace.xml +50 -0
  30. data/spec/happymapper_attribute_spec.rb +21 -0
  31. data/spec/happymapper_element_spec.rb +21 -0
  32. data/spec/happymapper_item_spec.rb +115 -0
  33. data/spec/happymapper_spec.rb +968 -0
  34. data/spec/happymapper_text_node_spec.rb +21 -0
  35. data/spec/happymapper_to_xml_namespaces_spec.rb +196 -0
  36. data/spec/happymapper_to_xml_spec.rb +196 -0
  37. data/spec/ignay_spec.rb +95 -0
  38. data/spec/spec_helper.rb +7 -0
  39. data/spec/xpath_spec.rb +88 -0
  40. 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
@@ -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