papercavalier-ruby-aaws 0.8.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 (59) hide show
  1. data/.gitignore +3 -0
  2. data/COPYING +340 -0
  3. data/INSTALL +260 -0
  4. data/NEWS +808 -0
  5. data/README +679 -0
  6. data/README.rdoc +140 -0
  7. data/Rakefile +17 -0
  8. data/VERSION.yml +5 -0
  9. data/example/batch_operation +28 -0
  10. data/example/browse_node_lookup1 +46 -0
  11. data/example/customer_content_lookup1 +27 -0
  12. data/example/customer_content_search1 +21 -0
  13. data/example/example1 +78 -0
  14. data/example/help1 +24 -0
  15. data/example/item_lookup1 +56 -0
  16. data/example/item_lookup2 +56 -0
  17. data/example/item_search1 +30 -0
  18. data/example/item_search2 +37 -0
  19. data/example/item_search3 +23 -0
  20. data/example/list_lookup1 +29 -0
  21. data/example/list_search1 +30 -0
  22. data/example/multiple_operation1 +69 -0
  23. data/example/seller_listing_lookup1 +30 -0
  24. data/example/seller_listing_search1 +29 -0
  25. data/example/seller_lookup1 +45 -0
  26. data/example/shopping_cart1 +42 -0
  27. data/example/similarity_lookup1 +48 -0
  28. data/example/tag_lookup1 +34 -0
  29. data/example/transaction_lookup1 +25 -0
  30. data/example/vehicle_search +22 -0
  31. data/lib/amazon.rb +165 -0
  32. data/lib/amazon/aws.rb +1493 -0
  33. data/lib/amazon/aws/cache.rb +141 -0
  34. data/lib/amazon/aws/search.rb +464 -0
  35. data/lib/amazon/aws/shoppingcart.rb +537 -0
  36. data/lib/amazon/locale.rb +102 -0
  37. data/test/setup.rb +56 -0
  38. data/test/tc_amazon.rb +20 -0
  39. data/test/tc_aws.rb +160 -0
  40. data/test/tc_browse_node_lookup.rb +49 -0
  41. data/test/tc_customer_content_lookup.rb +49 -0
  42. data/test/tc_help.rb +44 -0
  43. data/test/tc_item_lookup.rb +47 -0
  44. data/test/tc_item_search.rb +105 -0
  45. data/test/tc_list_lookup.rb +60 -0
  46. data/test/tc_list_search.rb +44 -0
  47. data/test/tc_multiple_operation.rb +375 -0
  48. data/test/tc_operation_request.rb +64 -0
  49. data/test/tc_seller_listing_lookup.rb +47 -0
  50. data/test/tc_seller_listing_search.rb +55 -0
  51. data/test/tc_seller_lookup.rb +44 -0
  52. data/test/tc_serialisation.rb +107 -0
  53. data/test/tc_shopping_cart.rb +214 -0
  54. data/test/tc_similarity_lookup.rb +48 -0
  55. data/test/tc_tag_lookup.rb +24 -0
  56. data/test/tc_transaction_lookup.rb +24 -0
  57. data/test/tc_vehicle_operations.rb +118 -0
  58. data/test/ts_aws.rb +24 -0
  59. metadata +141 -0
