woahdae-consumer 0.8.1
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +4 -0
- data/LICENSE +20 -0
- data/Manifest.txt +73 -0
- data/PostInstall.txt +8 -0
- data/README.rdoc +53 -0
- data/Rakefile +30 -0
- data/app_generators/consumer/USAGE +14 -0
- data/app_generators/consumer/consumer_generator.rb +89 -0
- data/app_generators/consumer/templates/LICENSE +20 -0
- data/app_generators/consumer/templates/README.rdoc +3 -0
- data/app_generators/consumer/templates/Rakefile +57 -0
- data/app_generators/consumer/templates/TODO +4 -0
- data/app_generators/consumer/templates/config/config.yml +2 -0
- data/app_generators/consumer/templates/config/config.yml.sample +1 -0
- data/app_generators/consumer/templates/lib/base.rb +6 -0
- data/app_generators/consumer/templates/rails/init.rb +1 -0
- data/app_generators/consumer/templates/script/destroy +14 -0
- data/app_generators/consumer/templates/script/generate +14 -0
- data/app_generators/consumer/templates/spec/spec_helper.rb +11 -0
- data/bin/consumer +17 -0
- data/config/website.yml.sample +2 -0
- data/consumer.gemspec +48 -0
- data/consumer_generators/request/USAGE +25 -0
- data/consumer_generators/request/request_generator.rb +94 -0
- data/consumer_generators/request/templates/lib/request.rb +55 -0
- data/consumer_generators/request/templates/lib/response.rb +12 -0
- data/consumer_generators/request/templates/spec/request_spec.rb +27 -0
- data/consumer_generators/request/templates/spec/response_spec.rb +10 -0
- data/consumer_generators/request/templates/spec/xml/response.xml +0 -0
- data/examples/active_record/README.txt +1 -0
- data/examples/active_record/ar_spec.rb +33 -0
- data/examples/active_record/database.sqlite +0 -0
- data/examples/active_record/environment.rb +15 -0
- data/examples/active_record/migration.rb +21 -0
- data/examples/active_record/models/book.rb +13 -0
- data/examples/active_record/models/contributor.rb +12 -0
- data/examples/active_record/xml/book.xml +6 -0
- data/examples/active_record/xml/book_with_contributors.xml +11 -0
- data/examples/active_record/xml/contributor.xml +3 -0
- data/examples/active_record/xml/contributor_with_books.xml +19 -0
- data/examples/shipping/environment.rb +3 -0
- data/examples/shipping/rate.rb +15 -0
- data/examples/shipping/shipping.yml.sample +8 -0
- data/examples/shipping/shipping_spec.rb +27 -0
- data/examples/shipping/ups_rate_request.rb +182 -0
- data/examples/shipping/ups_rate_response.xml +340 -0
- data/lib/consumer/helper.rb +111 -0
- data/lib/consumer/mapping.rb +184 -0
- data/lib/consumer/request.rb +280 -0
- data/lib/consumer.rb +28 -0
- data/script/console +10 -0
- data/script/destroy +14 -0
- data/script/generate +14 -0
- data/script/txt2html +71 -0
- data/spec/helper_spec.rb +136 -0
- data/spec/mapping_spec.rb +94 -0
- data/spec/request_spec.rb +75 -0
- data/spec/spec.opts +1 -0
- data/spec/spec_helper.rb +12 -0
- data/spec/xml/rate_response.xml +14 -0
- data/spec/xml/rate_response_error.xml +35 -0
- data/tasks/rspec.rake +21 -0
- data/test/test_consumer_generator.rb +68 -0
- data/test/test_generator_helper.rb +29 -0
- data/website/index.html +11 -0
- data/website/index.txt +81 -0
- data/website/javascripts/rounded_corners_lite.inc.js +285 -0
- data/website/stylesheets/screen.css +159 -0
- data/website/template.html.erb +50 -0
- metadata +180 -0
@@ -0,0 +1,340 @@
|
|
1
|
+
<?xml version="1.0"?>
|
2
|
+
<RatingServiceSelectionResponse>
|
3
|
+
<Response>
|
4
|
+
<TransactionReference>
|
5
|
+
<CustomerContext>RatingandService</CustomerContext>
|
6
|
+
<XpciVersion>1.0001</XpciVersion>
|
7
|
+
</TransactionReference>
|
8
|
+
<ResponseStatusCode>1</ResponseStatusCode>
|
9
|
+
<ResponseStatusDescription>Success</ResponseStatusDescription>
|
10
|
+
</Response>
|
11
|
+
<RatedShipment>
|
12
|
+
<Service>
|
13
|
+
<Code>03</Code>
|
14
|
+
</Service>
|
15
|
+
<RatedShipmentWarning>Yourinvoicemayvaryfromthedisplayedreferencerates</RatedShipmentWarning>
|
16
|
+
<BillingWeight>
|
17
|
+
<UnitOfMeasurement>
|
18
|
+
<Code>LBS</Code>
|
19
|
+
</UnitOfMeasurement>
|
20
|
+
<Weight>5.0</Weight>
|
21
|
+
</BillingWeight>
|
22
|
+
<TransportationCharges>
|
23
|
+
<CurrencyCode>USD</CurrencyCode>
|
24
|
+
<MonetaryValue>5.03</MonetaryValue>
|
25
|
+
</TransportationCharges>
|
26
|
+
<ServiceOptionsCharges>
|
27
|
+
<CurrencyCode>USD</CurrencyCode>
|
28
|
+
<MonetaryValue>0.00</MonetaryValue>
|
29
|
+
</ServiceOptionsCharges>
|
30
|
+
<TotalCharges>
|
31
|
+
<CurrencyCode>USD</CurrencyCode>
|
32
|
+
<MonetaryValue>5.03</MonetaryValue>
|
33
|
+
</TotalCharges>
|
34
|
+
<GuaranteedDaysToDelivery/>
|
35
|
+
<ScheduledDeliveryTime/>
|
36
|
+
<RatedPackage>
|
37
|
+
<TransportationCharges>
|
38
|
+
<CurrencyCode>USD</CurrencyCode>
|
39
|
+
<MonetaryValue>5.03</MonetaryValue>
|
40
|
+
</TransportationCharges>
|
41
|
+
<ServiceOptionsCharges>
|
42
|
+
<CurrencyCode>USD</CurrencyCode>
|
43
|
+
<MonetaryValue>0.00</MonetaryValue>
|
44
|
+
</ServiceOptionsCharges>
|
45
|
+
<TotalCharges>
|
46
|
+
<CurrencyCode>USD</CurrencyCode>
|
47
|
+
<MonetaryValue>5.03</MonetaryValue>
|
48
|
+
</TotalCharges>
|
49
|
+
<Weight>5.0</Weight>
|
50
|
+
<BillingWeight>
|
51
|
+
<UnitOfMeasurement>
|
52
|
+
<Code>LBS</Code>
|
53
|
+
</UnitOfMeasurement>
|
54
|
+
<Weight>5.0</Weight>
|
55
|
+
</BillingWeight>
|
56
|
+
</RatedPackage>
|
57
|
+
</RatedShipment>
|
58
|
+
<RatedShipment>
|
59
|
+
<Service>
|
60
|
+
<Code>12</Code>
|
61
|
+
</Service>
|
62
|
+
<RatedShipmentWarning>Yourinvoicemayvaryfromthedisplayedreferencerates</RatedShipmentWarning>
|
63
|
+
<BillingWeight>
|
64
|
+
<UnitOfMeasurement>
|
65
|
+
<Code>LBS</Code>
|
66
|
+
</UnitOfMeasurement>
|
67
|
+
<Weight>5.0</Weight>
|
68
|
+
</BillingWeight>
|
69
|
+
<TransportationCharges>
|
70
|
+
<CurrencyCode>USD</CurrencyCode>
|
71
|
+
<MonetaryValue>9.12</MonetaryValue>
|
72
|
+
</TransportationCharges>
|
73
|
+
<ServiceOptionsCharges>
|
74
|
+
<CurrencyCode>USD</CurrencyCode>
|
75
|
+
<MonetaryValue>0.00</MonetaryValue>
|
76
|
+
</ServiceOptionsCharges>
|
77
|
+
<TotalCharges>
|
78
|
+
<CurrencyCode>USD</CurrencyCode>
|
79
|
+
<MonetaryValue>9.12</MonetaryValue>
|
80
|
+
</TotalCharges>
|
81
|
+
<GuaranteedDaysToDelivery>3</GuaranteedDaysToDelivery>
|
82
|
+
<ScheduledDeliveryTime/>
|
83
|
+
<RatedPackage>
|
84
|
+
<TransportationCharges>
|
85
|
+
<CurrencyCode>USD</CurrencyCode>
|
86
|
+
<MonetaryValue>9.12</MonetaryValue>
|
87
|
+
</TransportationCharges>
|
88
|
+
<ServiceOptionsCharges>
|
89
|
+
<CurrencyCode>USD</CurrencyCode>
|
90
|
+
<MonetaryValue>0.00</MonetaryValue>
|
91
|
+
</ServiceOptionsCharges>
|
92
|
+
<TotalCharges>
|
93
|
+
<CurrencyCode>USD</CurrencyCode>
|
94
|
+
<MonetaryValue>9.12</MonetaryValue>
|
95
|
+
</TotalCharges>
|
96
|
+
<Weight>5.0</Weight>
|
97
|
+
<BillingWeight>
|
98
|
+
<UnitOfMeasurement>
|
99
|
+
<Code>LBS</Code>
|
100
|
+
</UnitOfMeasurement>
|
101
|
+
<Weight>5.0</Weight>
|
102
|
+
</BillingWeight>
|
103
|
+
</RatedPackage>
|
104
|
+
</RatedShipment>
|
105
|
+
<RatedShipment>
|
106
|
+
<Service>
|
107
|
+
<Code>59</Code>
|
108
|
+
</Service>
|
109
|
+
<RatedShipmentWarning>Yourinvoicemayvaryfromthedisplayedreferencerates</RatedShipmentWarning>
|
110
|
+
<BillingWeight>
|
111
|
+
<UnitOfMeasurement>
|
112
|
+
<Code>LBS</Code>
|
113
|
+
</UnitOfMeasurement>
|
114
|
+
<Weight>5.0</Weight>
|
115
|
+
</BillingWeight>
|
116
|
+
<TransportationCharges>
|
117
|
+
<CurrencyCode>USD</CurrencyCode>
|
118
|
+
<MonetaryValue>14.91</MonetaryValue>
|
119
|
+
</TransportationCharges>
|
120
|
+
<ServiceOptionsCharges>
|
121
|
+
<CurrencyCode>USD</CurrencyCode>
|
122
|
+
<MonetaryValue>0.00</MonetaryValue>
|
123
|
+
</ServiceOptionsCharges>
|
124
|
+
<TotalCharges>
|
125
|
+
<CurrencyCode>USD</CurrencyCode>
|
126
|
+
<MonetaryValue>14.91</MonetaryValue>
|
127
|
+
</TotalCharges>
|
128
|
+
<GuaranteedDaysToDelivery>2</GuaranteedDaysToDelivery>
|
129
|
+
<ScheduledDeliveryTime>10:30A.M.</ScheduledDeliveryTime>
|
130
|
+
<RatedPackage>
|
131
|
+
<TransportationCharges>
|
132
|
+
<CurrencyCode>USD</CurrencyCode>
|
133
|
+
<MonetaryValue>14.91</MonetaryValue>
|
134
|
+
</TransportationCharges>
|
135
|
+
<ServiceOptionsCharges>
|
136
|
+
<CurrencyCode>USD</CurrencyCode>
|
137
|
+
<MonetaryValue>0.00</MonetaryValue>
|
138
|
+
</ServiceOptionsCharges>
|
139
|
+
<TotalCharges>
|
140
|
+
<CurrencyCode>USD</CurrencyCode>
|
141
|
+
<MonetaryValue>14.91</MonetaryValue>
|
142
|
+
</TotalCharges>
|
143
|
+
<Weight>5.0</Weight>
|
144
|
+
<BillingWeight>
|
145
|
+
<UnitOfMeasurement>
|
146
|
+
<Code>LBS</Code>
|
147
|
+
</UnitOfMeasurement>
|
148
|
+
<Weight>5.0</Weight>
|
149
|
+
</BillingWeight>
|
150
|
+
</RatedPackage>
|
151
|
+
</RatedShipment>
|
152
|
+
<RatedShipment>
|
153
|
+
<Service>
|
154
|
+
<Code>02</Code>
|
155
|
+
</Service>
|
156
|
+
<RatedShipmentWarning>Yourinvoicemayvaryfromthedisplayedreferencerates</RatedShipmentWarning>
|
157
|
+
<BillingWeight>
|
158
|
+
<UnitOfMeasurement>
|
159
|
+
<Code>LBS</Code>
|
160
|
+
</UnitOfMeasurement>
|
161
|
+
<Weight>5.0</Weight>
|
162
|
+
</BillingWeight>
|
163
|
+
<TransportationCharges>
|
164
|
+
<CurrencyCode>USD</CurrencyCode>
|
165
|
+
<MonetaryValue>12.79</MonetaryValue>
|
166
|
+
</TransportationCharges>
|
167
|
+
<ServiceOptionsCharges>
|
168
|
+
<CurrencyCode>USD</CurrencyCode>
|
169
|
+
<MonetaryValue>0.00</MonetaryValue>
|
170
|
+
</ServiceOptionsCharges>
|
171
|
+
<TotalCharges>
|
172
|
+
<CurrencyCode>USD</CurrencyCode>
|
173
|
+
<MonetaryValue>12.79</MonetaryValue>
|
174
|
+
</TotalCharges>
|
175
|
+
<GuaranteedDaysToDelivery>2</GuaranteedDaysToDelivery>
|
176
|
+
<ScheduledDeliveryTime/>
|
177
|
+
<RatedPackage>
|
178
|
+
<TransportationCharges>
|
179
|
+
<CurrencyCode>USD</CurrencyCode>
|
180
|
+
<MonetaryValue>12.79</MonetaryValue>
|
181
|
+
</TransportationCharges>
|
182
|
+
<ServiceOptionsCharges>
|
183
|
+
<CurrencyCode>USD</CurrencyCode>
|
184
|
+
<MonetaryValue>0.00</MonetaryValue>
|
185
|
+
</ServiceOptionsCharges>
|
186
|
+
<TotalCharges>
|
187
|
+
<CurrencyCode>USD</CurrencyCode>
|
188
|
+
<MonetaryValue>12.79</MonetaryValue>
|
189
|
+
</TotalCharges>
|
190
|
+
<Weight>5.0</Weight>
|
191
|
+
<BillingWeight>
|
192
|
+
<UnitOfMeasurement>
|
193
|
+
<Code>LBS</Code>
|
194
|
+
</UnitOfMeasurement>
|
195
|
+
<Weight>5.0</Weight>
|
196
|
+
</BillingWeight>
|
197
|
+
</RatedPackage>
|
198
|
+
</RatedShipment>
|
199
|
+
<RatedShipment>
|
200
|
+
<Service>
|
201
|
+
<Code>13</Code>
|
202
|
+
</Service>
|
203
|
+
<RatedShipmentWarning>Yourinvoicemayvaryfromthedisplayedreferencerates</RatedShipmentWarning>
|
204
|
+
<BillingWeight>
|
205
|
+
<UnitOfMeasurement>
|
206
|
+
<Code>LBS</Code>
|
207
|
+
</UnitOfMeasurement>
|
208
|
+
<Weight>5.0</Weight>
|
209
|
+
</BillingWeight>
|
210
|
+
<TransportationCharges>
|
211
|
+
<CurrencyCode>USD</CurrencyCode>
|
212
|
+
<MonetaryValue>23.71</MonetaryValue>
|
213
|
+
</TransportationCharges>
|
214
|
+
<ServiceOptionsCharges>
|
215
|
+
<CurrencyCode>USD</CurrencyCode>
|
216
|
+
<MonetaryValue>0.00</MonetaryValue>
|
217
|
+
</ServiceOptionsCharges>
|
218
|
+
<TotalCharges>
|
219
|
+
<CurrencyCode>USD</CurrencyCode>
|
220
|
+
<MonetaryValue>23.71</MonetaryValue>
|
221
|
+
</TotalCharges>
|
222
|
+
<GuaranteedDaysToDelivery>1</GuaranteedDaysToDelivery>
|
223
|
+
<ScheduledDeliveryTime>3:00P.M.</ScheduledDeliveryTime>
|
224
|
+
<RatedPackage>
|
225
|
+
<TransportationCharges>
|
226
|
+
<CurrencyCode>USD</CurrencyCode>
|
227
|
+
<MonetaryValue>23.71</MonetaryValue>
|
228
|
+
</TransportationCharges>
|
229
|
+
<ServiceOptionsCharges>
|
230
|
+
<CurrencyCode>USD</CurrencyCode>
|
231
|
+
<MonetaryValue>0.00</MonetaryValue>
|
232
|
+
</ServiceOptionsCharges>
|
233
|
+
<TotalCharges>
|
234
|
+
<CurrencyCode>USD</CurrencyCode>
|
235
|
+
<MonetaryValue>23.71</MonetaryValue>
|
236
|
+
</TotalCharges>
|
237
|
+
<Weight>5.0</Weight>
|
238
|
+
<BillingWeight>
|
239
|
+
<UnitOfMeasurement>
|
240
|
+
<Code>LBS</Code>
|
241
|
+
</UnitOfMeasurement>
|
242
|
+
<Weight>5.0</Weight>
|
243
|
+
</BillingWeight>
|
244
|
+
</RatedPackage>
|
245
|
+
</RatedShipment>
|
246
|
+
<RatedShipment>
|
247
|
+
<Service>
|
248
|
+
<Code>14</Code>
|
249
|
+
</Service>
|
250
|
+
<RatedShipmentWarning>Yourinvoicemayvaryfromthedisplayedreferencerates</RatedShipmentWarning>
|
251
|
+
<BillingWeight>
|
252
|
+
<UnitOfMeasurement>
|
253
|
+
<Code>LBS</Code>
|
254
|
+
</UnitOfMeasurement>
|
255
|
+
<Weight>5.0</Weight>
|
256
|
+
</BillingWeight>
|
257
|
+
<TransportationCharges>
|
258
|
+
<CurrencyCode>USD</CurrencyCode>
|
259
|
+
<MonetaryValue>64.25</MonetaryValue>
|
260
|
+
</TransportationCharges>
|
261
|
+
<ServiceOptionsCharges>
|
262
|
+
<CurrencyCode>USD</CurrencyCode>
|
263
|
+
<MonetaryValue>0.00</MonetaryValue>
|
264
|
+
</ServiceOptionsCharges>
|
265
|
+
<TotalCharges>
|
266
|
+
<CurrencyCode>USD</CurrencyCode>
|
267
|
+
<MonetaryValue>64.25</MonetaryValue>
|
268
|
+
</TotalCharges>
|
269
|
+
<GuaranteedDaysToDelivery>1</GuaranteedDaysToDelivery>
|
270
|
+
<ScheduledDeliveryTime>8:00A.M.</ScheduledDeliveryTime>
|
271
|
+
<RatedPackage>
|
272
|
+
<TransportationCharges>
|
273
|
+
<CurrencyCode>USD</CurrencyCode>
|
274
|
+
<MonetaryValue>64.25</MonetaryValue>
|
275
|
+
</TransportationCharges>
|
276
|
+
<ServiceOptionsCharges>
|
277
|
+
<CurrencyCode>USD</CurrencyCode>
|
278
|
+
<MonetaryValue>0.00</MonetaryValue>
|
279
|
+
</ServiceOptionsCharges>
|
280
|
+
<TotalCharges>
|
281
|
+
<CurrencyCode>USD</CurrencyCode>
|
282
|
+
<MonetaryValue>64.25</MonetaryValue>
|
283
|
+
</TotalCharges>
|
284
|
+
<Weight>5.0</Weight>
|
285
|
+
<BillingWeight>
|
286
|
+
<UnitOfMeasurement>
|
287
|
+
<Code>LBS</Code>
|
288
|
+
</UnitOfMeasurement>
|
289
|
+
<Weight>5.0</Weight>
|
290
|
+
</BillingWeight>
|
291
|
+
</RatedPackage>
|
292
|
+
</RatedShipment>
|
293
|
+
<RatedShipment>
|
294
|
+
<Service>
|
295
|
+
<Code>01</Code>
|
296
|
+
</Service>
|
297
|
+
<RatedShipmentWarning>Yourinvoicemayvaryfromthedisplayedreferencerates</RatedShipmentWarning>
|
298
|
+
<BillingWeight>
|
299
|
+
<UnitOfMeasurement>
|
300
|
+
<Code>LBS</Code>
|
301
|
+
</UnitOfMeasurement>
|
302
|
+
<Weight>5.0</Weight>
|
303
|
+
</BillingWeight>
|
304
|
+
<TransportationCharges>
|
305
|
+
<CurrencyCode>USD</CurrencyCode>
|
306
|
+
<MonetaryValue>27.63</MonetaryValue>
|
307
|
+
</TransportationCharges>
|
308
|
+
<ServiceOptionsCharges>
|
309
|
+
<CurrencyCode>USD</CurrencyCode>
|
310
|
+
<MonetaryValue>0.00</MonetaryValue>
|
311
|
+
</ServiceOptionsCharges>
|
312
|
+
<TotalCharges>
|
313
|
+
<CurrencyCode>USD</CurrencyCode>
|
314
|
+
<MonetaryValue>27.63</MonetaryValue>
|
315
|
+
</TotalCharges>
|
316
|
+
<GuaranteedDaysToDelivery>1</GuaranteedDaysToDelivery>
|
317
|
+
<ScheduledDeliveryTime>10:30A.M.</ScheduledDeliveryTime>
|
318
|
+
<RatedPackage>
|
319
|
+
<TransportationCharges>
|
320
|
+
<CurrencyCode>USD</CurrencyCode>
|
321
|
+
<MonetaryValue>27.63</MonetaryValue>
|
322
|
+
</TransportationCharges>
|
323
|
+
<ServiceOptionsCharges>
|
324
|
+
<CurrencyCode>USD</CurrencyCode>
|
325
|
+
<MonetaryValue>0.00</MonetaryValue>
|
326
|
+
</ServiceOptionsCharges>
|
327
|
+
<TotalCharges>
|
328
|
+
<CurrencyCode>USD</CurrencyCode>
|
329
|
+
<MonetaryValue>27.63</MonetaryValue>
|
330
|
+
</TotalCharges>
|
331
|
+
<Weight>5.0</Weight>
|
332
|
+
<BillingWeight>
|
333
|
+
<UnitOfMeasurement>
|
334
|
+
<Code>LBS</Code>
|
335
|
+
</UnitOfMeasurement>
|
336
|
+
<Weight>5.0</Weight>
|
337
|
+
</BillingWeight>
|
338
|
+
</RatedPackage>
|
339
|
+
</RatedShipment>
|
340
|
+
</RatingServiceSelectionResponse>
|
@@ -0,0 +1,111 @@
|
|
1
|
+
module Consumer::Helper
|
2
|
+
# if you pass in a newline-less glob of xml it'll return an indented copy
|
3
|
+
# for improved readability.
|
4
|
+
def self.tidy(xml)
|
5
|
+
xml = xml.clone # avoid modifying @response_xml due to pass by reference
|
6
|
+
|
7
|
+
# remove all formatting to start from a common base
|
8
|
+
xml.gsub!(/\>[\t\n\r ]*\</, "><")
|
9
|
+
# replace empty tag pairs with <tag/>
|
10
|
+
xml.gsub!(/\<(\w*?)\>\<\/\1\>/, "<\\1/>")
|
11
|
+
# add in newlines after >, and sometimse before <
|
12
|
+
xml.gsub!(/\>\</,">\n<")
|
13
|
+
|
14
|
+
declaration = /\<\?xml/
|
15
|
+
start_tag = /\<[^\/]+?\>[\n\t\r ]+/
|
16
|
+
end_tag = /^[\t ]*\<\//
|
17
|
+
|
18
|
+
## add appropriate spacing before each newline.
|
19
|
+
tab = 0
|
20
|
+
siblings = false
|
21
|
+
first_tag = true
|
22
|
+
return xml.collect do |line|
|
23
|
+
next line if line =~ declaration
|
24
|
+
|
25
|
+
# calculate the indentation.
|
26
|
+
# In general we want to add spacing if it's a start tag or leaf node, and
|
27
|
+
# remove spacing if it's an end tag. The only times we don't want to add
|
28
|
+
# spacing is if it's the very first node or the previous node was a sibling
|
29
|
+
# instead of a parent.
|
30
|
+
if line =~ end_tag
|
31
|
+
tab -= 1
|
32
|
+
else
|
33
|
+
tab += 1 unless first_tag || siblings
|
34
|
+
end
|
35
|
+
|
36
|
+
# if the line is a start tag, the next lines will no longer be siblings
|
37
|
+
siblings = line =~ start_tag ? false : true
|
38
|
+
first_tag = false
|
39
|
+
|
40
|
+
# return line with appropriate amount of preceding spaces #
|
41
|
+
line = " " * (tab > 0 ? tab : 0) + line
|
42
|
+
end.join << "\n"
|
43
|
+
end
|
44
|
+
|
45
|
+
# returns a copy of the xml without empty nodes. Also removes internal
|
46
|
+
# (non-leaf) nodes that only contain empty leaves. Nodes containing only
|
47
|
+
# whitespace characters (space, newline, tab, and return) are considered empty.
|
48
|
+
def self.compact_xml(xml)
|
49
|
+
old_xml = xml
|
50
|
+
loop do
|
51
|
+
new_xml = old_xml.gsub(/\<(\w*?)\>[ \t\r\n]*\<\/\1\>\n?/, "")
|
52
|
+
if old_xml == new_xml # nothing was changed
|
53
|
+
return new_xml
|
54
|
+
else # something changed, so we'll go through it again
|
55
|
+
old_xml = new_xml
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
# returns a hash of defaults if +self.yaml_defaults+ is defined and the file
|
61
|
+
# defined there exists, empty hash otherwise.
|
62
|
+
#
|
63
|
+
# Also takes a namespace, i.e. a sub-hash, and when given a namespace it also
|
64
|
+
# enables a global namespace called 'all'. Thus if you had the yaml:
|
65
|
+
#
|
66
|
+
# <pre>
|
67
|
+
# all:
|
68
|
+
# my_name: Buster
|
69
|
+
# greetings:
|
70
|
+
# hello: world
|
71
|
+
# other:
|
72
|
+
# irrelevant: data
|
73
|
+
# </pre>
|
74
|
+
#
|
75
|
+
# a namespace of 'greetings' would return the hash:
|
76
|
+
#
|
77
|
+
# <code>
|
78
|
+
# {"my_name" => "Buster", "hello" => "world"}
|
79
|
+
# </code>
|
80
|
+
#
|
81
|
+
# You don't have to use the global namespace, but if you do, it will be included
|
82
|
+
# everywhere.
|
83
|
+
def self.hash_from_yaml(base_path, file, namespace = nil)
|
84
|
+
begin
|
85
|
+
hash = (base_path && file) ? YAML.load(File.read(File.join(base_path, file))) : {}
|
86
|
+
rescue => e
|
87
|
+
raise ArgumentError, "YAML load error: #{e.message}"
|
88
|
+
end
|
89
|
+
|
90
|
+
return {} if !hash
|
91
|
+
|
92
|
+
if namespace
|
93
|
+
global = hash["all"] || {}
|
94
|
+
namespaced_hash = hash[namespace] || {}
|
95
|
+
hash = global.merge(namespaced_hash)
|
96
|
+
end
|
97
|
+
|
98
|
+
return hash
|
99
|
+
end
|
100
|
+
|
101
|
+
def self.http_from_url(url)
|
102
|
+
uri = URI.parse url
|
103
|
+
http = Net::HTTP.new uri.host, uri.port
|
104
|
+
if uri.port == 443
|
105
|
+
http.use_ssl = true
|
106
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
107
|
+
end
|
108
|
+
return http, uri
|
109
|
+
end
|
110
|
+
|
111
|
+
end
|
@@ -0,0 +1,184 @@
|
|
1
|
+
module Consumer::Mapping
|
2
|
+
def self.included(base)
|
3
|
+
base.extend ClassMethods
|
4
|
+
end
|
5
|
+
|
6
|
+
### our lone instance method ###
|
7
|
+
|
8
|
+
##
|
9
|
+
# Same as doing:
|
10
|
+
#
|
11
|
+
# <code>self.association(s) = Association.from_xml(xml)</code>
|
12
|
+
# === Behaviors
|
13
|
+
# * sets the association to a call to Klass.from_xml
|
14
|
+
# === Parameters
|
15
|
+
# [+xml+] String of xml
|
16
|
+
# [+association+] The association name (i.e. self.something)
|
17
|
+
# [+klass+] The association class (i.e. Something.from_xml).
|
18
|
+
# Defaults to singular, capitalized +association+.
|
19
|
+
# === Returns
|
20
|
+
# Nothing in particular
|
21
|
+
def association_from_xml(xml, association, klass = nil)
|
22
|
+
klass ||= association.to_s.capitalize.singularize.constantize
|
23
|
+
|
24
|
+
association_instance = klass.from_xml(xml)
|
25
|
+
return if association_instance.nil?
|
26
|
+
|
27
|
+
self.send(association.to_s + "=", association_instance)
|
28
|
+
end
|
29
|
+
|
30
|
+
module ClassMethods
|
31
|
+
# Creates a new mapping hash in self.maps
|
32
|
+
# === Parameters
|
33
|
+
# The parameters here are used to add a new mapping hash to self.maps, which
|
34
|
+
# in turn is used by from_xml_via_map to instantiate new objects
|
35
|
+
# [+first_or_all+] If +:all+, from_xml_via_map will return an array instead
|
36
|
+
# of a single instance (i.e. sets map[:all] to true)
|
37
|
+
# [+base_path+] A fully qualified xpath, such as //SomethingResponse/bah.
|
38
|
+
# Also, uniquely identifies the map for a particular xml
|
39
|
+
# response in the case of multiple maps.
|
40
|
+
# [+registry+] A hash of :attribute => 'xpath' pairs. Xpaths are
|
41
|
+
# relative to +base_path+, but fully qualified xpaths are
|
42
|
+
# also valid.
|
43
|
+
#
|
44
|
+
# For example, if the base path was //Response/Bah and the
|
45
|
+
# registry was {:foo => "FooElm"}, then from_xml_via_map
|
46
|
+
# will set instance.foo to the value at
|
47
|
+
# //Response/Bah/FooElm in the xml. However, if you set
|
48
|
+
# {:foo => "//Response/Woot/Ack"}, then it will pull the
|
49
|
+
# value from //Response/Woot/Ack (not
|
50
|
+
# //Response/Bah/Response/Woot/Ack).
|
51
|
+
# [+options+] Valid options are:
|
52
|
+
# * +:include+ - sets map[:associations], which is an
|
53
|
+
# array of parameters to association_from_xml
|
54
|
+
# [+block+] In from_xml_via_map this gets called with the new
|
55
|
+
# instance as the last step of instantiation.
|
56
|
+
# === Returns
|
57
|
+
# The newly created map
|
58
|
+
# === Raises
|
59
|
+
# * RuntimeError if the base path is already defined in another mapping
|
60
|
+
# in the class
|
61
|
+
def map(first_or_all, base_path, registry, options = {}, &block)
|
62
|
+
if self.maps.find {|m| m[:base_path] == base_path}
|
63
|
+
raise "Base path exists: #{base_path}"
|
64
|
+
end
|
65
|
+
|
66
|
+
map = {
|
67
|
+
:all => first_or_all == :all ? true : false,
|
68
|
+
:base_path => base_path,
|
69
|
+
:registry => registry,
|
70
|
+
:associations => [*options[:include]].compact,
|
71
|
+
:block => block
|
72
|
+
}
|
73
|
+
self.maps << map
|
74
|
+
|
75
|
+
return map
|
76
|
+
end
|
77
|
+
|
78
|
+
# Returns @maps or []
|
79
|
+
def maps
|
80
|
+
@maps ||= []
|
81
|
+
end
|
82
|
+
|
83
|
+
# Pulls attributes from the xml using xpaths defined in the mapping whose
|
84
|
+
# base path matches the xml, and instantiates a new object with those attrs.
|
85
|
+
# === Behaviors
|
86
|
+
# * If multiple elements match the base path and map[:all] is true, it will
|
87
|
+
# return an array of objects.
|
88
|
+
# * Calls from_xml on elements in map[:associations] (see
|
89
|
+
# association_from_xml)
|
90
|
+
# * Calls map[:block] with the new instance (and optionally the libxml node)
|
91
|
+
# just before adding it to the return array for custom post-processing
|
92
|
+
# === Returns
|
93
|
+
# * An array of instances or a new instance depending on whether map[:all]
|
94
|
+
# is true or false, respectively
|
95
|
+
def from_xml_via_map(xml)
|
96
|
+
nodes, map = find_nodes_and_map(xml)
|
97
|
+
return nil if map.nil?
|
98
|
+
instances = []
|
99
|
+
|
100
|
+
nodes.each do |node|
|
101
|
+
attrs = attrs_from_node_and_registry(node, map[:registry])
|
102
|
+
instance = self.from_hash(attrs)
|
103
|
+
|
104
|
+
map[:associations].each do |association|
|
105
|
+
# TODO: spec
|
106
|
+
instance.association_from_xml(xml, association)
|
107
|
+
end
|
108
|
+
|
109
|
+
b = map[:block]
|
110
|
+
if b
|
111
|
+
case b.arity # number of parameters
|
112
|
+
when 1
|
113
|
+
b.call(instance)
|
114
|
+
when 2
|
115
|
+
b.call(instance, node)
|
116
|
+
end
|
117
|
+
end
|
118
|
+
|
119
|
+
return instance unless map[:all]
|
120
|
+
instances << instance
|
121
|
+
end
|
122
|
+
|
123
|
+
return instances
|
124
|
+
end
|
125
|
+
|
126
|
+
# you can override this to what you want. Defaults to
|
127
|
+
# an alias for from_xml_via_map.
|
128
|
+
def from_xml(xml)
|
129
|
+
@xml = xml
|
130
|
+
self.before_from_xml if defined?(before_from_xml)
|
131
|
+
from_xml_via_map(@xml)
|
132
|
+
end
|
133
|
+
|
134
|
+
# initializes a new instance of self and uses the attribute setters to
|
135
|
+
# populate attributes from the hash. Objects inheriting from ActiveRecord
|
136
|
+
# do this automatically in initialize, but the world doesn't (always) revolve
|
137
|
+
# around AR
|
138
|
+
def from_hash(attrs)
|
139
|
+
object = self.new
|
140
|
+
|
141
|
+
attrs.each do |attribute, value|
|
142
|
+
object.send("#{attribute}=", value)
|
143
|
+
end
|
144
|
+
|
145
|
+
object
|
146
|
+
end
|
147
|
+
|
148
|
+
private
|
149
|
+
|
150
|
+
# find the first map whose base path matches the xml,
|
151
|
+
# and return the nodes found at that base path along with the map
|
152
|
+
# === Parameters
|
153
|
+
# [+xml+] - String of xml
|
154
|
+
# === Returns
|
155
|
+
# two-member array of the form [[LibXML::XML::XPath::Object], Consumer::Mapping::Map]
|
156
|
+
# === Raises
|
157
|
+
# nothing
|
158
|
+
def find_nodes_and_map(xml)
|
159
|
+
self.maps.each do |map|
|
160
|
+
doc = LibXML::XML::Parser.string(xml).parse
|
161
|
+
nodes = doc.find(map[:base_path])
|
162
|
+
return nodes, map if !nodes.empty?
|
163
|
+
end
|
164
|
+
return [], nil
|
165
|
+
puts "No map found in #{self.class} for xml #{xml[0..100]}..." if $DEBUG
|
166
|
+
end
|
167
|
+
|
168
|
+
# returns a hash of attribute => value pairs given an xpath node and a
|
169
|
+
# map registry
|
170
|
+
# (LibXML::XML::XPath::Object and Consumer::Mapping::Map#registry, respectively)
|
171
|
+
def attrs_from_node_and_registry(node, registry)
|
172
|
+
attrs = {}
|
173
|
+
|
174
|
+
registry.each do |attribute, path|
|
175
|
+
leaf = node.find(path).first
|
176
|
+
attrs[attribute] = leaf.content if leaf.respond_to?(:content)
|
177
|
+
attrs[attribute] = leaf.value if leaf.respond_to?(:value)
|
178
|
+
end
|
179
|
+
|
180
|
+
attrs
|
181
|
+
end
|
182
|
+
|
183
|
+
end
|
184
|
+
end
|