kernow-ruby-aaws 0.5.4 → 0.7.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.
- data/INSTALL +7 -6
- data/NEWS +600 -272
- data/README +250 -163
- data/README.rdoc +145 -129
- data/Rakefile +13 -32
- data/VERSION +1 -0
- data/example/batch_operation +27 -0
- data/example/example1 +3 -3
- data/example/item_lookup1 +5 -4
- data/example/item_lookup2 +5 -4
- data/example/multiple_operation1 +4 -3
- data/example/vehicle_search +22 -0
- data/lib/amazon.rb +34 -16
- data/lib/amazon/aws.rb +496 -161
- data/lib/amazon/aws/search.rb +148 -28
- data/ruby-aaws.gemspec +117 -0
- data/test/setup.rb +5 -2
- data/test/tc_aws.rb +2 -2
- data/test/tc_browse_node_lookup.rb +62 -0
- data/test/tc_customer_content_lookup.rb +64 -0
- data/test/tc_help.rb +60 -0
- data/test/tc_item_lookup.rb +60 -0
- data/test/tc_item_search.rb +88 -3
- data/test/tc_list_lookup.rb +55 -0
- data/test/tc_list_search.rb +55 -0
- data/test/tc_multiple_operation.rb +211 -4
- data/test/tc_seller_listing_lookup.rb +58 -0
- data/test/tc_seller_listing_search.rb +70 -0
- data/test/tc_seller_lookup.rb +54 -0
- data/test/tc_shopping_cart.rb +9 -9
- data/test/tc_similarity_lookup.rb +59 -0
- data/test/tc_tag_lookup.rb +35 -0
- data/test/tc_transaction_lookup.rb +35 -0
- data/test/tc_vehicle_operations.rb +106 -0
- data/test/ts_aws.rb +16 -4
- metadata +85 -49
- data/ruby-aws.gemspec +0 -57
- data/ruby-aws.spec +0 -177
data/example/multiple_operation1
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
#!/usr/bin/ruby -w
|
2
2
|
#
|
3
|
-
# $Id: multiple_operation1,v 1.
|
3
|
+
# $Id: multiple_operation1,v 1.2 2009/02/20 00:25:59 ianmacd Exp $
|
4
4
|
|
5
5
|
require 'amazon/aws/search'
|
6
6
|
|
@@ -14,9 +14,10 @@ include Amazon::AWS::Search
|
|
14
14
|
# availability status.
|
15
15
|
#
|
16
16
|
il = ItemLookup.new( 'ASIN', { 'ItemId' => 'B000AE4QEC',
|
17
|
-
'MerchantId' => 'Amazon' },
|
18
|
-
{ 'ItemId' => 'B000051WBE',
|
19
17
|
'MerchantId' => 'Amazon' } )
|
18
|
+
il2 = ItemLookup.new( 'ASIN', { 'ItemId' => 'B000051WBE',
|
19
|
+
'MerchantId' => 'Amazon' } )
|
20
|
+
il.batch( il2 )
|
20
21
|
is = ItemSearch.new( 'Books', { 'Title' => 'Ruby' } )
|
21
22
|
|
22
23
|
mo = MultipleOperation.new( is, il )
|
@@ -0,0 +1,22 @@
|
|
1
|
+
#!/usr/bin/ruby -w
|
2
|
+
#
|
3
|
+
# $Id: vehicle_search,v 1.1 2009/02/19 15:48:57 ianmacd Exp $
|
4
|
+
|
5
|
+
require 'amazon/aws/search'
|
6
|
+
|
7
|
+
include Amazon::AWS
|
8
|
+
include Amazon::AWS::Search
|
9
|
+
|
10
|
+
is = VehicleSearch.new( { 'Year' => 2008 } )
|
11
|
+
rg = ResponseGroup.new( 'VehicleMakes' )
|
12
|
+
|
13
|
+
req = Request.new
|
14
|
+
req.locale = 'us'
|
15
|
+
|
16
|
+
resp = req.search( is, rg )
|
17
|
+
makes = resp.vehicle_search_response[0].vehicle_years[0].vehicle_year[0].
|
18
|
+
vehicle_makes[0].vehicle_make
|
19
|
+
|
20
|
+
printf( "Search returned %d makes of vehicle for 2008.\n\n", makes.size )
|
21
|
+
|
22
|
+
makes.each { |make| puts make, '' }
|
data/lib/amazon.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# $Id: amazon.rb,v 1.
|
1
|
+
# $Id: amazon.rb,v 1.29 2009/06/08 15:20:11 ianmacd Exp $
|
2
2
|
#
|
3
3
|
|
4
4
|
module Amazon
|
@@ -8,6 +8,7 @@ module Amazon
|
|
8
8
|
class AmazonError < StandardError; end
|
9
9
|
|
10
10
|
NAME = 'Ruby/Amazon'
|
11
|
+
|
11
12
|
@@config = {}
|
12
13
|
|
13
14
|
# Prints debugging messages and works like printf, except that it prints
|
@@ -22,28 +23,31 @@ module Amazon
|
|
22
23
|
#
|
23
24
|
def Amazon.url_encode(string)
|
24
25
|
|
25
|
-
# Shamelessly plagiarised from Wakou Aoyama's cgi.rb
|
26
|
+
# Shamelessly plagiarised from Wakou Aoyama's cgi.rb, but then altered
|
27
|
+
# slightly to please AWS.
|
26
28
|
#
|
27
|
-
string.gsub( /([^
|
28
|
-
'%' + $1.unpack( 'H2' * $1.
|
29
|
-
end
|
29
|
+
string.gsub( /([^a-zA-Z0-9_.~-]+)/ ) do
|
30
|
+
'%' + $1.unpack( 'H2' * $1.bytesize ).join( '%' ).upcase
|
31
|
+
end
|
30
32
|
end
|
31
33
|
|
32
34
|
|
33
35
|
# Convert a string from CamelCase to ruby_case.
|
34
36
|
#
|
35
|
-
def Amazon.uncamelise(
|
37
|
+
def Amazon.uncamelise(string)
|
36
38
|
# Avoid modifying by reference.
|
37
39
|
#
|
38
|
-
|
40
|
+
string = string.dup
|
39
41
|
|
40
42
|
# Don't mess with string if all caps.
|
41
43
|
#
|
42
|
-
|
44
|
+
if string =~ /[a-z]/
|
45
|
+
string.gsub!( /(.+?)(([A-Z][a-z]|[A-Z]+$))/, "\\1_\\2" )
|
46
|
+
end
|
43
47
|
|
44
48
|
# Convert to lower case.
|
45
49
|
#
|
46
|
-
|
50
|
+
string.downcase
|
47
51
|
end
|
48
52
|
|
49
53
|
|
@@ -63,6 +67,7 @@ module Amazon
|
|
63
67
|
# and are readable.
|
64
68
|
#
|
65
69
|
def initialize(config_str=nil)
|
70
|
+
locale = nil
|
66
71
|
|
67
72
|
if config_str
|
68
73
|
|
@@ -105,16 +110,24 @@ module Amazon
|
|
105
110
|
if readable
|
106
111
|
|
107
112
|
Amazon.dprintf( 'Opening %s ...', cf ) if config_class == File
|
108
|
-
|
113
|
+
|
109
114
|
config_class.open( cf ) { |f| lines = f.readlines }.each do |line|
|
110
115
|
line.chomp!
|
111
|
-
|
116
|
+
|
112
117
|
# Skip comments and blank lines.
|
113
118
|
#
|
114
119
|
next if line =~ /^(#|$)/
|
115
|
-
|
120
|
+
|
116
121
|
Amazon.dprintf( 'Read: %s', line )
|
117
|
-
|
122
|
+
|
123
|
+
# Determine whether we're entering the subsection of a new locale.
|
124
|
+
#
|
125
|
+
if match = line.match( /^\[(\w+)\]$/ )
|
126
|
+
locale = match[1]
|
127
|
+
Amazon.dprintf( "Config locale is now '%s'.", locale )
|
128
|
+
next
|
129
|
+
end
|
130
|
+
|
118
131
|
# Store these, because we'll probably find a use for these later.
|
119
132
|
#
|
120
133
|
begin
|
@@ -125,9 +138,14 @@ module Amazon
|
|
125
138
|
rescue NoMethodError, ConfigError
|
126
139
|
raise ConfigError, "bad config line: #{line}"
|
127
140
|
end
|
128
|
-
|
129
|
-
|
130
|
-
|
141
|
+
|
142
|
+
if locale && locale != 'global'
|
143
|
+
self[locale] ||= {}
|
144
|
+
self[locale][key] = val
|
145
|
+
else
|
146
|
+
self[key] = val
|
147
|
+
end
|
148
|
+
|
131
149
|
end
|
132
150
|
end
|
133
151
|
|
data/lib/amazon/aws.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# $Id: aws.rb,v 1.
|
1
|
+
# $Id: aws.rb,v 1.118 2009/06/15 23:51:53 ianmacd Exp $
|
2
2
|
#
|
3
3
|
#:include: ../../README.rdoc
|
4
4
|
|
@@ -6,13 +6,15 @@ module Amazon
|
|
6
6
|
|
7
7
|
module AWS
|
8
8
|
|
9
|
-
require 'uri'
|
10
9
|
require 'amazon'
|
11
10
|
require 'amazon/aws/cache'
|
11
|
+
require 'enumerator'
|
12
|
+
require 'iconv'
|
12
13
|
require 'rexml/document'
|
14
|
+
require 'uri'
|
13
15
|
|
14
16
|
NAME = '%s/%s' % [ Amazon::NAME, 'AWS' ]
|
15
|
-
VERSION = '0.
|
17
|
+
VERSION = '0.7.0'
|
16
18
|
USER_AGENT = '%s %s' % [ NAME, VERSION ]
|
17
19
|
|
18
20
|
# Default Associate tags to use per locale.
|
@@ -26,10 +28,11 @@ module Amazon
|
|
26
28
|
'us' => 'calibanorg-20'
|
27
29
|
}
|
28
30
|
|
29
|
-
# Service name and version for AWS.
|
31
|
+
# Service name and API version for AWS. The version of the API used can be
|
32
|
+
# changed via the user configuration file.
|
30
33
|
#
|
31
34
|
SERVICE = { 'Service' => 'AWSECommerceService',
|
32
|
-
'Version' => '
|
35
|
+
'Version' => '2009-03-31'
|
33
36
|
}
|
34
37
|
|
35
38
|
# Maximum number of 301 and 302 HTTP responses to follow, should Amazon
|
@@ -53,7 +56,9 @@ module Amazon
|
|
53
56
|
'CustomerContentLookup' => { 'parameter' => 'ReviewPage',
|
54
57
|
'max_page' => 10 },
|
55
58
|
'CustomerContentSearch' => { 'parameter' => 'CustomerPage',
|
56
|
-
'max_page' => 20 }
|
59
|
+
'max_page' => 20 },
|
60
|
+
'VehiclePartLookup' => { 'parameter' => 'FitmentPage',
|
61
|
+
'max_page' => 10 }
|
57
62
|
}
|
58
63
|
# N.B. ItemLookup can also use the following two pagination parameters
|
59
64
|
#
|
@@ -61,11 +66,23 @@ module Amazon
|
|
61
66
|
# ---------
|
62
67
|
# VariationPage 150
|
63
68
|
# ReviewPage 20
|
64
|
-
|
69
|
+
|
70
|
+
|
71
|
+
# A hash to store character encoding converters.
|
72
|
+
#
|
73
|
+
@@encodings = {}
|
74
|
+
|
75
|
+
|
65
76
|
# Exception class for HTTP errors.
|
66
77
|
#
|
67
78
|
class HTTPError < AmazonError; end
|
68
79
|
|
80
|
+
|
81
|
+
# Exception class for faulty batch operations.
|
82
|
+
#
|
83
|
+
class BatchError < AmazonError; end
|
84
|
+
|
85
|
+
|
69
86
|
class Endpoint
|
70
87
|
|
71
88
|
attr_reader :host, :path
|
@@ -86,11 +103,12 @@ module Amazon
|
|
86
103
|
'us' => Endpoint.new( 'http://ecs.amazonaws.com/onca/xml' )
|
87
104
|
}
|
88
105
|
|
106
|
+
|
89
107
|
# Fetch a page, either from the cache or by HTTP. This is used internally.
|
90
108
|
#
|
91
|
-
def AWS.get_page(request
|
109
|
+
def AWS.get_page(request) # :nodoc:
|
92
110
|
|
93
|
-
url = ENDPOINT[request.locale].path + query
|
111
|
+
url = ENDPOINT[request.locale].path + request.query
|
94
112
|
cache_url = ENDPOINT[request.locale].host + url
|
95
113
|
|
96
114
|
# Check for cached page and return that if it's there.
|
@@ -100,6 +118,17 @@ module Amazon
|
|
100
118
|
return body if body
|
101
119
|
end
|
102
120
|
|
121
|
+
# Check whether we have a secret key available for signing the request.
|
122
|
+
# If so, sign the request for authentication.
|
123
|
+
#
|
124
|
+
if request.config['secret_key_id']
|
125
|
+
unless request.sign
|
126
|
+
Amazon.dprintf( 'Warning! Failed to sign request. No OpenSSL support for SHA256 digest.' )
|
127
|
+
end
|
128
|
+
|
129
|
+
url = ENDPOINT[request.locale].path + request.query
|
130
|
+
end
|
131
|
+
|
103
132
|
# Get the existing connection. If there isn't one, force a new one.
|
104
133
|
#
|
105
134
|
conn = request.conn || request.reconnect.conn
|
@@ -114,7 +143,10 @@ module Amazon
|
|
114
143
|
# just not passed by here recently), the HTTP connection to the server
|
115
144
|
# will probably have timed out.
|
116
145
|
#
|
117
|
-
rescue Errno::
|
146
|
+
rescue EOFError, Errno::ECONNABORTED, Errno::ECONNREFUSED,
|
147
|
+
Errno::ECONNRESET, Errno::EPIPE, Errno::ETIMEDOUT,
|
148
|
+
Timeout::Error => error
|
149
|
+
Amazon.dprintf( 'Connection to server lost: %s. Retrying...', error )
|
118
150
|
conn = request.reconnect.conn
|
119
151
|
retry
|
120
152
|
end
|
@@ -148,16 +180,23 @@ module Amazon
|
|
148
180
|
end
|
149
181
|
|
150
182
|
|
151
|
-
def AWS.assemble_query(items) # :nodoc:
|
183
|
+
def AWS.assemble_query(items, encoding=nil) # :nodoc:
|
184
|
+
|
152
185
|
query = ''
|
186
|
+
@@encodings[encoding] ||= Iconv.new( 'utf-8', encoding ) if encoding
|
153
187
|
|
154
188
|
# We must sort the items into an array to get reproducible ordering
|
155
189
|
# of the query parameters. Otherwise, URL caching would not work. We
|
156
|
-
# must also convert the
|
157
|
-
# as the
|
190
|
+
# must also convert the parameter values to strings, in case Symbols
|
191
|
+
# have been used as the values.
|
158
192
|
#
|
159
193
|
items.sort { |a,b| a.to_s <=> b.to_s }.each do |k, v|
|
160
|
-
|
194
|
+
if encoding
|
195
|
+
query << '&%s=%s' %
|
196
|
+
[ k, Amazon.url_encode( @@encodings[encoding].iconv( v.to_s ) ) ]
|
197
|
+
else
|
198
|
+
query << '&%s=%s' % [ k, Amazon.url_encode( v.to_s ) ]
|
199
|
+
end
|
161
200
|
end
|
162
201
|
|
163
202
|
# Replace initial ampersand with question-mark.
|
@@ -217,7 +256,7 @@ module Amazon
|
|
217
256
|
# dynamically defined by a separate process.
|
218
257
|
#
|
219
258
|
def AWSObject.yaml_load(io)
|
220
|
-
|
259
|
+
io.each do |line|
|
221
260
|
|
222
261
|
# File data is external, so it's deemed unsafe when $SAFE > 0, which
|
223
262
|
# is the case with mod_ruby, for example, where $SAFE == 1.
|
@@ -234,7 +273,7 @@ module Amazon
|
|
234
273
|
|
235
274
|
# Module#const_defined? takes 2 parameters in Ruby 1.9.
|
236
275
|
#
|
237
|
-
cl_name << false if
|
276
|
+
cl_name << false if RUBY_VERSION >= '1.9.0'
|
238
277
|
|
239
278
|
unless AWSObject.const_defined?( *cl_name )
|
240
279
|
AWSObject.const_set( m[1], Class.new( AWSObject ) )
|
@@ -264,6 +303,9 @@ module Amazon
|
|
264
303
|
iv = '@' + method.id2name
|
265
304
|
|
266
305
|
if instance_variables.include?( iv )
|
306
|
+
|
307
|
+
# Return the instance variable that matches the method called.
|
308
|
+
#
|
267
309
|
instance_variable_get( iv )
|
268
310
|
elsif instance_variables.include?( iv.to_sym )
|
269
311
|
|
@@ -271,6 +313,12 @@ module Amazon
|
|
271
313
|
# not String.
|
272
314
|
#
|
273
315
|
instance_variable_get( iv.to_sym )
|
316
|
+
elsif @__val__.respond_to?( method.id2name )
|
317
|
+
|
318
|
+
# If our value responds to the method in question, call the method
|
319
|
+
# on that.
|
320
|
+
#
|
321
|
+
@__val__.send( method.id2name )
|
274
322
|
else
|
275
323
|
nil
|
276
324
|
end
|
@@ -320,13 +368,8 @@ module Amazon
|
|
320
368
|
alias :to_str :to_s
|
321
369
|
|
322
370
|
|
323
|
-
def to_i # :nodoc:
|
324
|
-
@__val__.to_i
|
325
|
-
end
|
326
|
-
|
327
|
-
|
328
371
|
def ==(other) # :nodoc:
|
329
|
-
|
372
|
+
@__val__.to_s == other
|
330
373
|
end
|
331
374
|
|
332
375
|
|
@@ -421,7 +464,7 @@ module Amazon
|
|
421
464
|
|
422
465
|
# Module#const_defined? takes 2 parameters in Ruby 1.9.
|
423
466
|
#
|
424
|
-
cl_name << false if
|
467
|
+
cl_name << false if RUBY_VERSION >= '1.9.0'
|
425
468
|
|
426
469
|
# Create a class for the new element type unless it already exists.
|
427
470
|
#
|
@@ -468,12 +511,12 @@ module Amazon
|
|
468
511
|
#
|
469
512
|
def get(discount=nil)
|
470
513
|
if self.class.to_s =~ /Image$/ && @url
|
471
|
-
|
472
|
-
|
514
|
+
url = URI.parse( @url[0] )
|
515
|
+
url.path.sub!( /(\.\d\d\._)/, "\\1PE#{discount}" ) if discount
|
473
516
|
|
474
517
|
# FIXME: All HTTP in Ruby/AWS should go through the same method.
|
475
518
|
#
|
476
|
-
|
519
|
+
Net::HTTP.start( url.host, url.port ) do |http|
|
477
520
|
http.get( url.path )
|
478
521
|
end.body
|
479
522
|
|
@@ -554,45 +597,82 @@ module Amazon
|
|
554
597
|
OPERATIONS = %w[
|
555
598
|
BrowseNodeLookup CustomerContentLookup CustomerContentSearch
|
556
599
|
Help ItemLookup ItemSearch
|
557
|
-
ListLookup ListSearch
|
558
|
-
SellerListingSearch
|
559
|
-
TagLookup
|
600
|
+
ListLookup ListSearch MultipleOperation
|
601
|
+
SellerListingLookup SellerListingSearch SellerLookup
|
602
|
+
SimilarityLookup TagLookup TransactionLookup
|
603
|
+
VehiclePartLookup VehiclePartSearch VehicleSearch
|
560
604
|
|
561
605
|
CartAdd CartClear CartCreate
|
562
606
|
CartGet CartModify
|
563
607
|
]
|
564
608
|
|
565
|
-
# These are the valid search parameters that can be used with
|
566
|
-
# ItemSearch.
|
567
|
-
#
|
568
|
-
PARAMETERS = %w[
|
569
|
-
Actor Artist AudienceRating Author
|
570
|
-
Brand BrowseNode City Composer Conductor
|
571
|
-
Director Keywords Manufacturer MusicLabel
|
572
|
-
Neighborhood Orchestra Power Publisher
|
573
|
-
TextStream Title
|
574
|
-
]
|
575
|
-
|
576
|
-
OPT_PARAMETERS = %w[
|
577
|
-
Availability Condition MaximumPrice MerchantId
|
578
|
-
MinimumPrice OfferStatus Sort
|
579
|
-
]
|
580
|
-
|
581
|
-
ALL_PARAMETERS = PARAMETERS + OPT_PARAMETERS
|
582
|
-
|
583
609
|
attr_reader :kind
|
584
|
-
attr_accessor :params
|
610
|
+
attr_accessor :params, :response_group
|
585
611
|
|
586
612
|
def initialize(parameters)
|
587
613
|
|
588
614
|
op_kind = self.class.to_s.sub( /^.*::/, '' )
|
589
|
-
unless OPERATIONS.include?( op_kind )
|
615
|
+
unless OPERATIONS.include?( op_kind )
|
590
616
|
raise "Bad operation: #{op_kind}"
|
591
617
|
end
|
592
618
|
#raise 'Too many parameters' if parameters.size > 10
|
593
619
|
|
594
620
|
@kind = op_kind
|
595
621
|
@params = { 'Operation' => op_kind }.merge( parameters )
|
622
|
+
|
623
|
+
if ResponseGroup::DEFAULT.key?( op_kind )
|
624
|
+
@response_group =
|
625
|
+
ResponseGroup.new( ResponseGroup::DEFAULT[op_kind] )
|
626
|
+
else
|
627
|
+
@response_group = nil
|
628
|
+
end
|
629
|
+
end
|
630
|
+
|
631
|
+
|
632
|
+
# Group together operations of the same class in a batch request.
|
633
|
+
# _operations_ should be either an operation of the same class as *self*
|
634
|
+
# or an array of such operations.
|
635
|
+
#
|
636
|
+
# If you need to batch operations from different classes, use a
|
637
|
+
# MultipleOperation instead.
|
638
|
+
#
|
639
|
+
# Example:
|
640
|
+
#
|
641
|
+
# is = ItemSearch.new( 'Books', { 'Title' => 'ruby programming' } )
|
642
|
+
# is2 = ItemSearch.new( 'Music', { 'Artist' => 'stranglers' } )
|
643
|
+
# is.response_group = ResponseGroup.new( :Small )
|
644
|
+
# is2.response_group = ResponseGroup.new( :Tracks )
|
645
|
+
# is.batch( is2 )
|
646
|
+
#
|
647
|
+
# Please see MultipleOperation.new for implementation details that also
|
648
|
+
# apply to batched operations.
|
649
|
+
#
|
650
|
+
def batch(*operations)
|
651
|
+
|
652
|
+
# Remove the Operation parameter to avoid batch syntax being applied.
|
653
|
+
# We'll readd it at the end.
|
654
|
+
#
|
655
|
+
op_type = @params.delete( 'Operation' )
|
656
|
+
|
657
|
+
operations.flatten.each do |op|
|
658
|
+
|
659
|
+
unless self.class == op.class
|
660
|
+
raise BatchError, "You can't batch different classes of operation. Use class MultipleOperation."
|
661
|
+
end
|
662
|
+
|
663
|
+
# Remove the Operation parameter.
|
664
|
+
#
|
665
|
+
op.params.delete( 'Operation' )
|
666
|
+
|
667
|
+
# Apply batch syntax.
|
668
|
+
#
|
669
|
+
@params = batch_parameters( @params, op.params )
|
670
|
+
@response_group.params = batch_response_groups( op )
|
671
|
+
end
|
672
|
+
|
673
|
+
# Reinstate the Operation parameter.
|
674
|
+
#
|
675
|
+
@params.merge!( { 'Operation' => op_type } )
|
596
676
|
end
|
597
677
|
|
598
678
|
|
@@ -603,21 +683,33 @@ module Amazon
|
|
603
683
|
@index ||= 1
|
604
684
|
|
605
685
|
unless b_params.empty?
|
606
|
-
op_str = self.class.to_s.sub(
|
686
|
+
op_str = @kind || self.class.to_s.sub( /^.*::/, '' )
|
607
687
|
|
608
688
|
# Fudge the operation string if we're dealing with a shopping cart.
|
609
689
|
#
|
610
690
|
op_str = 'Item' if op_str =~ /^Cart/
|
611
691
|
|
612
|
-
all_parameters = [
|
692
|
+
all_parameters = []
|
693
|
+
|
694
|
+
# Shopping carts pass an empty hash in params, so we have to ditch
|
695
|
+
# params in such a case to prevent the batch index from being off by
|
696
|
+
# one.
|
697
|
+
#
|
698
|
+
all_parameters.concat( [ params ] ) unless params.empty?
|
699
|
+
all_parameters.concat( b_params )
|
700
|
+
|
613
701
|
params = {}
|
702
|
+
index = 0
|
614
703
|
|
615
|
-
all_parameters.
|
704
|
+
all_parameters.each do |hash|
|
705
|
+
|
706
|
+
next if hash.empty?
|
616
707
|
|
617
708
|
# Don't batch an already batched hash.
|
618
709
|
#
|
619
|
-
if
|
620
|
-
params
|
710
|
+
if hash.to_a[0][0] =~ /^.+\..+\..+$/
|
711
|
+
params.merge!( hash )
|
712
|
+
@index += 1
|
621
713
|
next
|
622
714
|
end
|
623
715
|
|
@@ -625,6 +717,8 @@ module Amazon
|
|
625
717
|
shared_param = '%s.%d.%s' % [ op_str, @index + index, tag ]
|
626
718
|
params[shared_param] = val
|
627
719
|
end
|
720
|
+
|
721
|
+
index += 1
|
628
722
|
end
|
629
723
|
|
630
724
|
@index += b_params.size
|
@@ -634,69 +728,109 @@ module Amazon
|
|
634
728
|
params
|
635
729
|
end
|
636
730
|
|
731
|
+
end
|
732
|
+
|
733
|
+
|
734
|
+
# Convert response groups to batch format, e.g. ItemSearch.1.ResponseGroup.
|
735
|
+
#
|
736
|
+
def batch_response_groups(operation)
|
737
|
+
|
738
|
+
rg = {}
|
739
|
+
op_count = Hash.new( 1 )
|
637
740
|
|
638
|
-
|
639
|
-
|
640
|
-
|
741
|
+
[ self, operation ].each do |op|
|
742
|
+
rg_hash = op.response_group.params
|
743
|
+
|
744
|
+
if m = rg_hash.to_a[0][0].match( /^(.+)\..+\..+$/ )
|
745
|
+
# This hash is already in batch format.
|
746
|
+
#
|
747
|
+
rg.merge!( rg_hash )
|
748
|
+
|
749
|
+
# Keep a record of the highest index currently in use for each type
|
750
|
+
# of operation.
|
751
|
+
#
|
752
|
+
rg_hash.each do |key, val|
|
753
|
+
op_kind, index = key.match( /^(.+)\.(\d+)\..+$/ )[1, 2]
|
754
|
+
if index.to_i == op_count[op_kind]
|
755
|
+
op_count[op_kind] += 1
|
756
|
+
end
|
757
|
+
end
|
758
|
+
|
759
|
+
else
|
760
|
+
# Convert hash to batch format.
|
761
|
+
#
|
762
|
+
rg_hash.each_value do |val|
|
763
|
+
rg_str = '%s.%d.ResponseGroup' % [ op.kind, op_count[op.kind] ]
|
764
|
+
op_count[op.kind] += 1
|
765
|
+
rg[rg_str] = val
|
766
|
+
end
|
641
767
|
end
|
768
|
+
|
642
769
|
end
|
643
|
-
private :parameter_check
|
644
770
|
|
771
|
+
rg
|
645
772
|
end
|
646
773
|
|
647
774
|
|
648
|
-
# This class can be used to merge operations into a single
|
649
|
-
#
|
775
|
+
# This class can be used to merge multiple operations into a single
|
776
|
+
# operation for greater efficiency.
|
650
777
|
#
|
651
778
|
class MultipleOperation < Operation
|
652
779
|
|
653
|
-
# This
|
654
|
-
#
|
655
|
-
#
|
780
|
+
# This allows you to take two Operation objects and combine them to form
|
781
|
+
# a single object, which can then be used to perform a single request to
|
782
|
+
# AWS. This allows for greater efficiency, reducing the number of
|
783
|
+
# requests sent to AWS.
|
784
|
+
#
|
785
|
+
# AWS currently imposes a limit of two operations when encapsulating
|
786
|
+
# operations in a multiple operation.
|
656
787
|
#
|
657
788
|
# <em>operation1</em> and <em>operation2</em> are both objects from a
|
658
789
|
# subclass of Operation, such as ItemSearch, ItemLookup, etc.
|
659
790
|
#
|
660
|
-
#
|
661
|
-
#
|
791
|
+
# Please note the following implementation details:
|
792
|
+
#
|
793
|
+
# - If you use the _response_group_ parameter of Search::Request#search
|
794
|
+
# to pass the list of response groups, it will apply to both
|
795
|
+
# operations.
|
662
796
|
#
|
663
|
-
#
|
664
|
-
#
|
665
|
-
#
|
797
|
+
# If you want to use a different response group set for each
|
798
|
+
# operation, you should assign the relevant groups to the
|
799
|
+
# @response_group attribute of each Operation object. You must do this
|
800
|
+
# *before* you instantiate the MultipleOperation.
|
666
801
|
#
|
667
802
|
# - One or both operations may have multiple results pages available,
|
668
|
-
# but only the first page
|
803
|
+
# but only the first page is returned. If you need the subsequent
|
669
804
|
# pages, perform the operations separately, not as part of a
|
670
|
-
#
|
805
|
+
# multiple operation.
|
671
806
|
#
|
672
807
|
# Example:
|
673
808
|
#
|
674
809
|
# is = ItemSearch.new( 'Books', { 'Title' => 'Ruby' } )
|
675
810
|
# il = ItemLookup.new( 'ASIN', { 'ItemId' => 'B0013DZAYO',
|
676
811
|
# 'MerchantId' => 'Amazon' } )
|
677
|
-
#
|
812
|
+
# is.response_group = ResponseGroup.new( :Large )
|
813
|
+
# il.response_group = ResponseGroup.new( :Small )
|
814
|
+
# mo = MultipleOperation.new( is, il )
|
678
815
|
#
|
679
|
-
#
|
680
|
-
#
|
816
|
+
# As you can see, the operations that are combined as a
|
817
|
+
# MultipleOperation do not have to belong to the same class. In the
|
818
|
+
# above example, we compose a multiple operation consisting of an
|
819
|
+
# ItemSearch and an ItemLookup.
|
820
|
+
#
|
821
|
+
# If you want to batch operations belonging to the same class,
|
822
|
+
# Operation#batch provides an alternative.
|
681
823
|
#
|
682
824
|
def initialize(operation1, operation2)
|
683
825
|
|
684
|
-
|
685
|
-
# is to protect me, not for user code.
|
686
|
-
#
|
687
|
-
operation1.freeze
|
688
|
-
operation2.freeze
|
689
|
-
|
690
|
-
op_kind = '%s,%s' % [ operation1.kind, operation2.kind ]
|
826
|
+
op_kind = [ operation1.kind, operation2.kind ].join( ',' )
|
691
827
|
|
692
828
|
# Duplicate Operation objects and remove their Operation parameter.
|
693
829
|
#
|
694
830
|
op1 = operation1.dup
|
695
|
-
op1.params = op1.params.dup
|
696
831
|
op1.params.delete( 'Operation' )
|
697
832
|
|
698
833
|
op2 = operation2.dup
|
699
|
-
op2.params = op2.params.dup
|
700
834
|
op2.params.delete( 'Operation' )
|
701
835
|
|
702
836
|
if op1.class == op2.class
|
@@ -717,6 +851,9 @@ module Amazon
|
|
717
851
|
params = { 'Operation' => op_kind }.merge( b_params )
|
718
852
|
super( params )
|
719
853
|
|
854
|
+
@response_group = ResponseGroup.new( [] )
|
855
|
+
@response_group.params.delete( 'ResponseGroup' )
|
856
|
+
@response_group.params = op1.batch_response_groups( op2 )
|
720
857
|
end
|
721
858
|
|
722
859
|
end
|
@@ -737,8 +874,8 @@ module Amazon
|
|
737
874
|
#
|
738
875
|
# _help_type_ is the type of object for which help is being sought, such
|
739
876
|
# as *Operation* or *ResponseGroup*. _about_ is the name of the
|
740
|
-
# operation or response group you need help with, and _parameters_ is
|
741
|
-
# hash of parameters that
|
877
|
+
# operation or response group you need help with, and _parameters_ is an
|
878
|
+
# optional hash of parameters that further refine the request for help.
|
742
879
|
#
|
743
880
|
def initialize(help_type, about, parameters={})
|
744
881
|
super( { 'HelpType' => help_type,
|
@@ -764,9 +901,9 @@ module Amazon
|
|
764
901
|
#
|
765
902
|
# - *All* searches through all indices (but currently exists only in the
|
766
903
|
# *US* locale).
|
767
|
-
# - *Blended* combines
|
768
|
-
#
|
769
|
-
# and
|
904
|
+
# - *Blended* combines Apparel, Automotive, Books, DVD, Electronics,
|
905
|
+
# GourmetFood, Kitchen, Music, PCHardware, PetSupplies, Software,
|
906
|
+
# SoftwareVideoGames, SportingGoods, Tools, Toys, VHS and VideoGames.
|
770
907
|
# - *Merchants* combines all search indices for a merchant given with
|
771
908
|
# MerchantId.
|
772
909
|
# - *Music* combines the Classical, DigitalMusic, and MusicTracks
|
@@ -774,25 +911,60 @@ module Amazon
|
|
774
911
|
# - *Video* combines the DVD and VHS search indices.
|
775
912
|
#
|
776
913
|
SEARCH_INDICES = %w[
|
777
|
-
|
778
|
-
|
779
|
-
|
780
|
-
|
781
|
-
|
782
|
-
|
783
|
-
|
784
|
-
|
785
|
-
|
786
|
-
|
787
|
-
|
788
|
-
|
789
|
-
|
790
|
-
|
791
|
-
|
914
|
+
All
|
915
|
+
Apparel
|
916
|
+
Automotive
|
917
|
+
Baby
|
918
|
+
Beauty
|
919
|
+
Blended
|
920
|
+
Books
|
921
|
+
Classical
|
922
|
+
DigitalMusic
|
923
|
+
DVD
|
924
|
+
Electronics
|
925
|
+
ForeignBooks
|
926
|
+
GourmetFood
|
927
|
+
Grocery
|
928
|
+
HealthPersonalCare
|
929
|
+
Hobbies
|
930
|
+
HomeGarden
|
931
|
+
HomeImprovement
|
932
|
+
Industrial
|
933
|
+
Jewelry
|
934
|
+
KindleStore
|
935
|
+
Kitchen
|
936
|
+
Magazines
|
937
|
+
Merchants
|
938
|
+
Miscellaneous
|
939
|
+
MP3Downloads
|
940
|
+
Music
|
941
|
+
MusicalInstruments
|
942
|
+
MusicTracks
|
943
|
+
OfficeProducts
|
944
|
+
OutdoorLiving
|
945
|
+
PCHardware
|
946
|
+
PetSupplies
|
947
|
+
Photo
|
948
|
+
Shoes
|
949
|
+
SilverMerchants
|
950
|
+
Software
|
951
|
+
SoftwareVideoGames
|
952
|
+
SportingGoods
|
953
|
+
Tools
|
954
|
+
Toys
|
955
|
+
UnboxVideo
|
956
|
+
VHS
|
957
|
+
Video
|
958
|
+
VideoGames
|
959
|
+
Watches
|
960
|
+
Wireless
|
961
|
+
WirelessAccessories
|
962
|
+
]
|
792
963
|
|
793
964
|
|
794
965
|
# Search AWS for items. _search_index_ must be one of _SEARCH_INDICES_
|
795
|
-
# and _parameters_ is
|
966
|
+
# and _parameters_ is an optional hash of parameters that further refine
|
967
|
+
# the scope of the search.
|
796
968
|
#
|
797
969
|
# Example:
|
798
970
|
#
|
@@ -806,7 +978,6 @@ module Amazon
|
|
806
978
|
raise "Invalid search index: #{search_index}"
|
807
979
|
end
|
808
980
|
|
809
|
-
parameter_check( parameters )
|
810
981
|
super( { 'SearchIndex' => search_index }.merge( parameters ) )
|
811
982
|
end
|
812
983
|
|
@@ -820,33 +991,20 @@ module Amazon
|
|
820
991
|
class ItemLookup < Operation
|
821
992
|
|
822
993
|
# Look up a specific item in the AWS catalogue. _id_type_ is the type of
|
823
|
-
# identifier
|
824
|
-
# located and narrows the scope of the search
|
825
|
-
# optional hash of further items to be located. Use of _b_parameters_
|
826
|
-
# effectively results in a batch operation being sent to AWS.
|
994
|
+
# identifier and _parameters_ is a hash that identifies the item to be
|
995
|
+
# located and narrows the scope of the search.
|
827
996
|
#
|
828
997
|
# Example:
|
829
998
|
#
|
830
999
|
# il = ItemLookup.new( 'ASIN', { 'ItemId' => 'B000AE4QEC'
|
831
|
-
# 'MerchantId' => 'Amazon' },
|
832
|
-
# { 'ItemId' => 'B000051WBE',
|
833
1000
|
# 'MerchantId' => 'Amazon' } )
|
834
1001
|
#
|
835
|
-
# In the above example, we search for
|
836
|
-
#
|
837
|
-
#
|
1002
|
+
# In the above example, we search for an item, based on its ASIN. The
|
1003
|
+
# use of _MerchantId_ restricts the offers returned to those for sale
|
1004
|
+
# by Amazon (as opposed to third-party sellers).
|
838
1005
|
#
|
839
|
-
def initialize(id_type, parameters
|
840
|
-
|
841
|
-
id_type_str = 'IdType'
|
842
|
-
|
843
|
-
unless b_parameters.empty?
|
844
|
-
class_str = self.class.to_s.sub( /^.+::/, '' )
|
845
|
-
id_type_str = '%s.Shared.IdType' % [ class_str ]
|
846
|
-
parameters = batch_parameters( parameters, *b_parameters )
|
847
|
-
end
|
848
|
-
|
849
|
-
super( { id_type_str => id_type }.merge( parameters ) )
|
1006
|
+
def initialize(id_type, parameters)
|
1007
|
+
super( { 'IdType' => id_type }.merge( parameters ) )
|
850
1008
|
end
|
851
1009
|
|
852
1010
|
end
|
@@ -857,8 +1015,8 @@ module Amazon
|
|
857
1015
|
class SellerListingSearch < Operation
|
858
1016
|
|
859
1017
|
# Search for items for sale by a particular seller. _seller_id_ is the
|
860
|
-
# Amazon seller ID and _parameters_ is
|
861
|
-
# the scope of the search.
|
1018
|
+
# Amazon seller ID and _parameters_ is an optional hash of parameters
|
1019
|
+
# that further refine the scope of the search.
|
862
1020
|
#
|
863
1021
|
# Example:
|
864
1022
|
#
|
@@ -880,11 +1038,8 @@ module Amazon
|
|
880
1038
|
class SellerListingLookup < ItemLookup
|
881
1039
|
|
882
1040
|
# Look up a specific item for sale by a specific seller. _id_type_ is
|
883
|
-
# the type of identifier
|
884
|
-
# item to be located and narrows the scope of the search
|
885
|
-
# _b_parameters_ is an optional hash of further items to be located. Use
|
886
|
-
# of _b_parameters_ effectively results in a batch operation being sent
|
887
|
-
# to AWS.
|
1041
|
+
# the type of identifier and _parameters_ is a hash that identifies the
|
1042
|
+
# item to be located and narrows the scope of the search.
|
888
1043
|
#
|
889
1044
|
# Example:
|
890
1045
|
#
|
@@ -894,9 +1049,8 @@ module Amazon
|
|
894
1049
|
# In the above example, we search seller <b>AP8U6Y3PYQ9VO</b>'s listings
|
895
1050
|
# to find items for sale with the ASIN <b>B0009RRRC8</b>.
|
896
1051
|
#
|
897
|
-
def initialize(seller_id, id_type, parameters
|
898
|
-
super( id_type, { 'SellerId' => seller_id }.merge( parameters )
|
899
|
-
b_parameters )
|
1052
|
+
def initialize(seller_id, id_type, parameters)
|
1053
|
+
super( id_type, { 'SellerId' => seller_id }.merge( parameters ) )
|
900
1054
|
end
|
901
1055
|
|
902
1056
|
end
|
@@ -907,8 +1061,8 @@ module Amazon
|
|
907
1061
|
class SellerLookup < Operation
|
908
1062
|
|
909
1063
|
# Search for the details of a specific seller. _seller_id_ is the Amazon
|
910
|
-
# ID of the seller in question and _parameters_ is
|
911
|
-
# that
|
1064
|
+
# ID of the seller in question and _parameters_ is an optional hash of
|
1065
|
+
# parameters that further refine the scope of the search.
|
912
1066
|
#
|
913
1067
|
# Example:
|
914
1068
|
#
|
@@ -930,8 +1084,8 @@ module Amazon
|
|
930
1084
|
class CustomerContentLookup < Operation
|
931
1085
|
|
932
1086
|
# Search for public customer data. _customer_id_ is the unique ID
|
933
|
-
# identifying the customer on Amazon and _parameters_ is
|
934
|
-
# parameters that
|
1087
|
+
# identifying the customer on Amazon and _parameters_ is an optional
|
1088
|
+
# hash of parameters that further refine the scope of the search.
|
935
1089
|
#
|
936
1090
|
# Example:
|
937
1091
|
#
|
@@ -981,8 +1135,8 @@ module Amazon
|
|
981
1135
|
class ListSearch < Operation
|
982
1136
|
|
983
1137
|
# Search for Amazon lists. _list_type_ is the type of list to search for
|
984
|
-
# and _parameters_ is
|
985
|
-
# search.
|
1138
|
+
# and _parameters_ is an optional hash of parameters that narrow the
|
1139
|
+
# scope of the search.
|
986
1140
|
#
|
987
1141
|
# Example:
|
988
1142
|
#
|
@@ -1003,8 +1157,8 @@ module Amazon
|
|
1003
1157
|
class ListLookup < Operation
|
1004
1158
|
|
1005
1159
|
# Look up and return details about a specific list. _list_id_ is the
|
1006
|
-
# Amazon list ID, _list_type_ is the type of list and _parameters_ is
|
1007
|
-
# hash of parameters that
|
1160
|
+
# Amazon list ID, _list_type_ is the type of list and _parameters_ is an
|
1161
|
+
# optional hash of parameters that narrow the scope of the search.
|
1008
1162
|
#
|
1009
1163
|
# Example:
|
1010
1164
|
#
|
@@ -1014,7 +1168,7 @@ module Amazon
|
|
1014
1168
|
# <b>3P722DU4KUPCP</b> is retrieved from AWS.
|
1015
1169
|
#
|
1016
1170
|
def initialize(list_id, list_type, parameters={})
|
1017
|
-
|
1171
|
+
super( { 'ListId' => list_id,
|
1018
1172
|
'ListType' => list_type
|
1019
1173
|
}.merge( parameters ) )
|
1020
1174
|
end
|
@@ -1030,8 +1184,9 @@ module Amazon
|
|
1030
1184
|
class BrowseNodeLookup < Operation
|
1031
1185
|
|
1032
1186
|
# Look up and return the details of an Amazon browse node. _node_ is the
|
1033
|
-
# browse node to look up and _parameters_ is
|
1034
|
-
#
|
1187
|
+
# browse node to look up and _parameters_ is an optional hash of
|
1188
|
+
# parameters that further refine the scope of the search. _parameters_
|
1189
|
+
# is currently unused.
|
1035
1190
|
#
|
1036
1191
|
# Example:
|
1037
1192
|
#
|
@@ -1052,8 +1207,8 @@ module Amazon
|
|
1052
1207
|
class SimilarityLookup < Operation
|
1053
1208
|
|
1054
1209
|
# Look up items similar to _asin_, which can be a single item or an
|
1055
|
-
# array. _parameters_ is
|
1056
|
-
# refine the search.
|
1210
|
+
# array. _parameters_ is an optional hash of parameters that further
|
1211
|
+
# refine the scope of the search.
|
1057
1212
|
#
|
1058
1213
|
# Example:
|
1059
1214
|
#
|
@@ -1076,8 +1231,8 @@ module Amazon
|
|
1076
1231
|
class TagLookup < Operation
|
1077
1232
|
|
1078
1233
|
# Look up entities based on user-defined tags. _tag_name_ is the tag to
|
1079
|
-
# search on and _parameters_ is
|
1080
|
-
# further refine the search.
|
1234
|
+
# search on and _parameters_ is an optional hash of parameters that
|
1235
|
+
# further refine the scope of the search.
|
1081
1236
|
#
|
1082
1237
|
# Example:
|
1083
1238
|
#
|
@@ -1115,28 +1270,149 @@ module Amazon
|
|
1115
1270
|
end
|
1116
1271
|
|
1117
1272
|
|
1273
|
+
# Look up individual vehicle parts.
|
1274
|
+
#
|
1275
|
+
class VehiclePartLookup < Operation
|
1276
|
+
|
1277
|
+
# Look up a particular vehicle part. _item_id_ is the ASIN of the part
|
1278
|
+
# in question and _parameters_ is an optional hash of parameters that
|
1279
|
+
# further refine the scope of the search.
|
1280
|
+
#
|
1281
|
+
# Although the _item_id_ alone is enough to locate the part, providing
|
1282
|
+
# _parameters_ can be useful in determining whether the part looked up
|
1283
|
+
# is a fit for a particular vehicle type, as with the *VehiclePartFit*
|
1284
|
+
# response group.
|
1285
|
+
#
|
1286
|
+
# Example:
|
1287
|
+
#
|
1288
|
+
# vpl = VehiclePartLookup.new( 'B000C1ZLI8',
|
1289
|
+
# { 'Year' => 2008,
|
1290
|
+
# 'MakeId' => 73,
|
1291
|
+
# 'ModelId' => 6039,
|
1292
|
+
# 'TrimId' => 20 } )
|
1293
|
+
#
|
1294
|
+
# Here, we search for a <b>2008</b> model *Audi* <b>R8</b> with *Base*
|
1295
|
+
# trim. The required Ids can be found using VehiclePartSearch.
|
1296
|
+
#
|
1297
|
+
def initialize(item_id, parameters={})
|
1298
|
+
super( { 'ItemId' => item_id }.merge( parameters ) )
|
1299
|
+
end
|
1300
|
+
|
1301
|
+
end
|
1302
|
+
|
1303
|
+
|
1304
|
+
# Search for parts for a given vehicle.
|
1305
|
+
#
|
1306
|
+
class VehiclePartSearch < Operation
|
1307
|
+
|
1308
|
+
# Find parts for a given _year_, _make_id_ and _model_id_ of vehicle.
|
1309
|
+
# _parameters_ is an optional hash of parameters that further refine the
|
1310
|
+
# scope of the search.
|
1311
|
+
#
|
1312
|
+
# Example:
|
1313
|
+
#
|
1314
|
+
# vps = VehiclePartSearch.new( 2008, 73, 6039,
|
1315
|
+
# { 'TrimId' => 20,
|
1316
|
+
# 'EngineId' => 8914 } )
|
1317
|
+
#
|
1318
|
+
# In this example, we look for parts that will fit a <b>2008</b> model
|
1319
|
+
# *Audi* <b>R8</b> with *Base* trim and a <b>4.2L V8 Gas DOHC
|
1320
|
+
# Distributorless Naturally Aspirated Bosch Motronic Electronic FI
|
1321
|
+
# MFI</b> engine.
|
1322
|
+
#
|
1323
|
+
# Note that pagination of VehiclePartSearch results is not currently
|
1324
|
+
# supported.
|
1325
|
+
#
|
1326
|
+
# Use VehicleSearch to learn the MakeId and ModelId of the vehicle in
|
1327
|
+
# which you are interested.
|
1328
|
+
#
|
1329
|
+
def initialize(year, make_id, model_id, parameters={})
|
1330
|
+
super( { 'Year' => year,
|
1331
|
+
'MakeId' => make_id,
|
1332
|
+
'ModelId' => model_id }.merge( parameters ) )
|
1333
|
+
end
|
1334
|
+
|
1335
|
+
end
|
1336
|
+
|
1337
|
+
|
1338
|
+
# Search for vehicles.
|
1339
|
+
#
|
1340
|
+
class VehicleSearch < Operation
|
1341
|
+
|
1342
|
+
# Search for vehicles, based on one or more of the following
|
1343
|
+
# _parameters_: Year, MakeId, ModelId and TrimId.
|
1344
|
+
#
|
1345
|
+
# This method is best used iteratively. For example, first search on
|
1346
|
+
# year with a response group of *VehicleMakes* to return all makes for
|
1347
|
+
# that year.
|
1348
|
+
#
|
1349
|
+
# Next, search on year and make with a response group of *VehicleModels*
|
1350
|
+
# to find all models for that year and make.
|
1351
|
+
#
|
1352
|
+
# Then, search on year, make and model with a response group of
|
1353
|
+
# *VehicleTrims* to find all trim packages for that year, make and model.
|
1354
|
+
#
|
1355
|
+
# Finally, if required, search on year, make, model and trim package
|
1356
|
+
# with a response group of *VehicleOptions* to find all vehicle options
|
1357
|
+
# for that year, make, model and trim package.
|
1358
|
+
#
|
1359
|
+
# Example:
|
1360
|
+
#
|
1361
|
+
# vs = VehicleSearch.new( { 'Year' => 2008,
|
1362
|
+
# 'MakeId' => 20,
|
1363
|
+
# 'ModelId' => 6039,
|
1364
|
+
# 'TrimId' => 20 } )
|
1365
|
+
#
|
1366
|
+
# In this example, we search for <b>2008 Audi R8</b> vehicles with a
|
1367
|
+
# *Base* trim package. Used with the *VehicleOptions* response group,
|
1368
|
+
# a list of vehicle options would be returned.
|
1369
|
+
#
|
1370
|
+
def initialize(parameters={})
|
1371
|
+
super
|
1372
|
+
end
|
1373
|
+
|
1374
|
+
end
|
1375
|
+
|
1118
1376
|
# Response groups determine which data pertaining to the item(s) being
|
1119
|
-
# sought is returned. They
|
1120
|
-
#
|
1121
|
-
#
|
1122
|
-
#
|
1377
|
+
# sought is returned. They strongly influence the amount of data returned,
|
1378
|
+
# so you should always use the smallest response group(s) containing the
|
1379
|
+
# data of interest to you, to avoid masses of unnecessary data being
|
1380
|
+
# returned.
|
1123
1381
|
#
|
1124
1382
|
class ResponseGroup
|
1125
1383
|
|
1126
|
-
|
1384
|
+
# The default type of response group to use with each type of operation.
|
1385
|
+
#
|
1386
|
+
DEFAULT = { 'BrowseNodeLookup' => [ :BrowseNodeInfo, :TopSellers ],
|
1387
|
+
'CustomerContentLookup' => [ :CustomerInfo, :CustomerLists ],
|
1388
|
+
'CustomerContentSearch' => :CustomerInfo,
|
1389
|
+
'Help' => :Help,
|
1390
|
+
'ItemLookup' => :Large,
|
1391
|
+
'ItemSearch' => :Large,
|
1392
|
+
'ListLookup' => [ :ListInfo, :Small ],
|
1393
|
+
'ListSearch' => :ListInfo,
|
1394
|
+
'SellerListingLookup' => :SellerListing,
|
1395
|
+
'SellerListingSearch' => :SellerListing,
|
1396
|
+
'SellerLookup' => :Seller,
|
1397
|
+
'SimilarityLookup' => :Large,
|
1398
|
+
'TagLookup' => [ :Tags, :TagsSummary ],
|
1399
|
+
'TransactionLookup' => :TransactionDetails,
|
1400
|
+
'VehiclePartLookup' => :VehiclePartFit,
|
1401
|
+
'VehiclePartSearch' => :VehicleParts,
|
1402
|
+
'VehicleSearch' => :VehicleMakes
|
1403
|
+
}
|
1404
|
+
|
1405
|
+
attr_reader :list
|
1406
|
+
attr_accessor :params
|
1127
1407
|
|
1128
1408
|
# Define a set of one or more response groups to be applied to items
|
1129
1409
|
# retrieved by an AWS operation.
|
1130
1410
|
#
|
1131
|
-
# If no response groups are given in _rg_ when instantiating an object,
|
1132
|
-
# *Small* will be used by default.
|
1133
|
-
#
|
1134
1411
|
# Example:
|
1135
1412
|
#
|
1136
1413
|
# rg = ResponseGroup.new( 'Medium', 'Offers', 'Reviews' )
|
1137
1414
|
#
|
1138
1415
|
def initialize(*rg)
|
1139
|
-
rg << 'Small' if rg.empty?
|
1140
1416
|
@list = rg
|
1141
1417
|
@params = { 'ResponseGroup' => @list.join( ',' ) }
|
1142
1418
|
end
|
@@ -1154,13 +1430,19 @@ module Amazon
|
|
1154
1430
|
class AWSError < AmazonError; end
|
1155
1431
|
|
1156
1432
|
def Error.exception(xml)
|
1157
|
-
|
1158
|
-
|
1433
|
+
err_class = xml.elements['Code'].text.sub( /^AWS.*\./, '' )
|
1434
|
+
err_msg = xml.elements['Message'].text
|
1159
1435
|
|
1160
1436
|
# Dynamically define a new exception class for this class of error,
|
1161
1437
|
# unless it already exists.
|
1162
1438
|
#
|
1163
|
-
|
1439
|
+
# Note that Ruby 1.9's Module.const_defined? needs a second parameter
|
1440
|
+
# of *false*, or it will also search AWSError's ancestors.
|
1441
|
+
#
|
1442
|
+
cd_params = [ err_class ]
|
1443
|
+
cd_params << false if RUBY_VERSION >= '1.9.0'
|
1444
|
+
|
1445
|
+
unless Amazon::AWS::Error.const_defined?( *cd_params )
|
1164
1446
|
Amazon::AWS::Error.const_set( err_class, Class.new( AWSError ) )
|
1165
1447
|
end
|
1166
1448
|
|
@@ -1171,6 +1453,59 @@ module Amazon
|
|
1171
1453
|
|
1172
1454
|
end
|
1173
1455
|
|
1456
|
+
|
1457
|
+
# Create a shorthand module method for each of the AWS operations. These
|
1458
|
+
# can be used to create less verbose code at the expense of flexibility.
|
1459
|
+
#
|
1460
|
+
# For example, we might normally write the following code:
|
1461
|
+
#
|
1462
|
+
# is = ItemSearch.new( 'Books', { 'Title' => 'Ruby' } )
|
1463
|
+
# rg = ResponseGroup.new( 'Large' )
|
1464
|
+
# req = Request.new
|
1465
|
+
# response = req.search( is, rg )
|
1466
|
+
#
|
1467
|
+
# but we could instead use ItemSearch's associated module method as
|
1468
|
+
# follows:
|
1469
|
+
#
|
1470
|
+
# response = Amazon::AWS.item_search( 'Books', { 'Title' => 'Ruby' } )
|
1471
|
+
#
|
1472
|
+
# Note that these equivalent module methods all attempt to use the *Large*
|
1473
|
+
# response group, which may or may not work. If an
|
1474
|
+
# Amazon::AWS::Error::InvalidResponseGroup is raised, we will scan the
|
1475
|
+
# text of the error message returned by AWS to try to glean a valid
|
1476
|
+
# response group and then retry the operation using that instead.
|
1477
|
+
|
1478
|
+
|
1479
|
+
# Ontain a list of all subclasses of the Operation class.
|
1480
|
+
#
|
1481
|
+
classes =
|
1482
|
+
ObjectSpace.enum_for( :each_object, class << Operation; self; end ).to_a
|
1483
|
+
|
1484
|
+
classes.each do |cl|
|
1485
|
+
# Convert class name to Ruby case, e.g. ItemSearch => item_search.
|
1486
|
+
#
|
1487
|
+
class_name = cl.to_s.sub( /^.+::/, '' )
|
1488
|
+
uncamelised_name = Amazon.uncamelise( class_name )
|
1489
|
+
|
1490
|
+
# Define the module method counterpart of each operation.
|
1491
|
+
#
|
1492
|
+
module_eval %Q(
|
1493
|
+
def AWS.#{uncamelised_name}(*params)
|
1494
|
+
# Instantiate an object of the desired operational class.
|
1495
|
+
#
|
1496
|
+
op = #{cl.to_s}.new( *params )
|
1497
|
+
|
1498
|
+
# Attempt a search for the given operation using its default
|
1499
|
+
# response group types.
|
1500
|
+
#
|
1501
|
+
results = Search::Request.new.search( op )
|
1502
|
+
yield results if block_given?
|
1503
|
+
return results
|
1504
|
+
|
1505
|
+
end
|
1506
|
+
)
|
1507
|
+
end
|
1508
|
+
|
1174
1509
|
end
|
1175
1510
|
|
1176
1511
|
end
|