@@ -0,0 +1,537 @@
1
+ # $Id: shoppingcart.rb,v 1.20 2010/02/19 19:13:39 ianmacd Exp $
2
+ #
3
+
4
+ require 'amazon/aws/search'
5
+
6
+ module Amazon
7
+
8
+ module AWS
9
+
10
+ # Load this library with:
11
+ #
12
+ # require 'amazon/aws/shoppingcart'
13
+ #
14
+ module ShoppingCart
15
+
16
+ # Attempts to remove non-existent items from a shopping-cart will raise
17
+ # this exception.
18
+ #
19
+ class CartError < Amazon::AWS::Error::AWSError; end
20
+
21
+ class Cart < Amazon::AWS::Search::Request
22
+
23
+ # _cart_id_ is an alphanumeric token that uniquely identifies a
24
+ # remote shopping-cart. _hmac_ is a <b>H</b>ash <b>M</b>essage
25
+ # <b>A</b>uthentication <b>C</b>ode. This is an encrypted alphanumeric
26
+ # token used to authenticate requests. _purchase_url_ is the URL to
27
+ # follow in order to complete the purchase of the items in the
28
+ # shopping-cart. _cart_items_ is an Array of items in the active area
29
+ # of the cart and _saved_for_later_items_ is an Array of items in the
30
+ # <i>Save For Later</i> area of the cart.
31
+ #
32
+ attr_reader :cart_id, :hmac, :purchase_url, :cart_items,
33
+ :saved_for_later_items
34
+ alias :items :cart_items
35
+ alias :saved_items :saved_for_later_items
36
+ alias :saved :saved_for_later_items
37
+
38
+
39
+ # Create a new instance of a remote shopping-cart. See
40
+ # Amazon::AWS::Search::Request.new for details of the parameters.
41
+ #
42
+ # Example:
43
+ #
44
+ # cart = Cart.new
45
+ #
46
+ def initialize(key_id=nil, associate=nil, locale=nil,
47
+ user_agent=USER_AGENT)
48
+
49
+ @cart_items = []
50
+ @saved_for_later_items = []
51
+
52
+ # Note the *false* as the fourth parameter to _super_, because we
53
+ # never want to cache shopping-cart transactions.
54
+ #
55
+ super( key_id, associate, locale, false, user_agent )
56
+ end
57
+
58
+
59
+ # Prepare the remote shopping-cart for use and place one or more items
60
+ # in it.
61
+ #
62
+ # _id_type_ is a String, either *ASIN* or *OfferListingId*. _item_id_
63
+ # is the actual ASIN or offer listing ID in question, _quantity_ is
64
+ # the quantity of the item to add to the cart, and _merge_cart_ is
65
+ # whether or not the remote shopping-cart should be merged with the
66
+ # local cart on the Amazon retail site upon check-out.
67
+ #
68
+ # _more_items_ is an optional list of Hash objects describing
69
+ # additional items to place in the cart.
70
+ #
71
+ # Example:
72
+ #
73
+ # cart.cart_create( :ASIN, 'B00151HZA6', 1,
74
+ # { 'B000WC4AH0' => 2 },
75
+ # { 'B000PY32OM' => 3 } )
76
+ #
77
+ # or:
78
+ #
79
+ # cart.cart_create( :ASIN, 'B00151HZA6', 1,
80
+ # { 'B000WC4AH0' => 2,
81
+ # 'B000PY32OM' => 3 } )
82
+ #
83
+ # Please note that it's not yet possible to update a wishlist at
84
+ # purchase time by referring to the item's *ListItemId* when adding
85
+ # that item to the cart.
86
+ #
87
+ def cart_create(id_type, item_id, quantity=1, merge_cart=false,
88
+ *more_items)
89
+ cc = CartCreate.new( id_type, item_id, quantity, merge_cart, nil,
90
+ *more_items )
91
+
92
+ @rg = ResponseGroup.new( :Cart )
93
+ cc.response_group = @rg
94
+
95
+ cart = search( cc ).cart_create_response.cart
96
+
97
+ @cart_id = cart.cart_id
98
+ @hmac = cart.hmac
99
+ @purchase_url = cart.purchase_url
100
+ @cart_items = cart.cart_items.cart_item
101
+ end
102
+
103
+ alias :create :cart_create
104
+
105
+
106
+ # Add one or more new items to the remote shopping-cart. This can not
107
+ # be used to update quantities of items *already* in the cart. For
108
+ # that, you must use Cart#cart_modify instead.
109
+ #
110
+ # _id_type_ is a String, either *ASIN* or *OfferListingId*. _item_id_
111
+ # is the actual ASIN or offer listing ID in question, and _quantity_
112
+ # is the quantity of the item to add to the cart.
113
+ #
114
+ # _more_items_ is an optional list of Hash objects describing
115
+ # additional items to add to the cart.
116
+ #
117
+ # Example:
118
+ #
119
+ # cart.cart_add( :ASIN, 'B0014C2BL4', 3,
120
+ # { 'B00006BCKL' => 2 },
121
+ # { 'B000VVE2UW' => 1 } )
122
+ #
123
+ # or:
124
+ #
125
+ # cart.cart_add( :ASIN, 'B0014C2BL4', 3,
126
+ # { 'B00006BCKL' => 2,
127
+ # 'B000VVE2UW' => 1 } )
128
+ #
129
+ def cart_add(id_type, item_id, quantity=1, *more_items)
130
+ ca = CartAdd.new( id_type, item_id, quantity, *more_items )
131
+ ca.response_group = @rg
132
+ ca.params.merge!( { 'CartId' => @cart_id, 'HMAC' => @hmac } )
133
+
134
+ cart = search( ca ).cart_add_response.cart
135
+ @cart_items = cart.cart_items.cart_item
136
+ end
137
+
138
+ alias :add :cart_add
139
+
140
+
141
+ # Returns whether or not an item is present in the cart, be it in the
142
+ # active or <i>Save For Later</i> area.
143
+ #
144
+ # _item_id_type_ is the name of the attribute that uniquely identifies
145
+ # an item, such as *ASIN* or *CartItemId*. _item_id_ is the value of
146
+ # the _item_id_type_ for the item whose presence in the cart is being
147
+ # determined.
148
+ #
149
+ # If the item is present in the cart, its _CartItemId_ is returned as a
150
+ # String. Otherwise, *false* is returned.
151
+ #
152
+ # Example:
153
+ #
154
+ # cart.include?( :ASIN, 'B00151HZA6' )
155
+ #
156
+ def include?(item_id_type, item_id)
157
+ active?( item_id_type, item_id ) ||
158
+ saved_for_later?( item_id_type, item_id )
159
+ end
160
+
161
+ alias :contain? :include?
162
+
163
+
164
+ # Returns whether or not an item is present in an area of the cart.
165
+ #
166
+ # _area_ is an array of cart items, _item_id_type_ is the name of the
167
+ # attribute that uniquely identifies an item, such as *ASIN* or
168
+ # *CartItemId* and _item_id_ is the value of the _item_id_type_ for
169
+ # the item whose presence in the cart is being determined.
170
+ #
171
+ # If the item is present in the cart, its _CartItemId_ is returned as a
172
+ # String. Otherwise, *false* is returned.
173
+ #
174
+ # Example:
175
+ #
176
+ # cart.in_area?( @cart_items, :ASIN, 'B00151HZA6' )
177
+ #
178
+ # or:
179
+ #
180
+ # cart.in_area?( @saved_for_later_items, :ASIN, 'B00151HZA6' )
181
+ #
182
+ def in_area?(area, item_id_type, item_id)
183
+ found = area.find do |item|
184
+ item.send( Amazon.uncamelise( item_id_type.to_s ) ).to_s == item_id
185
+ end
186
+
187
+ found ? found.cart_item_id.to_s : false
188
+ end
189
+ private :in_area?
190
+
191
+
192
+ # Returns whether or not an item is present in the active area of the
193
+ # cart.
194
+ #
195
+ # _item_id_type_ is the name of the attribute that uniquely identifies
196
+ # an item, such as *ASIN* or *CartItemId*. _item_id_ is the value of
197
+ # the _item_id_type_ for the item whose presence in the cart is being
198
+ # determined.
199
+ #
200
+ # If the item is present in the cart, its _CartItemId_ is returned as a
201
+ # String. Otherwise, *false* is returned.
202
+ #
203
+ # Example:
204
+ #
205
+ # cart.active?( :ASIN, 'B00151HZA6' )
206
+ #
207
+ def active?(item_id_type, item_id)
208
+ in_area?( @cart_items, item_id_type, item_id )
209
+ end
210
+
211
+
212
+ # Returns whether or not an item is present in the <i>Save For
213
+ # Later</i> area of the cart.
214
+ #
215
+ # _item_id_type_ is the name of the attribute that uniquely identifies
216
+ # an item, such as *ASIN* or *CartItemId*. _item_id_ is the value of
217
+ # the _item_id_type_ for the item whose presence in the cart is being
218
+ # determined.
219
+ #
220
+ # If the item is present in the cart, its _CartItemId_ is returned as a
221
+ # String. Otherwise, *false* is returned.
222
+ #
223
+ # Example:
224
+ #
225
+ # cart.saved_for_later?( :ASIN, 'B00151HZA6' )
226
+ #
227
+ def saved_for_later?(item_id_type, item_id)
228
+ in_area?( @saved_for_later_items, item_id_type, item_id )
229
+ end
230
+
231
+ alias :saved? :saved_for_later?
232
+
233
+
234
+ # Modify the quantities of one or more products already in the cart.
235
+ # Changing the quantity of an item to <b>0</b> effectively removes it
236
+ # from the cart.
237
+ #
238
+ # _item_id_type_ is the name of the attribute that uniquely identifies
239
+ # an item in the cart, such as *ASIN* or *CartItemId*. _item_id_ is
240
+ # the value of the _item_id_type_ of the item to be modified, and
241
+ # _quantity_ is its new quantity.
242
+ #
243
+ # _save_for_later_ should be set to *true* if the items in question
244
+ # should be moved to the <i>Save For Later</i> area of the
245
+ # shopping-cart, or *false* if they should be moved to the active
246
+ # area. _save_for_later_ therefore applies to every item specified by
247
+ # _item_id_ and _more_items_. Use *nil* when the location of the items
248
+ # should not be changed.
249
+ #
250
+ # Current Amazon AWS documentation claims that specifying partial
251
+ # quantities can be used to move some copies of an item from one area
252
+ # of the cart to another, whilst leaving the rest in place. In
253
+ # practice, however, this causes an AWS error that explains that a
254
+ # quantity may not be specified in combination with an instruction to
255
+ # move copies from one area of the cart to another. For this reason,
256
+ # when _save_for_later_ is not *nil*, item quantities are currently
257
+ # ignored.
258
+ #
259
+ # _more_items_ is an optional list of Hash objects describing
260
+ # additional items whose quantity should be modified.
261
+ #
262
+ # Example:
263
+ #
264
+ # cart.cart_modify( :ASIN, 'B00151HZA6', 2, false,
265
+ # { 'B0013F2M52' => 1 },
266
+ # { 'B000HCPSR6' => 3 } )
267
+ #
268
+ # or:
269
+ #
270
+ # cart.cart_modify( :ASIN, 'B00151HZA6', 2, true,
271
+ # { 'B0013F2M52' => 1,
272
+ # 'B000HCPSR6' => 3 } )
273
+ #
274
+ def cart_modify(item_id_type, item_id, quantity, save_for_later=nil,
275
+ *more_items)
276
+ item_quantity1 = quantity
277
+
278
+ unless cart_item_id1 = self.include?( item_id_type, item_id )
279
+ raise CartError,
280
+ "Can't find item with '#{item_id_type}' of '#{item_id}' in cart."
281
+ end
282
+
283
+ more_items.collect! do |extra_item|
284
+ items = []
285
+
286
+ extra_item.each do |item|
287
+ item_id, quantity = item
288
+ unless cart_item_id = self.include?( item_id_type, item_id )
289
+ raise CartError,
290
+ "Can't find item with '#{item_id_type}' of '#{item_id}' in cart."
291
+ end
292
+
293
+ items << { cart_item_id => quantity }
294
+ end
295
+
296
+ items
297
+ end
298
+
299
+ more_items.flatten!
300
+
301
+ cm = CartModify.new( cart_item_id1, item_quantity1, save_for_later,
302
+ *more_items )
303
+ cm.response_group = @rg
304
+ cm.params.merge!( { 'CartId' => @cart_id, 'HMAC' => @hmac } )
305
+
306
+ cart = search( cm ).cart_modify_response.cart
307
+
308
+ if ci = cart.cart_items
309
+ @cart_items = ci.cart_item
310
+ else
311
+ @cart_items = []
312
+ end
313
+
314
+ if sfl = cart.saved_for_later_items
315
+ @saved_for_later_items = sfl.saved_for_later_item
316
+ else
317
+ @saved_for_later_items = []
318
+ end
319
+ end
320
+
321
+ alias :modify :cart_modify
322
+
323
+
324
+ # Retrieve a remote shopping-cart. This is especially useful when
325
+ # needing to resurrect a cart at a later time, when the Cart object
326
+ # containing the original data no longer exists.
327
+ #
328
+ # _cart_id_ is the unique ID of the cart to be retrieved and _hmac_ is
329
+ # the cart's hash message authentication code. These details can
330
+ # be obtained from an existing cart using the <i>@cart_id</i> and
331
+ # <i>@hmac</i> instance variables.
332
+ #
333
+ # Example:
334
+ #
335
+ # old_cart = Cart.new
336
+ # old_cart.get_cart( '203-4219703-7532717',
337
+ # 'o98sn9Z16JOEF/9eo6OcD8zOZA4=' )
338
+ #
339
+ def cart_get(cart_id, hmac)
340
+ cg = CartGet.new
341
+ @rg = ResponseGroup.new( :Cart )
342
+ cg.response_group = @rg
343
+ cg.params.merge!( { 'CartId' => cart_id, 'HMAC' => hmac } )
344
+
345
+ cart = search( cg ).cart_get_response.cart
346
+
347
+ @cart_id = cart.cart_id
348
+ @hmac = cart.hmac
349
+ @purchase_url = cart.purchase_url
350
+
351
+ if ci = cart.cart_items
352
+ @cart_items = ci.cart_item
353
+ else
354
+ @cart_items = []
355
+ end
356
+
357
+ if sfl = cart.saved_for_later_items
358
+ @saved_for_later_items = sfl.saved_for_later_item
359
+ else
360
+ @saved_for_later_items = []
361
+ end
362
+
363
+ self
364
+ end
365
+
366
+ alias :get :cart_get
367
+
368
+
369
+ # Remove all items from the shopping-cart.
370
+ #
371
+ # Example:
372
+ #
373
+ # cart.cart_clear
374
+ #
375
+ def cart_clear
376
+ cc = CartClear.new
377
+ cc.response_group = @rg
378
+ cc.params.merge!( { 'CartId' => @cart_id, 'HMAC' => @hmac } )
379
+
380
+ cart = search( cc ).cart_clear_response.cart
381
+
382
+ @cart_items = []
383
+ @saved_for_later_items = []
384
+
385
+ end
386
+
387
+ alias :clear :cart_clear
388
+
389
+
390
+ include Enumerable
391
+
392
+ # Iterator for each item in the cart.
393
+ #
394
+ def each
395
+ @cart_items.each { |item| yield item }
396
+ end
397
+
398
+ alias :each_item :each
399
+
400
+ end
401
+
402
+
403
+ class CartOperation < Operation # :nodoc:
404
+
405
+ def query_parameters
406
+ @params.merge!( { 'Operation' => @kind,
407
+ 'ResponseGroup' => @response_group } )
408
+ end
409
+
410
+ # Writer method is overridden in parent class, but we want access to
411
+ # the original here, so we unalias it in this class.
412
+ #
413
+ alias :response_group= :response_group_orig=
414
+ end
415
+
416
+
417
+ # Worker class used by Cart#cart_create.
418
+ #
419
+ class CartCreate < CartOperation # :nodoc:
420
+
421
+ # Create a shopping-cart and add item(s) to it.
422
+ #
423
+ def initialize(id_type, item_id, quantity, merge_cart=false,
424
+ save_for_later=nil, *more_items)
425
+
426
+ # FIXME: Need to deal with ListItemId, too.
427
+
428
+ # Prepend first item to more_items array (which may be empty).
429
+ #
430
+ more_items.unshift( { item_id => quantity } )
431
+
432
+ mc = merge_cart ? 'True' : 'False'
433
+
434
+ more_items.collect! do |extra_item|
435
+ items = []
436
+
437
+ extra_item.each do |item|
438
+ item_id, quantity = item
439
+
440
+ case save_for_later
441
+ when true
442
+ items << { id_type => item_id,
443
+ 'Action' => 'SaveForLater' }
444
+ when false
445
+ items << { id_type => item_id,
446
+ 'Action' => 'MoveToCart' }
447
+ when nil
448
+ items << { id_type => item_id,
449
+ 'Quantity' => quantity }
450
+ else
451
+ raise CartError,
452
+ "save_for_later must be true, false or nil, but was #{save_for_later}"
453
+ end
454
+ end
455
+
456
+ items
457
+ end
458
+
459
+ more_items.flatten!
460
+
461
+ # Force batch syntax.
462
+ #
463
+ params = {}
464
+
465
+ more_items.each_with_index do |hash, index|
466
+ hash.each do |k, v|
467
+ shared = 'Item.%d.%s' % [ index + 1, k ]
468
+ params[shared] = v
469
+ end
470
+ end
471
+
472
+ params.merge!( { 'MergeCart' => mc } ) if merge_cart
473
+ super( params )
474
+ end
475
+
476
+ end
477
+
478
+
479
+ # Worker class used by Cart#cart_add.
480
+ #
481
+ class CartAdd < CartCreate # :nodoc:
482
+
483
+ # Add new item(s) to a cart.
484
+ #
485
+ def initialize(id_type, item_id, quantity, *more_items)
486
+ super( id_type, item_id, quantity, false, nil, *more_items )
487
+ end
488
+
489
+ end
490
+
491
+
492
+ # Worker class used by Cart#cart_modify.
493
+ #
494
+ class CartModify < CartCreate # :nodoc:
495
+
496
+ # Modify the quantity of item(s) in a cart.
497
+ #
498
+ def initialize(cart_item_id, quantity, save_for_later=false,
499
+ *more_items)
500
+
501
+ super( 'CartItemId', cart_item_id, quantity, false, save_for_later,
502
+ *more_items )
503
+ end
504
+
505
+ end
506
+
507
+
508
+ # Worker class used by Cart#cart_clear.
509
+ #
510
+ class CartClear < CartOperation # :nodoc:
511
+
512
+ # Remove all items from a cart.
513
+ #
514
+ def initialize
515
+ super( {} )
516
+ end
517
+
518
+ end
519
+
520
+
521
+ # Worker class used by Cart#cart_get.
522
+ #
523
+ class CartGet < CartOperation # :nodoc:
524
+
525
+ # Fetch a cart.
526
+ #
527
+ def initialize
528
+ super( {} )
529
+ end
530
+
531
+ end
532
+
533
+ end
534
+
535
+ end
536
+
537
+ end