legolin-happymapper 0.3.0
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/HOW_TO_RELEASE +5 -0
- data/History +59 -0
- data/License +20 -0
- data/Manifest +42 -0
- data/README +61 -0
- data/Rakefile +43 -0
- data/TODO +0 -0
- data/examples/amazon.rb +34 -0
- data/examples/current_weather.rb +21 -0
- data/examples/dashed_elements.rb +20 -0
- data/examples/multi_street_address.rb +15 -0
- data/examples/post.rb +19 -0
- data/examples/twitter.rb +37 -0
- data/happymapper.gemspec +0 -0
- data/legolin-happymapper.gemspec +34 -0
- data/lib/happymapper.rb +161 -0
- data/lib/happymapper/attribute.rb +3 -0
- data/lib/happymapper/element.rb +3 -0
- data/lib/happymapper/item.rb +192 -0
- data/lib/happymapper/version.rb +3 -0
- data/spec/fixtures/address.xml +8 -0
- data/spec/fixtures/analytics.xml +61 -0
- data/spec/fixtures/commit.xml +52 -0
- data/spec/fixtures/current_weather.xml +89 -0
- data/spec/fixtures/family_tree.xml +7 -0
- data/spec/fixtures/multi_street_address.xml +9 -0
- data/spec/fixtures/multiple_namespaces.xml +170 -0
- data/spec/fixtures/nested_namespaces.xml +17 -0
- data/spec/fixtures/pita.xml +133 -0
- data/spec/fixtures/posts.xml +23 -0
- data/spec/fixtures/product_default_namespace.xml +10 -0
- data/spec/fixtures/product_no_namespace.xml +10 -0
- data/spec/fixtures/product_single_namespace.xml +10 -0
- data/spec/fixtures/radar.xml +21 -0
- data/spec/fixtures/statuses.xml +422 -0
- data/spec/happymapper_attribute_spec.rb +17 -0
- data/spec/happymapper_element_spec.rb +17 -0
- data/spec/happymapper_item_spec.rb +115 -0
- data/spec/happymapper_spec.rb +719 -0
- data/spec/spec.opts +1 -0
- data/spec/spec_helper.rb +13 -0
- data/website/css/common.css +47 -0
- data/website/index.html +98 -0
- metadata +129 -0
@@ -0,0 +1,17 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper.rb'
|
2
|
+
|
3
|
+
describe HappyMapper::Attribute do
|
4
|
+
describe "initialization" do
|
5
|
+
before do
|
6
|
+
@attr = HappyMapper::Attribute.new(:foo, String)
|
7
|
+
end
|
8
|
+
|
9
|
+
it 'should know that it is an attribute' do
|
10
|
+
@attr.attribute?.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
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper.rb'
|
2
|
+
|
3
|
+
describe HappyMapper::Element do
|
4
|
+
describe "initialization" do
|
5
|
+
before do
|
6
|
+
@attr = HappyMapper::Element.new(:foo, String)
|
7
|
+
end
|
8
|
+
|
9
|
+
it 'should know that it is an element' do
|
10
|
+
@attr.element?.should be_true
|
11
|
+
end
|
12
|
+
|
13
|
+
it 'should know that it is NOT an attribute' do
|
14
|
+
@attr.attribute?.should be_false
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,115 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper.rb'
|
2
|
+
|
3
|
+
module Foo
|
4
|
+
class Bar; end
|
5
|
+
end
|
6
|
+
|
7
|
+
describe HappyMapper::Item do
|
8
|
+
|
9
|
+
describe "new instance" do
|
10
|
+
before do
|
11
|
+
@item = HappyMapper::Item.new(:foo, String, :tag => 'foobar')
|
12
|
+
end
|
13
|
+
|
14
|
+
it "should accept a name" do
|
15
|
+
@item.name.should == 'foo'
|
16
|
+
end
|
17
|
+
|
18
|
+
it 'should accept a type' do
|
19
|
+
@item.type.should == String
|
20
|
+
end
|
21
|
+
|
22
|
+
it 'should accept :tag as an option' do
|
23
|
+
@item.tag.should == 'foobar'
|
24
|
+
end
|
25
|
+
|
26
|
+
it "should have a method_name" do
|
27
|
+
@item.method_name.should == 'foo'
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
describe "#constant" do
|
32
|
+
it "should just use type if constant" do
|
33
|
+
item = HappyMapper::Item.new(:foo, String)
|
34
|
+
item.constant.should == String
|
35
|
+
end
|
36
|
+
|
37
|
+
it "should convert string type to constant" do
|
38
|
+
item = HappyMapper::Item.new(:foo, 'String')
|
39
|
+
item.constant.should == String
|
40
|
+
end
|
41
|
+
|
42
|
+
it "should convert string with :: to constant" do
|
43
|
+
item = HappyMapper::Item.new(:foo, 'Foo::Bar')
|
44
|
+
item.constant.should == Foo::Bar
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
describe "#method_name" do
|
49
|
+
it "should convert dashes to underscores" do
|
50
|
+
item = HappyMapper::Item.new(:'foo-bar', String, :tag => 'foobar')
|
51
|
+
item.method_name.should == 'foo_bar'
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
describe "#xpath" do
|
56
|
+
it "should default to tag" do
|
57
|
+
item = HappyMapper::Item.new(:foo, String, :tag => 'foobar')
|
58
|
+
item.xpath.should == 'foobar'
|
59
|
+
end
|
60
|
+
|
61
|
+
it "should prepend with .// if options[:deep] true" do
|
62
|
+
item = HappyMapper::Item.new(:foo, String, :tag => 'foobar', :deep => true)
|
63
|
+
item.xpath.should == './/foobar'
|
64
|
+
end
|
65
|
+
|
66
|
+
it "should prepend namespace if namespace exists" do
|
67
|
+
item = HappyMapper::Item.new(:foo, String, :tag => 'foobar')
|
68
|
+
item.namespace = 'http://example.com'
|
69
|
+
item.xpath.should == 'happymapper:foobar'
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
describe "typecasting" do
|
74
|
+
it "should work with Strings" do
|
75
|
+
item = HappyMapper::Item.new(:foo, String)
|
76
|
+
[21, '21'].each do |a|
|
77
|
+
item.typecast(a).should == '21'
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
it "should work with Integers" do
|
82
|
+
item = HappyMapper::Item.new(:foo, Integer)
|
83
|
+
[21, 21.0, '21'].each do |a|
|
84
|
+
item.typecast(a).should == 21
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
it "should work with Floats" do
|
89
|
+
item = HappyMapper::Item.new(:foo, Float)
|
90
|
+
[21, 21.0, '21'].each do |a|
|
91
|
+
item.typecast(a).should == 21.0
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
it "should work with Times" do
|
96
|
+
item = HappyMapper::Item.new(:foo, Time)
|
97
|
+
item.typecast('2000-01-01 01:01:01.123456').should == Time.local(2000, 1, 1, 1, 1, 1, 123456)
|
98
|
+
end
|
99
|
+
|
100
|
+
it "should work with Dates" do
|
101
|
+
item = HappyMapper::Item.new(:foo, Date)
|
102
|
+
item.typecast('2000-01-01').should == Date.new(2000, 1, 1)
|
103
|
+
end
|
104
|
+
|
105
|
+
it "should work with DateTimes" do
|
106
|
+
item = HappyMapper::Item.new(:foo, DateTime)
|
107
|
+
item.typecast('2000-01-01 00:00:00').should == DateTime.new(2000, 1, 1, 0, 0, 0)
|
108
|
+
end
|
109
|
+
|
110
|
+
it "should work with Boolean" do
|
111
|
+
item = HappyMapper::Item.new(:foo, Boolean)
|
112
|
+
item.typecast('false').should == false
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
@@ -0,0 +1,719 @@
|
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper.rb'
|
2
|
+
require 'pp'
|
3
|
+
require 'uri'
|
4
|
+
|
5
|
+
module Analytics
|
6
|
+
class Property
|
7
|
+
include HappyMapper
|
8
|
+
|
9
|
+
tag 'property'
|
10
|
+
namespace 'http://schemas.google.com/analytics/2009'
|
11
|
+
attribute :name, String
|
12
|
+
attribute :value, String
|
13
|
+
end
|
14
|
+
|
15
|
+
class Entry
|
16
|
+
include HappyMapper
|
17
|
+
|
18
|
+
tag 'entry'
|
19
|
+
element :id, String
|
20
|
+
element :updated, DateTime
|
21
|
+
element :title, String
|
22
|
+
element :table_id, String, :namespace => 'http://schemas.google.com/analytics/2009', :tag => 'tableId'
|
23
|
+
has_many :properties, Property
|
24
|
+
end
|
25
|
+
|
26
|
+
class Feed
|
27
|
+
include HappyMapper
|
28
|
+
|
29
|
+
tag 'feed'
|
30
|
+
element :id, String
|
31
|
+
element :updated, DateTime
|
32
|
+
element :title, String
|
33
|
+
has_many :entries, Entry
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
class Feature
|
38
|
+
include HappyMapper
|
39
|
+
element :name, String, :tag => '.|.//text()'
|
40
|
+
end
|
41
|
+
|
42
|
+
class FeatureBullet
|
43
|
+
include HappyMapper
|
44
|
+
|
45
|
+
tag 'features_bullets'
|
46
|
+
has_many :features, Feature
|
47
|
+
element :bug, String
|
48
|
+
end
|
49
|
+
|
50
|
+
class Product
|
51
|
+
include HappyMapper
|
52
|
+
|
53
|
+
element :title, String
|
54
|
+
has_one :feature_bullets, FeatureBullet
|
55
|
+
end
|
56
|
+
|
57
|
+
module FamilySearch
|
58
|
+
class Person
|
59
|
+
include HappyMapper
|
60
|
+
|
61
|
+
attribute :version, String
|
62
|
+
attribute :modified, Time
|
63
|
+
attribute :id, String
|
64
|
+
end
|
65
|
+
|
66
|
+
class Persons
|
67
|
+
include HappyMapper
|
68
|
+
has_many :person, Person
|
69
|
+
end
|
70
|
+
|
71
|
+
class FamilyTree
|
72
|
+
include HappyMapper
|
73
|
+
|
74
|
+
tag 'familytree'
|
75
|
+
attribute :version, String
|
76
|
+
attribute :status_message, String, :tag => 'statusMessage'
|
77
|
+
attribute :status_code, String, :tag => 'statusCode'
|
78
|
+
has_one :persons, Persons
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
module FedEx
|
83
|
+
class Address
|
84
|
+
include HappyMapper
|
85
|
+
|
86
|
+
tag 'Address'
|
87
|
+
namespace 'http://fedex.com/ws/track/v2'
|
88
|
+
element :city, String, :tag => 'City'
|
89
|
+
element :state, String, :tag => 'StateOrProvinceCode'
|
90
|
+
element :zip, String, :tag => 'PostalCode'
|
91
|
+
element :countrycode, String, :tag => 'CountryCode'
|
92
|
+
element :residential, Boolean, :tag => 'Residential'
|
93
|
+
end
|
94
|
+
|
95
|
+
class Event
|
96
|
+
include HappyMapper
|
97
|
+
|
98
|
+
tag 'Events'
|
99
|
+
namespace 'http://fedex.com/ws/track/v2'
|
100
|
+
element :timestamp, String, :tag => 'Timestamp'
|
101
|
+
element :eventtype, String, :tag => 'EventType'
|
102
|
+
element :eventdescription, String, :tag => 'EventDescription'
|
103
|
+
has_one :address, Address
|
104
|
+
end
|
105
|
+
|
106
|
+
class PackageWeight
|
107
|
+
include HappyMapper
|
108
|
+
|
109
|
+
tag 'PackageWeight'
|
110
|
+
namespace 'http://fedex.com/ws/track/v2'
|
111
|
+
element :units, String, :tag => 'Units'
|
112
|
+
element :value, Integer, :tag => 'Value'
|
113
|
+
end
|
114
|
+
|
115
|
+
class TrackDetails
|
116
|
+
include HappyMapper
|
117
|
+
|
118
|
+
tag 'TrackDetails'
|
119
|
+
namespace 'http://fedex.com/ws/track/v2'
|
120
|
+
element :tracking_number, String, :tag => 'TrackingNumber'
|
121
|
+
element :status_code, String, :tag => 'StatusCode'
|
122
|
+
element :status_desc, String, :tag => 'StatusDescription'
|
123
|
+
element :carrier_code, String, :tag => 'CarrierCode'
|
124
|
+
element :service_info, String, :tag => 'ServiceInfo'
|
125
|
+
has_one :weight, PackageWeight, :tag => 'PackageWeight'
|
126
|
+
element :est_delivery, String, :tag => 'EstimatedDeliveryTimestamp'
|
127
|
+
has_many :events, Event
|
128
|
+
end
|
129
|
+
|
130
|
+
class Notification
|
131
|
+
include HappyMapper
|
132
|
+
|
133
|
+
tag 'Notifications'
|
134
|
+
namespace 'http://fedex.com/ws/track/v2'
|
135
|
+
element :severity, String, :tag => 'Severity'
|
136
|
+
element :source, String, :tag => 'Source'
|
137
|
+
element :code, Integer, :tag => 'Code'
|
138
|
+
element :message, String, :tag => 'Message'
|
139
|
+
element :localized_message, String, :tag => 'LocalizedMessage'
|
140
|
+
end
|
141
|
+
|
142
|
+
class TransactionDetail
|
143
|
+
include HappyMapper
|
144
|
+
|
145
|
+
tag 'TransactionDetail'
|
146
|
+
namespace 'http://fedex.com/ws/track/v2'
|
147
|
+
element :cust_tran_id, String, :tag => 'CustomerTransactionId'
|
148
|
+
end
|
149
|
+
|
150
|
+
class TrackReply
|
151
|
+
include HappyMapper
|
152
|
+
|
153
|
+
tag 'TrackReply'
|
154
|
+
namespace 'http://fedex.com/ws/track/v2'
|
155
|
+
element :highest_severity, String, :tag => 'HighestSeverity'
|
156
|
+
element :more_data, Boolean, :tag => 'MoreData'
|
157
|
+
has_many :notifications, Notification, :tag => 'Notifications'
|
158
|
+
has_many :trackdetails, TrackDetails, :tag => 'TrackDetails'
|
159
|
+
has_one :tran_detail, TransactionDetail, :tab => 'TransactionDetail'
|
160
|
+
end
|
161
|
+
end
|
162
|
+
|
163
|
+
class Place
|
164
|
+
include HappyMapper
|
165
|
+
element :name, String
|
166
|
+
end
|
167
|
+
|
168
|
+
class Radar
|
169
|
+
include HappyMapper
|
170
|
+
has_many :places, Place
|
171
|
+
end
|
172
|
+
|
173
|
+
class Post
|
174
|
+
include HappyMapper
|
175
|
+
|
176
|
+
attribute :href, String
|
177
|
+
attribute :hash, String
|
178
|
+
attribute :description, String
|
179
|
+
attribute :tag, String
|
180
|
+
attribute :time, Time
|
181
|
+
attribute :others, Integer
|
182
|
+
attribute :extended, String
|
183
|
+
end
|
184
|
+
|
185
|
+
class User
|
186
|
+
include HappyMapper
|
187
|
+
|
188
|
+
element :id, Integer
|
189
|
+
element :name, String
|
190
|
+
element :screen_name, String
|
191
|
+
element :location, String
|
192
|
+
element :description, String
|
193
|
+
element :profile_image_url, String
|
194
|
+
element :url, String
|
195
|
+
element :protected, Boolean
|
196
|
+
element :followers_count, Integer
|
197
|
+
end
|
198
|
+
|
199
|
+
class Status
|
200
|
+
include HappyMapper
|
201
|
+
|
202
|
+
element :id, Integer
|
203
|
+
element :text, String
|
204
|
+
element :created_at, Time
|
205
|
+
element :source, String
|
206
|
+
element :truncated, Boolean
|
207
|
+
element :in_reply_to_status_id, Integer
|
208
|
+
element :in_reply_to_user_id, Integer
|
209
|
+
element :favorited, Boolean
|
210
|
+
element :non_existent, String, :tag => 'dummy', :namespace => 'fake'
|
211
|
+
has_one :user, User
|
212
|
+
end
|
213
|
+
|
214
|
+
class CurrentWeather
|
215
|
+
include HappyMapper
|
216
|
+
|
217
|
+
tag 'ob'
|
218
|
+
namespace 'http://www.aws.com/aws'
|
219
|
+
element :temperature, Integer, :tag => 'temp'
|
220
|
+
element :feels_like, Integer, :tag => 'feels-like'
|
221
|
+
element :current_condition, String, :tag => 'current-condition', :attributes => {:icon => String}
|
222
|
+
end
|
223
|
+
|
224
|
+
class Address
|
225
|
+
include HappyMapper
|
226
|
+
|
227
|
+
tag 'address'
|
228
|
+
element :street, String
|
229
|
+
element :postcode, String
|
230
|
+
element :housenumber, String
|
231
|
+
element :city, String
|
232
|
+
element :country, String
|
233
|
+
end
|
234
|
+
|
235
|
+
# for type coercion
|
236
|
+
class ProductGroup < String; end
|
237
|
+
|
238
|
+
module PITA
|
239
|
+
class Item
|
240
|
+
include HappyMapper
|
241
|
+
|
242
|
+
tag 'Item' # if you put class in module you need tag
|
243
|
+
element :asin, String, :tag => 'ASIN'
|
244
|
+
element :detail_page_url, URI, :tag => 'DetailPageURL', :parser => :parse
|
245
|
+
element :manufacturer, String, :tag => 'Manufacturer', :deep => true
|
246
|
+
element :point, String, :tag => 'point', :namespace => 'http://www.georss.org/georss'
|
247
|
+
element :product_group, ProductGroup, :tag => 'ProductGroup', :deep => true, :parser => :new, :raw => true
|
248
|
+
end
|
249
|
+
|
250
|
+
class Items
|
251
|
+
include HappyMapper
|
252
|
+
|
253
|
+
tag 'Items' # if you put class in module you need tag
|
254
|
+
element :total_results, Integer, :tag => 'TotalResults'
|
255
|
+
element :total_pages, Integer, :tag => 'TotalPages'
|
256
|
+
has_many :items, Item
|
257
|
+
end
|
258
|
+
end
|
259
|
+
|
260
|
+
module GitHub
|
261
|
+
class Commit
|
262
|
+
include HappyMapper
|
263
|
+
|
264
|
+
tag "commit"
|
265
|
+
element :url, String
|
266
|
+
element :tree, String
|
267
|
+
element :message, String
|
268
|
+
element :id, String
|
269
|
+
element :'committed-date', Date
|
270
|
+
end
|
271
|
+
end
|
272
|
+
|
273
|
+
module Groups
|
274
|
+
class GroupElement
|
275
|
+
include HappyMapper
|
276
|
+
|
277
|
+
attribute :id, String
|
278
|
+
end
|
279
|
+
|
280
|
+
class Group
|
281
|
+
include HappyMapper
|
282
|
+
|
283
|
+
has_many :GroupElements, GroupElement, :group_tag => "groupelements"
|
284
|
+
end
|
285
|
+
end
|
286
|
+
|
287
|
+
|
288
|
+
describe HappyMapper do
|
289
|
+
|
290
|
+
describe "being included into another class" do
|
291
|
+
before do
|
292
|
+
@klass = Class.new do
|
293
|
+
include HappyMapper
|
294
|
+
|
295
|
+
def self.to_s
|
296
|
+
'Foo'
|
297
|
+
end
|
298
|
+
end
|
299
|
+
end
|
300
|
+
|
301
|
+
it "should set attributes to an array" do
|
302
|
+
@klass.attributes.should == []
|
303
|
+
end
|
304
|
+
|
305
|
+
it "should set @elements to a hash" do
|
306
|
+
@klass.elements.should == []
|
307
|
+
end
|
308
|
+
|
309
|
+
it "should allow adding an attribute" do
|
310
|
+
lambda {
|
311
|
+
@klass.attribute :name, String
|
312
|
+
}.should change(@klass, :attributes)
|
313
|
+
end
|
314
|
+
|
315
|
+
it "should allow adding an attribute containing a dash" do
|
316
|
+
lambda {
|
317
|
+
@klass.attribute :'bar-baz', String
|
318
|
+
}.should change(@klass, :attributes)
|
319
|
+
end
|
320
|
+
|
321
|
+
it "should be able to get all attributes in array" do
|
322
|
+
@klass.attribute :name, String
|
323
|
+
@klass.attributes.size.should == 1
|
324
|
+
end
|
325
|
+
|
326
|
+
it "should allow adding an element" do
|
327
|
+
lambda {
|
328
|
+
@klass.element :name, String
|
329
|
+
}.should change(@klass, :elements)
|
330
|
+
end
|
331
|
+
|
332
|
+
it "should allow adding an element containing a dash" do
|
333
|
+
lambda {
|
334
|
+
@klass.element :'bar-baz', String
|
335
|
+
}.should change(@klass, :elements)
|
336
|
+
|
337
|
+
end
|
338
|
+
|
339
|
+
it "should be able to get all elements in array" do
|
340
|
+
@klass.element(:name, String)
|
341
|
+
@klass.elements.size.should == 1
|
342
|
+
end
|
343
|
+
|
344
|
+
it "should allow has one association" do
|
345
|
+
@klass.has_one(:user, User)
|
346
|
+
element = @klass.elements.first
|
347
|
+
element.name.should == 'user'
|
348
|
+
element.type.should == User
|
349
|
+
element.options[:single] = true
|
350
|
+
end
|
351
|
+
|
352
|
+
it "should allow has many association" do
|
353
|
+
@klass.has_many(:users, User)
|
354
|
+
element = @klass.elements.first
|
355
|
+
element.name.should == 'users'
|
356
|
+
element.type.should == User
|
357
|
+
element.options[:single] = false
|
358
|
+
end
|
359
|
+
|
360
|
+
it "should default tag name to lowercase class" do
|
361
|
+
@klass.tag_name.should == 'foo'
|
362
|
+
end
|
363
|
+
|
364
|
+
it "should default tag name of class in modules to the last constant lowercase" do
|
365
|
+
module Bar; class Baz; include HappyMapper; end; end
|
366
|
+
Bar::Baz.tag_name.should == 'baz'
|
367
|
+
end
|
368
|
+
|
369
|
+
it "should allow setting tag name" do
|
370
|
+
@klass.tag('FooBar')
|
371
|
+
@klass.tag_name.should == 'FooBar'
|
372
|
+
end
|
373
|
+
|
374
|
+
it "should allow setting a namespace" do
|
375
|
+
@klass.namespace(namespace = "foo")
|
376
|
+
@klass.namespace.should == namespace
|
377
|
+
end
|
378
|
+
|
379
|
+
it "should provide #parse" do
|
380
|
+
@klass.should respond_to(:parse)
|
381
|
+
end
|
382
|
+
end
|
383
|
+
|
384
|
+
describe "#attributes" do
|
385
|
+
it "should only return attributes for the current class" do
|
386
|
+
Post.attributes.size.should == 7
|
387
|
+
Status.attributes.size.should == 0
|
388
|
+
end
|
389
|
+
end
|
390
|
+
|
391
|
+
describe "#elements" do
|
392
|
+
it "should only return elements for the current class" do
|
393
|
+
Post.elements.size.should == 0
|
394
|
+
Status.elements.size.should == 10
|
395
|
+
end
|
396
|
+
end
|
397
|
+
|
398
|
+
it "should parse xml attributes into ruby objects" do
|
399
|
+
posts = Post.parse(fixture_file('posts.xml'))
|
400
|
+
posts.size.should == 20
|
401
|
+
first = posts.first
|
402
|
+
first.href.should == 'http://roxml.rubyforge.org/'
|
403
|
+
first.hash.should == '19bba2ab667be03a19f67fb67dc56917'
|
404
|
+
first.description.should == 'ROXML - Ruby Object to XML Mapping Library'
|
405
|
+
first.tag.should == 'ruby xml gems mapping'
|
406
|
+
first.time.should == Time.utc(2008, 8, 9, 5, 24, 20)
|
407
|
+
first.others.should == 56
|
408
|
+
first.extended.should == 'ROXML is a Ruby library designed to make it easier for Ruby developers to work with XML. Using simple annotations, it enables Ruby classes to be custom-mapped to XML. ROXML takes care of the marshalling and unmarshalling of mapped attributes so that developers can focus on building first-class Ruby classes.'
|
409
|
+
end
|
410
|
+
|
411
|
+
it "should parse xml elements to ruby objcts" do
|
412
|
+
statuses = Status.parse(fixture_file('statuses.xml'))
|
413
|
+
statuses.size.should == 20
|
414
|
+
first = statuses.first
|
415
|
+
first.id.should == 882281424
|
416
|
+
first.created_at.should == Time.utc(2008, 8, 9, 5, 38, 12)
|
417
|
+
first.source.should == 'web'
|
418
|
+
first.truncated.should be_false
|
419
|
+
first.in_reply_to_status_id.should == 1234
|
420
|
+
first.in_reply_to_user_id.should == 12345
|
421
|
+
first.favorited.should be_false
|
422
|
+
first.user.id.should == 4243
|
423
|
+
first.user.name.should == 'John Nunemaker'
|
424
|
+
first.user.screen_name.should == 'jnunemaker'
|
425
|
+
first.user.location.should == 'Mishawaka, IN, US'
|
426
|
+
first.user.description.should == 'Loves his wife, ruby, notre dame football and iu basketball'
|
427
|
+
first.user.profile_image_url.should == 'http://s3.amazonaws.com/twitter_production/profile_images/53781608/Photo_75_normal.jpg'
|
428
|
+
first.user.url.should == 'http://addictedtonew.com'
|
429
|
+
first.user.protected.should be_false
|
430
|
+
first.user.followers_count.should == 486
|
431
|
+
end
|
432
|
+
|
433
|
+
it "should parse xml containing the desired element as root node" do
|
434
|
+
address = Address.parse(fixture_file('address.xml'), :single => true)
|
435
|
+
address.street.should == 'Milchstrasse'
|
436
|
+
address.postcode.should == '26131'
|
437
|
+
address.housenumber.should == '23'
|
438
|
+
address.city.should == 'Oldenburg'
|
439
|
+
address.country.should == 'Germany'
|
440
|
+
end
|
441
|
+
|
442
|
+
it "should parse xml with default namespace (amazon)" do
|
443
|
+
file_contents = fixture_file('pita.xml')
|
444
|
+
items = PITA::Items.parse(file_contents, :single => true)
|
445
|
+
items.total_results.should == 22
|
446
|
+
items.total_pages.should == 3
|
447
|
+
first = items.items[0]
|
448
|
+
second = items.items[1]
|
449
|
+
first.asin.should == '0321480791'
|
450
|
+
first.point.should == '38.5351715088 -121.7948684692'
|
451
|
+
first.detail_page_url.should be_a_kind_of(URI)
|
452
|
+
first.detail_page_url.to_s.should == 'http://www.amazon.com/gp/redirect.html%3FASIN=0321480791%26tag=ws%26lcode=xm2%26cID=2025%26ccmID=165953%26location=/o/ASIN/0321480791%253FSubscriptionId=dontbeaswoosh'
|
453
|
+
first.manufacturer.should == 'Addison-Wesley Professional'
|
454
|
+
first.product_group.should == '<ProductGroup>Book</ProductGroup>'
|
455
|
+
second.asin.should == '047022388X'
|
456
|
+
second.manufacturer.should == 'Wrox'
|
457
|
+
end
|
458
|
+
|
459
|
+
it "should parse xml that has attributes of elements" do
|
460
|
+
items = CurrentWeather.parse(fixture_file('current_weather.xml'))
|
461
|
+
first = items[0]
|
462
|
+
first.temperature.should == 51
|
463
|
+
first.feels_like.should == 51
|
464
|
+
first.current_condition.should == 'Sunny'
|
465
|
+
first.current_condition.icon.should == 'http://deskwx.weatherbug.com/images/Forecast/icons/cond007.gif'
|
466
|
+
end
|
467
|
+
|
468
|
+
it "should parse xml with nested elements" do
|
469
|
+
radars = Radar.parse(fixture_file('radar.xml'))
|
470
|
+
first = radars[0]
|
471
|
+
first.places.size.should == 1
|
472
|
+
first.places[0].name.should == 'Store'
|
473
|
+
second = radars[1]
|
474
|
+
second.places.size.should == 0
|
475
|
+
third = radars[2]
|
476
|
+
third.places.size.should == 2
|
477
|
+
third.places[0].name.should == 'Work'
|
478
|
+
third.places[1].name.should == 'Home'
|
479
|
+
end
|
480
|
+
|
481
|
+
it "should parse xml that has elements with dashes" do
|
482
|
+
commit = GitHub::Commit.parse(fixture_file('commit.xml'))
|
483
|
+
commit.message.should == "move commands.rb and helpers.rb into commands/ dir"
|
484
|
+
commit.url.should == "http://github.com/defunkt/github-gem/commit/c26d4ce9807ecf57d3f9eefe19ae64e75bcaaa8b"
|
485
|
+
commit.id.should == "c26d4ce9807ecf57d3f9eefe19ae64e75bcaaa8b"
|
486
|
+
commit.committed_date.should == Date.parse("2008-03-02T16:45:41-08:00")
|
487
|
+
commit.tree.should == "28a1a1ca3e663d35ba8bf07d3f1781af71359b76"
|
488
|
+
end
|
489
|
+
|
490
|
+
it "should parse xml with no namespace" do
|
491
|
+
product = Product.parse(fixture_file('product_no_namespace.xml'), :single => true)
|
492
|
+
product.title.should == "A Title"
|
493
|
+
product.feature_bullets.bug.should == 'This is a bug'
|
494
|
+
product.feature_bullets.features.size.should == 2
|
495
|
+
product.feature_bullets.features[0].name.should == 'This is feature text 1'
|
496
|
+
product.feature_bullets.features[1].name.should == 'This is feature text 2'
|
497
|
+
end
|
498
|
+
|
499
|
+
it "should parse xml with default namespace" do
|
500
|
+
product = Product.parse(fixture_file('product_default_namespace.xml'), :single => true)
|
501
|
+
product.title.should == "A Title"
|
502
|
+
product.feature_bullets.bug.should == 'This is a bug'
|
503
|
+
product.feature_bullets.features.size.should == 2
|
504
|
+
product.feature_bullets.features[0].name.should == 'This is feature text 1'
|
505
|
+
product.feature_bullets.features[1].name.should == 'This is feature text 2'
|
506
|
+
end
|
507
|
+
|
508
|
+
it "should parse xml with single namespace" do
|
509
|
+
product = Product.parse(fixture_file('product_single_namespace.xml'), :single => true)
|
510
|
+
product.title.should == "A Title"
|
511
|
+
product.feature_bullets.bug.should == 'This is a bug'
|
512
|
+
product.feature_bullets.features.size.should == 2
|
513
|
+
product.feature_bullets.features[0].name.should == 'This is feature text 1'
|
514
|
+
product.feature_bullets.features[1].name.should == 'This is feature text 2'
|
515
|
+
end
|
516
|
+
|
517
|
+
it "should parse xml with multiple namespaces" do
|
518
|
+
track = FedEx::TrackReply.parse(fixture_file('multiple_namespaces.xml'))
|
519
|
+
track.highest_severity.should == 'SUCCESS'
|
520
|
+
track.more_data.should be_false
|
521
|
+
notification = track.notifications.first
|
522
|
+
notification.code.should == 0
|
523
|
+
notification.localized_message.should == 'Request was successfully processed.'
|
524
|
+
notification.message.should == 'Request was successfully processed.'
|
525
|
+
notification.severity.should == 'SUCCESS'
|
526
|
+
notification.source.should == 'trck'
|
527
|
+
detail = track.trackdetails.first
|
528
|
+
detail.carrier_code.should == 'FDXG'
|
529
|
+
detail.est_delivery.should == '2009-01-02T00:00:00'
|
530
|
+
detail.service_info.should == 'Ground-Package Returns Program-Domestic'
|
531
|
+
detail.status_code.should == 'OD'
|
532
|
+
detail.status_desc.should == 'On FedEx vehicle for delivery'
|
533
|
+
detail.tracking_number.should == '9611018034267800045212'
|
534
|
+
detail.weight.units.should == 'LB'
|
535
|
+
detail.weight.value.should == 2
|
536
|
+
events = detail.events
|
537
|
+
events.size.should == 10
|
538
|
+
first_event = events[0]
|
539
|
+
first_event.eventdescription.should == 'On FedEx vehicle for delivery'
|
540
|
+
first_event.eventtype.should == 'OD'
|
541
|
+
first_event.timestamp.should == '2009-01-02T06:00:00'
|
542
|
+
first_event.address.city.should == 'WICHITA'
|
543
|
+
first_event.address.countrycode.should == 'US'
|
544
|
+
first_event.address.residential.should be_false
|
545
|
+
first_event.address.state.should == 'KS'
|
546
|
+
first_event.address.zip.should == '67226'
|
547
|
+
last_event = events[-1]
|
548
|
+
last_event.eventdescription.should == 'In FedEx possession'
|
549
|
+
last_event.eventtype.should == 'IP'
|
550
|
+
last_event.timestamp.should == '2008-12-27T09:40:00'
|
551
|
+
last_event.address.city.should == 'LONGWOOD'
|
552
|
+
last_event.address.countrycode.should == 'US'
|
553
|
+
last_event.address.residential.should be_false
|
554
|
+
last_event.address.state.should == 'FL'
|
555
|
+
last_event.address.zip.should == '327506398'
|
556
|
+
track.tran_detail.cust_tran_id.should == '20090102-111321'
|
557
|
+
end
|
558
|
+
|
559
|
+
it "should be able to parse google analytics api xml" do
|
560
|
+
data = Analytics::Feed.parse(fixture_file('analytics.xml'))
|
561
|
+
data.id.should == 'http://www.google.com/analytics/feeds/accounts/nunemaker@gmail.com'
|
562
|
+
data.entries.size.should == 4
|
563
|
+
|
564
|
+
entry = data.entries[0]
|
565
|
+
entry.title.should == 'addictedtonew.com'
|
566
|
+
entry.properties.size.should == 4
|
567
|
+
|
568
|
+
property = entry.properties[0]
|
569
|
+
property.name.should == 'ga:accountId'
|
570
|
+
property.value.should == '85301'
|
571
|
+
end
|
572
|
+
|
573
|
+
it "should allow instantiating with a string" do
|
574
|
+
module StringFoo
|
575
|
+
class Bar
|
576
|
+
include HappyMapper
|
577
|
+
has_many :things, 'StringFoo::Thing'
|
578
|
+
end
|
579
|
+
|
580
|
+
class Thing
|
581
|
+
include HappyMapper
|
582
|
+
end
|
583
|
+
end
|
584
|
+
end
|
585
|
+
|
586
|
+
xit "should parse family search xml" do
|
587
|
+
tree = FamilySearch::FamilyTree.parse(fixture_file('family_tree.xml'))
|
588
|
+
tree.version.should == '1.0.20071213.942'
|
589
|
+
tree.status_message.should == 'OK'
|
590
|
+
tree.status_code.should == '200'
|
591
|
+
# tree.people.size.should == 1
|
592
|
+
# tree.people.first.version.should == '1199378491000'
|
593
|
+
# tree.people.first.modified.should == Time.utc(2008, 1, 3, 16, 41, 31) # 2008-01-03T09:41:31-07:00
|
594
|
+
# tree.people.first.id.should == 'KWQS-BBQ'
|
595
|
+
end
|
596
|
+
|
597
|
+
describe 'nested elements with namespaces' do
|
598
|
+
module Namespaces
|
599
|
+
class Info
|
600
|
+
include HappyMapper
|
601
|
+
namespace 'http://schemas.google.com/analytics/2009'
|
602
|
+
element :category, String
|
603
|
+
end
|
604
|
+
|
605
|
+
class Alert
|
606
|
+
include HappyMapper
|
607
|
+
namespace 'http://schemas.google.com/analytics/2009'
|
608
|
+
|
609
|
+
element :identifier, String
|
610
|
+
element :severity, String, :namespace => false
|
611
|
+
has_one :info, Info
|
612
|
+
end
|
613
|
+
class Distribution
|
614
|
+
include HappyMapper
|
615
|
+
|
616
|
+
tag 'EDXLDistribution'
|
617
|
+
has_one :alert, Alert
|
618
|
+
end
|
619
|
+
end
|
620
|
+
|
621
|
+
def mapping
|
622
|
+
@mapping ||= Namespaces::Distribution.parse(fixture_file('nested_namespaces.xml'))
|
623
|
+
end
|
624
|
+
|
625
|
+
it "should parse elements with inline namespace" do
|
626
|
+
lambda { mapping }.should_not raise_error
|
627
|
+
end
|
628
|
+
|
629
|
+
it "should map elements with inline namespace" do
|
630
|
+
mapping.alert.identifier.should == 'CDC-2006-183'
|
631
|
+
end
|
632
|
+
|
633
|
+
it "should map sub elements of with nested namespace" do
|
634
|
+
mapping.alert.info.category.should == 'Health'
|
635
|
+
end
|
636
|
+
|
637
|
+
it "should map elements without a namespace" do
|
638
|
+
mapping.alert.severity.should == 'Severe'
|
639
|
+
end
|
640
|
+
end
|
641
|
+
|
642
|
+
describe "" do
|
643
|
+
before do
|
644
|
+
@user = User.new
|
645
|
+
end
|
646
|
+
|
647
|
+
it "should provide #to_xml_node" do
|
648
|
+
@user.should respond_to(:to_xml_node)
|
649
|
+
end
|
650
|
+
|
651
|
+
it "should generate XML tags" do
|
652
|
+
@user.to_xml_node.to_s(:indent => false).should == "<user/>"
|
653
|
+
end
|
654
|
+
|
655
|
+
it "should generate XML tags for elements" do
|
656
|
+
@user.name = "Maxim"
|
657
|
+
@user.to_xml_node.to_s(:indent => false).should == "<user><name>Maxim</name></user>"
|
658
|
+
end
|
659
|
+
|
660
|
+
it "should generate XML attributes for attributes" do
|
661
|
+
obj = FamilySearch::Person.new
|
662
|
+
obj.version = "1.2.3.4"
|
663
|
+
obj.to_xml_node.to_s(:indent => false).should == '<person version="1.2.3.4"/>'
|
664
|
+
end
|
665
|
+
|
666
|
+
it "should generate XML for has_one relationship" do
|
667
|
+
obj = FedEx::Event.new
|
668
|
+
obj.address = FedEx::Address.new
|
669
|
+
obj.to_xml_node.to_s(:indent => false).should == '<Events><Address/></Events>'
|
670
|
+
end
|
671
|
+
|
672
|
+
it "should generate XML for has_many relationship" do
|
673
|
+
obj = FeatureBullet.new
|
674
|
+
f1 = Feature.new
|
675
|
+
f1.name = "name1"
|
676
|
+
f2 = Feature.new
|
677
|
+
f2.name = "name2"
|
678
|
+
obj.features = [f1, f2]
|
679
|
+
obj.to_xml_node.to_s(:indent => false).should == '<features_bullets><feature><name>name1</name></feature><feature><name>name2</name></feature></features_bullets>'
|
680
|
+
end
|
681
|
+
|
682
|
+
it "should generate XML for has_many relationship and remove empty elements (without children and attributes)" do
|
683
|
+
obj = FeatureBullet.new
|
684
|
+
f1 = Feature.new
|
685
|
+
f2 = Feature.new
|
686
|
+
obj.features = [f1, f2]
|
687
|
+
obj.to_xml_node.to_s(:indent => false).should == '<features_bullets/>'
|
688
|
+
end
|
689
|
+
|
690
|
+
it "should generate helper tag for has_many if :group_tag option is true" do
|
691
|
+
obj = Groups::Group.new
|
692
|
+
ge1 = Groups::GroupElement.new
|
693
|
+
ge1.id = "id1"
|
694
|
+
ge2 = Groups::GroupElement.new
|
695
|
+
ge2.id = "id2"
|
696
|
+
obj.GroupElements = [ge1, ge2]
|
697
|
+
obj.to_xml_node.to_s(:indent => false).should == '<group><groupelements><groupelement id="id1"/><groupelement id="id2"/></groupelements></group>'
|
698
|
+
end
|
699
|
+
|
700
|
+
it "should generate helper tag for has_many if :group_tag option is true and remove empty elements (without children and attributes)" do
|
701
|
+
obj = Groups::Group.new
|
702
|
+
ge1 = Groups::GroupElement.new
|
703
|
+
ge2 = Groups::GroupElement.new
|
704
|
+
obj.GroupElements = [ge1, ge2]
|
705
|
+
obj.to_xml_node.to_s(:indent => false).should == '<group/>'
|
706
|
+
end
|
707
|
+
|
708
|
+
it "should provide #to_xml" do
|
709
|
+
@user.should respond_to(:to_xml)
|
710
|
+
end
|
711
|
+
|
712
|
+
it "should generate XML document" do
|
713
|
+
@user.name = "Maxim"
|
714
|
+
@user.to_xml.should == %Q(<?xml version="1.0" encoding="UTF-8"?>\n<user>\n <name>Maxim</name>\n</user>\n)
|
715
|
+
end
|
716
|
+
|
717
|
+
end
|
718
|
+
|
719
|
+
end
|