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