ruby-aaws 0.4.1
Sign up to get free protection for your applications and to get access to all the features.
- data/COPYING +340 -0
- data/NEWS +304 -0
- data/README +558 -0
- data/README.rdoc +136 -0
- data/example/browse_node_lookup1 +46 -0
- data/example/customer_content_lookup1 +27 -0
- data/example/customer_content_search1 +21 -0
- data/example/example1 +87 -0
- data/example/help1 +25 -0
- data/example/item_lookup1 +55 -0
- data/example/item_lookup2 +55 -0
- data/example/item_search1 +30 -0
- data/example/item_search2 +37 -0
- data/example/item_search3 +23 -0
- data/example/list_lookup1 +29 -0
- data/example/list_search1 +30 -0
- data/example/multiple_operation1 +67 -0
- data/example/seller_listing_lookup1 +30 -0
- data/example/seller_listing_search1 +28 -0
- data/example/seller_lookup1 +45 -0
- data/example/shopping_cart1 +42 -0
- data/example/similarity_lookup1 +48 -0
- data/example/tag_lookup1 +34 -0
- data/example/transaction_lookup1 +26 -0
- data/lib/amazon/aws/cache.rb +141 -0
- data/lib/amazon/aws/search.rb +317 -0
- data/lib/amazon/aws/shoppingcart.rb +504 -0
- data/lib/amazon/aws.rb +1156 -0
- data/lib/amazon/locale.rb +102 -0
- data/lib/amazon.rb +99 -0
- data/test/setup.rb +31 -0
- data/test/tc_amazon.rb +20 -0
- data/test/tc_aws.rb +118 -0
- data/test/tc_item_search.rb +21 -0
- data/test/tc_multiple_operation.rb +58 -0
- data/test/tc_operation_request.rb +58 -0
- data/test/tc_serialisation.rb +103 -0
- data/test/tc_shopping_cart.rb +214 -0
- data/test/ts_aws.rb +12 -0
- metadata +95 -0
@@ -0,0 +1,48 @@
|
|
1
|
+
#!/usr/bin/ruby -w
|
2
|
+
#
|
3
|
+
# $Id: similarity_lookup1,v 1.1 2008/04/27 06:03:54 ianmacd Exp $
|
4
|
+
|
5
|
+
require 'amazon/aws'
|
6
|
+
require 'amazon/aws/search'
|
7
|
+
|
8
|
+
include Amazon::AWS
|
9
|
+
include Amazon::AWS::Search
|
10
|
+
|
11
|
+
# Example of a batch operation, using the ASIN as the shared ID.
|
12
|
+
#
|
13
|
+
sl = SimilarityLookup.new( [ 'B000AE4QEC', 'B000051WBE' ] )
|
14
|
+
|
15
|
+
# You can have multiple response groups.
|
16
|
+
#
|
17
|
+
rg = ResponseGroup.new( 'Medium', 'Offers', 'Reviews' )
|
18
|
+
|
19
|
+
req = Request.new
|
20
|
+
req.locale = 'uk'
|
21
|
+
|
22
|
+
resp = req.search( sl, rg )
|
23
|
+
item_sets = resp.similarity_lookup_response[0].items
|
24
|
+
|
25
|
+
item_sets.each do |item_set|
|
26
|
+
item_set.item.each do |item|
|
27
|
+
attribs = item.item_attributes[0]
|
28
|
+
puts attribs.label
|
29
|
+
if attribs.list_price
|
30
|
+
puts attribs.title, attribs.list_price[0].formatted_price
|
31
|
+
end
|
32
|
+
|
33
|
+
# Availability has become a cumbersome thing to retrieve in AWSv4.
|
34
|
+
#
|
35
|
+
puts 'Availability: %s' %
|
36
|
+
[ item.offers[0].offer[0].offer_listing[0].availability ]
|
37
|
+
puts 'Average rating: %s' % [ item.customer_reviews[0].average_rating ]
|
38
|
+
puts 'Reviewed by %s customers.' %
|
39
|
+
[ item.customer_reviews[0].total_reviews ]
|
40
|
+
|
41
|
+
puts 'Customers said:'
|
42
|
+
item.customer_reviews[0].review.each do |review|
|
43
|
+
puts ' %s (%s votes)' % [ review.summary, review.total_votes ]
|
44
|
+
end
|
45
|
+
|
46
|
+
puts
|
47
|
+
end
|
48
|
+
end
|
data/example/tag_lookup1
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
#!/usr/bin/ruby -w
|
2
|
+
#
|
3
|
+
# $Id: tag_lookup1,v 1.1 2008/04/27 19:46:43 ianmacd Exp $
|
4
|
+
|
5
|
+
require 'amazon/aws'
|
6
|
+
require 'amazon/aws/search'
|
7
|
+
|
8
|
+
include Amazon::AWS
|
9
|
+
include Amazon::AWS::Search
|
10
|
+
|
11
|
+
tag_str = 'Awful'
|
12
|
+
tl = TagLookup.new( tag_str )
|
13
|
+
|
14
|
+
# You can have multiple response groups.
|
15
|
+
#
|
16
|
+
rg = ResponseGroup.new( 'Tags', 'TagsSummary' )
|
17
|
+
|
18
|
+
req = Request.new
|
19
|
+
req.locale = 'us'
|
20
|
+
|
21
|
+
resp = req.search( tl, rg )
|
22
|
+
tag = resp.tag_lookup_response.tags.tag
|
23
|
+
|
24
|
+
printf( "Tag name '%s' has %d distinct items.\n", tag_str, tag.distinct_items )
|
25
|
+
printf( "Tag has %d distinct items.\n", tag.distinct_users )
|
26
|
+
printf( "Tag has %d total usages.\n", tag.total_usages )
|
27
|
+
printf( "Tagged for the first time in entity %s on %s\nby %s..\n",
|
28
|
+
tag.first_tagging.entity_id,
|
29
|
+
tag.first_tagging.time,
|
30
|
+
tag.first_tagging.user_id )
|
31
|
+
printf( "Tagged for the last time in entity %s on %s\nby %s..\n",
|
32
|
+
tag.last_tagging.entity_id,
|
33
|
+
tag.last_tagging.time,
|
34
|
+
tag.last_tagging.user_id )
|
@@ -0,0 +1,26 @@
|
|
1
|
+
#!/usr/bin/ruby -w
|
2
|
+
#
|
3
|
+
# $Id: transaction_lookup1,v 1.1 2008/04/27 21:24:21 ianmacd Exp $
|
4
|
+
|
5
|
+
require 'amazon/aws'
|
6
|
+
require 'amazon/aws/search'
|
7
|
+
|
8
|
+
include Amazon::AWS
|
9
|
+
include Amazon::AWS::Search
|
10
|
+
|
11
|
+
tl = TransactionLookup.new( '103-5663398-5028241' )
|
12
|
+
|
13
|
+
rg = ResponseGroup.new( 'TransactionDetails' )
|
14
|
+
|
15
|
+
req = Request.new
|
16
|
+
req.locale = 'us'
|
17
|
+
|
18
|
+
resp = req.search( tl, rg )
|
19
|
+
trans = resp.transaction_lookup_response.transactions.transaction
|
20
|
+
|
21
|
+
printf( "Transaction date was %s.\n", trans.transaction_date )
|
22
|
+
printf( "It was in the amount of %s and the seller was %s.\n",
|
23
|
+
trans.totals.total.formatted_price, trans.seller_name )
|
24
|
+
printf( "The shipping charge was %s and the package was sent by %s.\n",
|
25
|
+
trans.totals.shipping_charge.formatted_price,
|
26
|
+
trans.shipments.shipment.delivery_method )
|
@@ -0,0 +1,141 @@
|
|
1
|
+
# $Id: cache.rb,v 1.8 2008/06/10 06:33:46 ianmacd Exp $
|
2
|
+
#
|
3
|
+
|
4
|
+
module Amazon
|
5
|
+
|
6
|
+
module AWS
|
7
|
+
|
8
|
+
# This class provides a simple results caching system for operations
|
9
|
+
# performed by AWS.
|
10
|
+
#
|
11
|
+
# To use it, set _cache_ to *true* in either <tt>/etc/amazonrc</tt> or
|
12
|
+
# <tt>~/.amazonrc</tt>.
|
13
|
+
#
|
14
|
+
# By default, the cache directory used is <tt>/tmp/amazon</tt>, but this
|
15
|
+
# can be changed by defining _cache_dir_ in either <tt>/etc/amazonrc</tt>
|
16
|
+
# or <tt>~/.amazonrc</tt>.
|
17
|
+
#
|
18
|
+
# When a cache is used, Ruby/AWS will check the cache directory for a
|
19
|
+
# recent copy of a response to the exact operation that you are
|
20
|
+
# performing. If found, the cached response will be returned instead of
|
21
|
+
# the request being forwarded to the AWS servers for processing. If no
|
22
|
+
# (recent) copy is found, the request will be forwarded to the AWS servers
|
23
|
+
# as usual. Recency is defined here as less than 24 hours old.
|
24
|
+
#
|
25
|
+
class Cache
|
26
|
+
|
27
|
+
require 'fileutils'
|
28
|
+
|
29
|
+
begin
|
30
|
+
require 'md5'
|
31
|
+
rescue LoadError
|
32
|
+
# Ruby 1.9 has moved MD5.
|
33
|
+
#
|
34
|
+
require 'digest/md5'
|
35
|
+
end
|
36
|
+
|
37
|
+
# Exception class for bad cache paths.
|
38
|
+
#
|
39
|
+
class PathError < StandardError; end
|
40
|
+
|
41
|
+
# Length of one day in seconds
|
42
|
+
#
|
43
|
+
ONE_DAY = 86400 # :nodoc:
|
44
|
+
|
45
|
+
# Age in days below which to consider cache files valid.
|
46
|
+
#
|
47
|
+
MAX_AGE = 1.0
|
48
|
+
|
49
|
+
# Default cache location.
|
50
|
+
#
|
51
|
+
DEFAULT_CACHE_DIR = '/tmp/amazon'
|
52
|
+
|
53
|
+
attr_reader :path
|
54
|
+
|
55
|
+
def initialize(path=DEFAULT_CACHE_DIR)
|
56
|
+
path ||= DEFAULT_CACHE_DIR
|
57
|
+
|
58
|
+
::FileUtils::mkdir_p( path ) unless File.exists? path
|
59
|
+
|
60
|
+
unless File.directory? path
|
61
|
+
raise PathError, "cache path #{path} is not a directory"
|
62
|
+
end
|
63
|
+
|
64
|
+
unless File.readable? path
|
65
|
+
raise PathError, "cache path #{path} is not readable"
|
66
|
+
end
|
67
|
+
|
68
|
+
unless File.writable? path
|
69
|
+
raise PathError, "cache path #{path} is not writable"
|
70
|
+
end
|
71
|
+
|
72
|
+
@path = path
|
73
|
+
end
|
74
|
+
|
75
|
+
|
76
|
+
# Determine whether or not the the response to a given URL is cached.
|
77
|
+
# Returns *true* or *false*.
|
78
|
+
#
|
79
|
+
def cached?(url)
|
80
|
+
digest = Digest::MD5.hexdigest( url )
|
81
|
+
|
82
|
+
cache_files = Dir.glob( File.join( @path, '*' ) ).map do |d|
|
83
|
+
File.basename( d )
|
84
|
+
end
|
85
|
+
|
86
|
+
return cache_files.include?( digest ) &&
|
87
|
+
( Time.now - File.mtime( File.join( @path, digest ) ) ) /
|
88
|
+
ONE_DAY <= MAX_AGE
|
89
|
+
end
|
90
|
+
|
91
|
+
|
92
|
+
# Retrieve the cached response associated with _url_.
|
93
|
+
#
|
94
|
+
def fetch(url)
|
95
|
+
digest = Digest::MD5.hexdigest( url )
|
96
|
+
cache_file = File.join( @path, digest )
|
97
|
+
|
98
|
+
return nil unless File.exist? cache_file
|
99
|
+
|
100
|
+
Amazon.dprintf( 'Fetching %s from cache...', digest )
|
101
|
+
File.open( File.join( cache_file ) ).readlines.to_s
|
102
|
+
end
|
103
|
+
|
104
|
+
|
105
|
+
# Cache the data from _contents_ and associate it with _url_.
|
106
|
+
#
|
107
|
+
def store(url, contents)
|
108
|
+
digest = Digest::MD5.hexdigest( url )
|
109
|
+
cache_file = File.join( @path, digest )
|
110
|
+
|
111
|
+
Amazon.dprintf( 'Caching %s...', digest )
|
112
|
+
File.open( cache_file, 'w' ) { |f| f.puts contents }
|
113
|
+
end
|
114
|
+
|
115
|
+
|
116
|
+
# This method flushes all files from the cache directory specified
|
117
|
+
# in the object's <i>@path</i> variable.
|
118
|
+
#
|
119
|
+
def flush_all
|
120
|
+
FileUtils.rm Dir.glob( File.join( @path, '*' ) )
|
121
|
+
end
|
122
|
+
|
123
|
+
|
124
|
+
# This method flushes expired files from the cache directory specified
|
125
|
+
# in the object's <i>@path</i> variable.
|
126
|
+
#
|
127
|
+
def flush_expired
|
128
|
+
now = Time.now
|
129
|
+
|
130
|
+
expired_files = Dir.glob( File.join( @path, '*' ) ).find_all do |f|
|
131
|
+
( now - File.mtime( f ) ) / ONE_DAY > MAX_AGE
|
132
|
+
end
|
133
|
+
|
134
|
+
FileUtils.rm expired_files
|
135
|
+
end
|
136
|
+
|
137
|
+
end
|
138
|
+
|
139
|
+
end
|
140
|
+
|
141
|
+
end
|
@@ -0,0 +1,317 @@
|
|
1
|
+
# $Id: search.rb,v 1.21 2008/05/31 19:42:04 ianmacd Exp $
|
2
|
+
#
|
3
|
+
|
4
|
+
module Amazon
|
5
|
+
|
6
|
+
module AWS
|
7
|
+
|
8
|
+
require 'amazon/aws'
|
9
|
+
require 'net/http'
|
10
|
+
require 'rexml/document'
|
11
|
+
|
12
|
+
# Load this library with:
|
13
|
+
#
|
14
|
+
# require 'amazon/aws/search'
|
15
|
+
#
|
16
|
+
module Search
|
17
|
+
|
18
|
+
class Request
|
19
|
+
|
20
|
+
include REXML
|
21
|
+
|
22
|
+
# Exception class for bad access key ID.
|
23
|
+
#
|
24
|
+
class AccessKeyIdError < StandardError; end
|
25
|
+
|
26
|
+
# Exception class for bad locales.
|
27
|
+
#
|
28
|
+
class LocaleError < StandardError; end
|
29
|
+
|
30
|
+
attr_reader :conn, :locale, :user_agent
|
31
|
+
attr_writer :cache
|
32
|
+
|
33
|
+
# This method is used to generate an AWS search request object.
|
34
|
+
#
|
35
|
+
# _key_id_ is your AWS {access key
|
36
|
+
# ID}[https://aws-portal.amazon.com/gp/aws/developer/registration/index.html],
|
37
|
+
# _associate_ is your
|
38
|
+
# Associates[http://docs.amazonwebservices.com/AWSECommerceService/2008-04-07/GSG/BecominganAssociate.html]
|
39
|
+
# tag (if any), _locale_ is the locale in which you which to work
|
40
|
+
# (*us* for amazon.com[http://www.amazon.com/], *uk* for
|
41
|
+
# amazon.co.uk[http://www.amazon.co.uk], etc.), _cache_ is whether or
|
42
|
+
# not you wish to utilise a response cache, and _user_agent_ is the
|
43
|
+
# client name to pass when performing calls to AWS. By default,
|
44
|
+
# _user_agent_ will be set to a string identifying the Ruby/AWS
|
45
|
+
# library and its version number.
|
46
|
+
#
|
47
|
+
# _locale_ and _cache_ can also be set later, if you wish to change
|
48
|
+
# the current behaviour.
|
49
|
+
#
|
50
|
+
# Example:
|
51
|
+
#
|
52
|
+
# req = Request.new( '0Y44V8FAFNM119CX4TR2', 'calibanorg-20' )
|
53
|
+
#
|
54
|
+
def initialize(key_id=nil, associate=nil, locale=nil, cache=nil,
|
55
|
+
user_agent=USER_AGENT)
|
56
|
+
|
57
|
+
@config ||= Amazon::Config.new
|
58
|
+
|
59
|
+
def_locale = locale
|
60
|
+
locale = 'us' unless locale
|
61
|
+
locale.downcase!
|
62
|
+
|
63
|
+
key_id ||= @config['key_id']
|
64
|
+
cache = @config['cache'] if cache.nil?
|
65
|
+
|
66
|
+
# Take locale from config file if no locale was passed to method.
|
67
|
+
#
|
68
|
+
if @config.key?( 'locale' ) && ! def_locale
|
69
|
+
locale = @config['locale']
|
70
|
+
end
|
71
|
+
validate_locale( locale )
|
72
|
+
|
73
|
+
if key_id.nil?
|
74
|
+
raise AccessKeyIdError, 'key_id may not be nil'
|
75
|
+
end
|
76
|
+
|
77
|
+
@key_id = key_id
|
78
|
+
@tag = associate || @config['associate'] || DEF_ASSOC[locale]
|
79
|
+
@user_agent = user_agent
|
80
|
+
@cache = unless cache == 'false' || cache == false
|
81
|
+
Amazon::AWS::Cache.new( @config['cache_dir'] )
|
82
|
+
else
|
83
|
+
nil
|
84
|
+
end
|
85
|
+
self.locale = locale
|
86
|
+
end
|
87
|
+
|
88
|
+
|
89
|
+
# Assign a new locale. If the locale we're coming from is using the
|
90
|
+
# default Associate ID for that locale, then we use the new locale's
|
91
|
+
# default ID, too.
|
92
|
+
#
|
93
|
+
def locale=(l) # :nodoc:
|
94
|
+
old_locale = @locale ||= nil
|
95
|
+
@locale = validate_locale( l )
|
96
|
+
|
97
|
+
# Use the new locale's default ID if the ID currently in use is the
|
98
|
+
# current locale's default ID.
|
99
|
+
#
|
100
|
+
if @tag == Amazon::AWS::DEF_ASSOC[old_locale]
|
101
|
+
@tag = Amazon::AWS::DEF_ASSOC[@locale]
|
102
|
+
end
|
103
|
+
|
104
|
+
# We must now set up a new HTTP connection to the correct server for
|
105
|
+
# this locale, unless the same server is used for both.
|
106
|
+
#
|
107
|
+
unless Amazon::AWS::ENDPOINT[@locale] ==
|
108
|
+
Amazon::AWS::ENDPOINT[old_locale]
|
109
|
+
#connect( @locale )
|
110
|
+
@conn = nil
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
|
115
|
+
# If @cache has simply been assigned *true* at some point in time,
|
116
|
+
# assign a proper cache object to it when it is referenced. Otherwise,
|
117
|
+
# just return its value.
|
118
|
+
#
|
119
|
+
def cache # :nodoc:
|
120
|
+
if @cache == true
|
121
|
+
@cache = Amazon::AWS::Cache.new( @config['cache_dir'] )
|
122
|
+
else
|
123
|
+
@cache
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
|
128
|
+
# Verify the validity of a locale string. _l_ is the locale string.
|
129
|
+
#
|
130
|
+
def validate_locale(l)
|
131
|
+
unless Amazon::AWS::ENDPOINT.has_key? l
|
132
|
+
raise LocaleError, "invalid locale: #{l}"
|
133
|
+
end
|
134
|
+
l
|
135
|
+
end
|
136
|
+
private :validate_locale
|
137
|
+
|
138
|
+
|
139
|
+
# Return an HTTP connection for the current _locale_.
|
140
|
+
#
|
141
|
+
def connect(locale)
|
142
|
+
if ENV.key? 'http_proxy'
|
143
|
+
uri = URI.parse( ENV['http_proxy'] )
|
144
|
+
proxy_user = proxy_pass = nil
|
145
|
+
proxy_user, proxy_pass = uri.userinfo.split( /:/ ) if uri.userinfo
|
146
|
+
@conn = Net::HTTP::Proxy( uri.host, uri.port, proxy_user,
|
147
|
+
proxy_pass ).start(
|
148
|
+
Amazon::AWS::ENDPOINT[locale].host )
|
149
|
+
else
|
150
|
+
@conn = Net::HTTP::start( Amazon::AWS::ENDPOINT[locale].host )
|
151
|
+
end
|
152
|
+
end
|
153
|
+
private :connect
|
154
|
+
|
155
|
+
|
156
|
+
# Reconnect to the server if our connection has been lost (due to a
|
157
|
+
# time-out, etc.).
|
158
|
+
#
|
159
|
+
def reconnect # :nodoc:
|
160
|
+
connect( self.locale )
|
161
|
+
self
|
162
|
+
end
|
163
|
+
|
164
|
+
|
165
|
+
# This method checks for errors in an XML response returned by AWS.
|
166
|
+
# _xml_ is the XML node below which to search.
|
167
|
+
#
|
168
|
+
def error_check(xml)
|
169
|
+
if xml = xml.elements['Errors/Error']
|
170
|
+
error = Amazon::AWS::Error::AWSError.new( xml )
|
171
|
+
raise error.exception
|
172
|
+
end
|
173
|
+
end
|
174
|
+
private :error_check
|
175
|
+
|
176
|
+
|
177
|
+
# Perform a search of the AWS catalogue. _operation_ is one of the
|
178
|
+
# objects subclased from _Operation_, such as _ItemSearch_,
|
179
|
+
# _ItemLookup_, etc. It may also be a _MultipleOperation_ object.
|
180
|
+
#
|
181
|
+
# _response_group_ will apply to all both operations contained in
|
182
|
+
# _operation_, if _operation_ is a _MultipleOperation_ object.
|
183
|
+
#
|
184
|
+
# _nr_pages_ is the number of results pages to return. It defaults to
|
185
|
+
# <b>1</b>. If a higher number is given, pages 1 to _nr_pages_ will be
|
186
|
+
# returned. If the special value <b>:ALL_PAGES</b> is given, all
|
187
|
+
# results pages will be returned.
|
188
|
+
#
|
189
|
+
# If operation is of class _MultipleOperation_, the operations
|
190
|
+
# combined within will return only the first page, regardless of
|
191
|
+
# whether a higher number of pages is requested.
|
192
|
+
#
|
193
|
+
def search(operation, response_group, nr_pages=1)
|
194
|
+
q_params = Amazon::AWS::SERVICE.
|
195
|
+
merge( { 'AWSAccessKeyId' => @key_id,
|
196
|
+
'AssociateTag' => @tag } ).
|
197
|
+
merge( operation.params ).
|
198
|
+
merge( response_group.params )
|
199
|
+
|
200
|
+
query = Amazon::AWS.assemble_query( q_params )
|
201
|
+
page = Amazon::AWS.get_page( self, query )
|
202
|
+
doc = Document.new( page )
|
203
|
+
|
204
|
+
# Some errors occur at the very top level of the XML. For example,
|
205
|
+
# when no Operation parameter is given. This should not be possible
|
206
|
+
# with user code, but occurred during debugging of this library.
|
207
|
+
#
|
208
|
+
error_check( doc )
|
209
|
+
|
210
|
+
# Fundamental errors happen at the OperationRequest level. For
|
211
|
+
# example, if an invalid AWSAccessKeyId is used.
|
212
|
+
#
|
213
|
+
error_check( doc.elements['*/OperationRequest'] )
|
214
|
+
|
215
|
+
# Check for parameter and value errors deeper down, inside Request.
|
216
|
+
#
|
217
|
+
if operation.kind == 'MultipleOperation'
|
218
|
+
|
219
|
+
# Everything is a level deeper, because of the
|
220
|
+
# <MultiOperationResponse> container.
|
221
|
+
#
|
222
|
+
# Check for errors in the first operation.
|
223
|
+
#
|
224
|
+
error_check( doc.elements['*/*/*/Request'] )
|
225
|
+
|
226
|
+
# Check for errors in the second operation.
|
227
|
+
#
|
228
|
+
error_check( doc.elements['*/*[3]/*/Request'] )
|
229
|
+
|
230
|
+
# If second operation is batched, check for errors in its 2nd set
|
231
|
+
# of results.
|
232
|
+
#
|
233
|
+
if batched = doc.elements['*/*[3]/*[2]/Request']
|
234
|
+
error_check( batched )
|
235
|
+
end
|
236
|
+
else
|
237
|
+
error_check( doc.elements['*/*/Request'] )
|
238
|
+
|
239
|
+
# If operation is batched, check for errors in its 2nd set of
|
240
|
+
# results.
|
241
|
+
#
|
242
|
+
if batched = doc.elements['*/*[3]/Request']
|
243
|
+
error_check( batched )
|
244
|
+
end
|
245
|
+
end
|
246
|
+
|
247
|
+
# FIXME: This doesn't work if a MultipleOperation was used, because
|
248
|
+
# <TotalPages> will be nested one level deeper. It's therefore
|
249
|
+
# currently only possible to return the first page of results
|
250
|
+
# for operations combined in a MultipleOperation.
|
251
|
+
#
|
252
|
+
if doc.elements['*/*[2]/TotalPages']
|
253
|
+
total_pages = doc.elements['*/*[2]/TotalPages'].text.to_i
|
254
|
+
else
|
255
|
+
total_pages = 1
|
256
|
+
end
|
257
|
+
|
258
|
+
# Create a root AWS object and walk the XML response tree.
|
259
|
+
#
|
260
|
+
aws = AWS::AWSObject.new( operation )
|
261
|
+
aws.walk( doc )
|
262
|
+
result = aws
|
263
|
+
|
264
|
+
# If only one page has been requested or only one page is available,
|
265
|
+
# we can stop here. First yield to the block, if given.
|
266
|
+
#
|
267
|
+
if nr_pages == 1 || ( tp = total_pages ) == 1
|
268
|
+
yield result if block_given?
|
269
|
+
return result
|
270
|
+
end
|
271
|
+
|
272
|
+
# Limit the number of pages to the maximum number available.
|
273
|
+
#
|
274
|
+
nr_pages = tp.to_i if nr_pages == :ALL_PAGES || nr_pages > tp.to_i
|
275
|
+
|
276
|
+
# Iterate over pages 2 and higher, but go no higher than MAX_PAGES.
|
277
|
+
#
|
278
|
+
2.upto( nr_pages < MAX_PAGES ? nr_pages : MAX_PAGES ) do |page_nr|
|
279
|
+
query = Amazon::AWS.assemble_query(
|
280
|
+
q_params.merge( { 'ItemPage' => page_nr } ) )
|
281
|
+
page = Amazon::AWS.get_page( self, query )
|
282
|
+
doc = Document.new( page )
|
283
|
+
|
284
|
+
# Check for errors.
|
285
|
+
#
|
286
|
+
error_check( doc.elements['*/OperationRequest'] )
|
287
|
+
error_check( doc.elements['*/*/Request'] )
|
288
|
+
|
289
|
+
# Create a new AWS object and walk the XML response tree.
|
290
|
+
#
|
291
|
+
aws = AWS::AWSObject.new
|
292
|
+
aws.walk( doc )
|
293
|
+
|
294
|
+
# When dealing with multiple pages, we return not just an
|
295
|
+
# AWSObject, but an array of them.
|
296
|
+
#
|
297
|
+
result = [ result ] unless result.is_a? Array
|
298
|
+
|
299
|
+
# Append the new object to the array.
|
300
|
+
#
|
301
|
+
result << aws
|
302
|
+
end
|
303
|
+
|
304
|
+
# Yield each object to the block, if given.
|
305
|
+
#
|
306
|
+
result.each { |r| yield r } if block_given?
|
307
|
+
|
308
|
+
result
|
309
|
+
end
|
310
|
+
|
311
|
+
end
|
312
|
+
|
313
|
+
end
|
314
|
+
|
315
|
+
end
|
316
|
+
|
317
|
+
end
|