ruby-aaws 0.5.1 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
data/NEWS CHANGED
@@ -1,4 +1,113 @@
1
- $Id: NEWS,v 1.17 2009/03/28 23:04:22 ianmacd Exp $
1
+ $Id: NEWS,v 1.18 2009/05/26 15:25:19 ianmacd Exp $
2
+
3
+
4
+ 0.6.0 - 2009-05-26
5
+ ------------------
6
+
7
+ 1. Requests to AWS can now be signed in order to authenticate them. Amazon
8
+ plans to make the signing of requests mandatory as of 15th August 2009, so
9
+ it is recommended to start doing so now.
10
+
11
+ To have your requests automatically signed by Ruby/AWS, simply add the
12
+ 'secret_key_id' parameter to your ~/.amazonrc configuration file. Its value
13
+ should, rather predictably, be your secret access key, which can be
14
+ retrieved here:
15
+
16
+ https://aws-portal.amazon.com/gp/aws/developer/account/index.html?ie=UTF8&action=access-key
17
+
18
+ You needn't be concerned about Amazon's warnings not to show your secret
19
+ key to anyone else, because it will be used only for signing requests,
20
+ prior to sending them. The key itself will not be sent over the network to
21
+ Amazon, even in encrypted form.
22
+
23
+ In order to incorporate the new functionality, minor changes had to be made
24
+ to the way the AWS request URLs are encoded. This change means that
25
+ previous requests cached by earlier versions of Ruby/AWS will not be found
26
+ in the cache. This is a minor, one-time inconvenience, and it just means
27
+ that the requests will be performed and cached again.
28
+
29
+ 2. When Amazon's AWS servers check whether the correct signature has been
30
+ applied to a request, they recalculate the signature based on the data in
31
+ the request and check for a match with the signature supplied by Ruby/AWS.
32
+
33
+ This introduces a complicating factor, namely the treatment of non-ASCII
34
+ characters in the request, such as accented letters. When recalculating the
35
+ signature, Amazon will use the UTF-8 representation of any such characters.
36
+ This will cause a signature mismatch if you used a different encoding, such
37
+ as ISO-8859-1 (a.k.a. Latin-1), when you supplied values for your request
38
+ parameters.
39
+
40
+ Ruby/AWS can't (reliably) dynamically determine which character encoding
41
+ your strings use, so this information can now be supplied via the
42
+ ~/.amazonrc configuration file, using the 'encoding' parameter. This should
43
+ be set to whichever encoding you use. If left unset, it defaults to UTF-8.
44
+ An exception will be raised if you attempt to use an invalid (i.e. unknown)
45
+ encoding.
46
+
47
+ Currently, the encoding you use makes no difference unless your requests
48
+ are being signed, but because signing will soon be mandatory, I recommend
49
+ you explicitly state which encoding you intend to use.
50
+
51
+ You may also change the encoding in use at any time by assigning to the
52
+ @encoding instance variable of your Request object.
53
+
54
+ 3. The robustness of the software has been improved by handling the following
55
+ additional exceptions while communicating with the AWS servers:
56
+ Errno::ECONNREFUSED, Errno::ECONNABORTED, Errno::ETIMEDOUT and
57
+ Timeout::Error. Users have reported that all of these occur from time to
58
+ time, although only Windows platforms seem to suffer from
59
+ Errno::ECONNABORTED.
60
+
61
+ 4. The version of the AWS API used is now 2009-03-31, the latest at the time
62
+ of writing.
63
+
64
+ 5. <RANT>
65
+ Amazon must have appointed a new interim Senior Vice-President of
66
+ Outward-Facing Moniker Reconciliation or something, because earlier this
67
+ month, on 8th May, I received an e-mail from Amazon, informing me that the
68
+ Web service formerly known as Amazon Web Services, latterly the E-Commerce
69
+ Service, and then, until this month, the Amazon Associates Web Service, is
70
+ to undergo yet another name change.
71
+
72
+ Once again, the reason for the new moniker is that it ostensibly "more
73
+ accurately reflects the purpose of the API". The new sobriquet is the
74
+ highly reflective 'Product Advertising API'.
75
+
76
+ It never ceases to amaze me that the collective intellectual might of a
77
+ company as large and resourceful as Amazon cannot, over a period of five
78
+ years, converge to decisively name an API.
79
+
80
+ How long until the reins of responsibility for this offering change hands
81
+ once again and the next in a growing line of misguided middle managers
82
+ decides that he can best raise his profile with his superiors by changing
83
+ the name of the API to "better reflect its purpose"?
84
+
85
+ Well, I'm resistant to change, especially stupid, time-wasting changes, so
86
+ I'll be continuing to refer to AWS as AWS for the foreseeable future. When
87
+ I say AWS, you'll know I mean the product whose name is woefully subject to
88
+ Amazon's whimsy.
89
+
90
+ The same e-mail informed me that Amazon would soon be introducing mandatory
91
+ authentication of AWS requests.
92
+
93
+ I downloaded the latest developer guide, wrote some code to implement
94
+ request signatures, and then spent a good couple of hours trying to make my
95
+ code produce the sample results shown in the developer guide.
96
+
97
+ Ultimately, I realised that the sample requests in the developer guide
98
+ could not have produced the output claimed by the documentation.
99
+
100
+ Not only that, but 3 of the 10 steps in the developer guide, in the section
101
+ detailing how to sign AWS requests, contain critical errors. This means
102
+ that Amazon didn't once follow their own documentation to verify its
103
+ correctness.
104
+
105
+ Most of the mistakes have since been silently rectified by Amazon, without
106
+ any mention on the AWS forum or revising the document version. Who knows
107
+ how often the developer guide changes on a day to day basis. I had thought
108
+ each dated version to be a static, completed work, but this is apparently
109
+ not the case.
110
+ </RANT>
2
111
 
3
112
 
4
113
  0.5.1 - 2009-03-29
data/README CHANGED
@@ -1,4 +1,4 @@
1
- $Id: README,v 1.20 2009/03/28 23:04:23 ianmacd Exp $
1
+ $Id: README,v 1.21 2009/05/25 23:38:24 ianmacd Exp $
2
2
 
3
3
 
4
4
  Introduction
@@ -56,9 +56,10 @@ good news is that, in most cases, this isn't as much work as it might sound.
56
56
 
57
57
  Another bit of good news is that the /etc/amazonrc and ~/.amazonrc files used
58
58
  by Ruby/Amazon _are_ compatible with Ruby/AWS. The only change required for
59
- Ruby/AWS is the addition of a 'key_id' parameter, which should contain your
60
- AWS Access Key ID. That fact notwithstanding, as of version 0.5.0, Ruby/AWS
61
- also supports a more flexible, locale-specific configuration syntax.
59
+ Ruby/AWS is the addition of the 'key_id' and 'secret_key_id' parameters, which
60
+ should contain your AWS Access Key ID and its secret counterpart. That fact
61
+ notwithstanding, as of version 0.5.0, Ruby/AWS also supports a more flexible,
62
+ locale-specific configuration syntax.
62
63
 
63
64
  Amazon finally decomissioned v3 of the AWS API on 2008-03-31. As a result, the
64
65
  original Ruby/Amazon library no longer functions and is therefore obsolete.
@@ -79,10 +80,10 @@ Please obtain and use an AWS Access Key ID instead.
79
80
  API version
80
81
  -----------
81
82
 
82
- Ruby/AWS currently requests the 2009-02-01 revision of the AWS API when
83
+ Ruby/AWS currently requests the 2009-03-31 revision of the AWS API when
83
84
  performing its operations:
84
85
 
85
- http://docs.amazonwebservices.com/AWSECommerceService/2009-02-01/DG/
86
+ http://docs.amazonwebservices.com/AWSECommerceService/2009-03-31/DG/
86
87
 
87
88
  However, a different version can be requested via the 'api' parameter in the
88
89
  user configuration file.
@@ -91,19 +92,20 @@ user configuration file.
91
92
  Status and functionality
92
93
  ------------------------
93
94
 
94
- Ruby/AWS is currently beta code. Amongst other things, this means:
95
+ Ruby/AWS is currently beta software. Amongst other things, this means:
95
96
 
96
- - You will encounter bugs, but hopefully not too many and none too serious. If
97
- you tell me about them, I will endeavour to fix them.
97
+ - You will encounter bugs, but hopefully not too many and none too serious.
98
+ Tell me about them and I will endeavour to fix them.
98
99
 
99
- - The documentation is incomplete, but steadily getting better. Version 0.0.1
100
- had virtually none, so consider yourself lucky.
100
+ - The documentation isn't what it could be, but it's hopefully enough to get
101
+ you up and running.
101
102
 
102
- - Not all features are currently implemented. Others may not be _fully_
103
- implemented. Yet others may not be _properly_ implemented.
103
+ - Not all features are currently implemented. Others may not yet be _fully_
104
+ implemented. Some, I probably haven't even thought of yet. Again, if
105
+ something's missing, tell me, and if it makes sense, I'll add it.
104
106
 
105
- Nevertheless, the AWS v4 API is now more or less fully supported, with only
106
- small gaps in the functionality of some operations.
107
+ In spite of this shortcomings, the AWS v4 API is more or less fully
108
+ supported, with only small gaps in the functionality of some operations.
107
109
 
108
110
  Currently implemented operations are:
109
111
 
@@ -130,19 +132,21 @@ Ruby/AWS is currently beta code. Amongst other things, this means:
130
132
  CartModify
131
133
  CartClear
132
134
 
133
- Version 0.4.0 also adds:
135
+ Version 0.4.0 adds the remaining shopping-cart operation, which I had first
136
+ thought superfluous:
134
137
 
135
138
  CartGet
136
139
 
137
- Multiple operations are supported, but not well tested.
140
+ Multiple operations are supported, but not well tested (by me, anyway).
138
141
 
139
142
  As of version 0.5.0, batch operations are fully supported, using the
140
143
  Operation#batch method.
141
144
 
142
- Beware of bugs in this area. There appear to also be (undocumented)
143
- Amazon-imposed restrictions on the use of multiple operations and batch
144
- requests, so some experimentation on your part will probably be required to
145
- determine what works and what doesn't.
145
+ Beware of bugs in this area. Quite apart from any mistakes I've made in the
146
+ implementation, there appear to also be (undocumented) Amazon-imposed
147
+ restrictions on the use of multiple operations and batch requests, so some
148
+ experimentation will be required on your part to determine what works and
149
+ what doesn't.
146
150
 
147
151
  The 2008-08-19 version of the AWS API added the following operations:
148
152
 
@@ -150,21 +154,21 @@ Ruby/AWS is currently beta code. Amongst other things, this means:
150
154
  VehiclePartSearch
151
155
  VehicleSearch
152
156
 
153
- These are supported by Ruby/AWS as of version 0.5.0
157
+ These are supported by Ruby/AWS from version 0.5.0 onwards.
154
158
 
155
159
  - Classes, methods, constants and instance variables may change name in the
156
- future. These various objects may appear from nowhere, change shape, grow,
157
- shrink or disappear entirely. Such fundamental changes will almost certainly
158
- break existing code, so I will endeavour to keep them to a minimum.
160
+ future. New ones may appear from nowhere and existing ones may change shape,
161
+ grow, shrink or disappear without trace. Such fundamental changes will break
162
+ existing code, so I will endeavour to keep them to a minimum.
159
163
 
160
164
  In short, code written to work with this release of Ruby/AWS may stop working
161
165
  when you upgrade to the next. In fact, it may even stop working _during_ this
162
- release, because it's possible there are circumstances that would cause an
163
- exception to be raised, that I haven't come across in my limited testing of
164
- the code. It's also possible that future changes made by Amazon will affect
165
- Ruby/AWS in unexpected ways.
166
+ release cycle, because it's possible there are fatal conditions that I didn't
167
+ encounter in my limited testing of the code. It's also possible that future
168
+ (possibly unannounced) changes made by Amazon will affect Ruby/AWS in
169
+ ways I can't anticipate.
166
170
 
167
- That said, the Ruby/AWS's API is pretty stable at this point in time. I won't
171
+ That said, the Ruby/AWS API is pretty stable at this point in time. I won't
168
172
  break any of the method interfaces without seriously considering the merits of
169
173
  doing so.
170
174
 
@@ -179,22 +183,43 @@ choose between an installation script and a RubyGems installation.
179
183
  Usage
180
184
  -----
181
185
 
182
- First of all, create either /etc/amazonrc or ~/.amazonrc. Its contents should
183
- look something like this:
186
+ First of all, create either /etc/amazonrc or ~/.amazonrc as a plain text file.
187
+ Its contents should look something like this:
184
188
 
185
189
  # Any line that starts with a hash character is a comment.
186
190
  key_id = '0Y44V8G41KCQPGF6XYZ2'
191
+ secret_key_id = 'k+kuddeoQJzUnImC0Hyy21J4xLWQc1hbvfQ+7F1G
187
192
  associate = 'fuzbarorg-21'
188
193
  cache = false
189
194
  locale = 'uk'
195
+ encoding = 'iso-8859-15'
196
+
197
+ Including your secret key is a new feature in version 0.6.0 of Ruby/AWS. If
198
+ you choose to do so, your requests to AWS will be signed for authentication by
199
+ the Amazon's servers.
200
+
201
+ Amazon plans to make this practice obligatory as of 15th August 2009, so I
202
+ recommend that you adopt it well ahead of time.
203
+
204
+ When Amazon checks for a valid signature, it does so by comparing its
205
+ computation of the signature with the one supplied by the user. In doing this,
206
+ Amazon uses the UTF-8 representation of parameter values that you supply, even
207
+ if you use a different encoding.
208
+
209
+ In order to have Ruby/AWS properly reencode your strings as UTF-8, you need
210
+ to tell it which encoding you are using. The 'encoding' parameter can be used
211
+ for this, but you can omit it if your strings are already UTF-8, because this
212
+ is the default.
190
213
 
191
214
  As of version 0.5.0 of Ruby/AWS, the following locale-specific configuration
192
215
  syntax is also supported:
193
216
 
194
217
  [global]
195
218
  key_id = '0Y44V8G41KCQPGF6XYZ2'
196
- locale = 'uk'
219
+ secret_key_id = 'k+kuddeoQJzUnImC0Hyy21J4xLWQc1hbvfQ+7F1G
197
220
  cache = false
221
+ locale = 'uk'
222
+ encoding = 'iso-8859-15'
198
223
  # Request a specific version of the API.
199
224
  # api = '2008-03-03'
200
225
 
@@ -204,16 +229,20 @@ syntax is also supported:
204
229
  [us]
205
230
  associate = 'fuzbarorg-20'
206
231
 
207
- Because you're embedding your key ID in the file, you should protect it (on
208
- UNIX and equivalent systems) by making it mode 0600:
232
+ This enables the use of a different associate tag for each locale, although,
233
+ oddly enough, no-one has ever requested this feature.
234
+
235
+ Because you're embedding your personal keys in the file, you should protect it
236
+ (on UNIX and equivalent systems) by making it mode 0600:
209
237
 
210
238
  $ chmod 600 ~/.amazonrc
211
239
 
212
- If you define 'cache' to be 'true', you may also define 'cache_dir' to point
213
- to somewhere other the default, /tmp/amazon.
240
+ If you define 'cache' to be 'true', you may want to also define 'cache_dir' to
241
+ point to somewhere other the default cache directory, /tmp/amazon.
214
242
 
215
243
  If you want to place .amazonrc somewhere other than $HOME, you may set
216
- $AMAZONRCDIR in the environment, as this location is checked prior to $HOME.
244
+ the $AMAZONRCDIR environment variable, as this location is checked prior to
245
+ $HOME.
217
246
 
218
247
  If you're using Windows, $HOME is usually undefined, so a number of additional
219
248
  locations are checked for .amazonrc.
@@ -230,13 +259,13 @@ $AMAZONRCDIR and $HOME are defined, but only the path specified by $HOME
230
259
  contains a file called .amazonrc, it will not be found.
231
260
 
232
261
  If you want the user configuration file to be called something other than
233
- .amazonrc, you may define $AMAZONRCFILE in the environment.
262
+ .amazonrc, you may define the $AMAZONRCFILE environment variable.
234
263
 
235
- Once you have your configuration file, you can get started on your code.
264
+ Once you have your configuration file, you can get started writing your code.
236
265
 
237
- Here's some basic code, indicating how to perform an ItemSearch, probably the
266
+ Here's a basic example, showing how to perform an ItemSearch, probably the
238
267
  most common type of AWS operation. Please see the ./examples subdirectory for
239
- more examples of working code.
268
+ more examples of contrived, but working code.
240
269
 
241
270
  --
242
271
 
@@ -288,11 +317,13 @@ XML to Ruby mapping
288
317
  -------------------
289
318
 
290
319
  Here, I will discuss the mapping of the XML returned from AWS to native Ruby
291
- objects and data.
320
+ objects and data. Note that the XML shown below was that returned at the time
321
+ of writing and may look different to what you would see today if you were to
322
+ execute the same request.
292
323
 
293
- When the following code:
324
+ When this code:
294
325
 
295
- resp = req.search( is, rg )
326
+ resp = req.search( is, rg )
296
327
 
297
328
  was called in the previous section, the following URL was composed and sent to
298
329
  AWS as an HTTP GET operation:
@@ -370,7 +401,7 @@ the following statements would all be true:
370
401
  - ItemAttributes, Author, Manufacturer, ProductGroup and Title would all be
371
402
  dynamically defined subclasses of AWSObject.
372
403
 
373
- - An instance of the ItemAttributes class would be instantiated, with instance
404
+ - An instance of the ItemAttributes class would be created, with instance
374
405
  variables @author, @manufacturer, @product_group and @title.
375
406
 
376
407
  - To each of these instance variables would respectively be assigned an array
@@ -379,13 +410,15 @@ the following statements would all be true:
379
410
  would all be single element arrays, because there's only one instance of
380
411
  each kind of tag in the XML.
381
412
 
382
- - These lowest level objects would have no instance variables, because the
383
- corresponding XML elements contain no children, just a value. These objects
384
- are therefore directly assigned the value of the corresponding XML element.
413
+ - The Author, Manufacturer, ProductGroup and Title objects would have no
414
+ instance variables of their own, because the corresponding XML elements
415
+ have no children, just a value. These objects are therefore directly
416
+ assigned the value in question.
385
417
 
386
- So, if resp is the top level AWSObject created and returned by calling
387
- Amazon::AWS::Search::Request#search on the Request object, and we'd like to
388
- know the ASIN of the first item found, we can refer to this as follows:
418
+ So, if resp is the top level AWSObject created and returned by calling the
419
+ Amazon::AWS::Search::Request#search method of the Request object, and we'd
420
+ like to know the ASIN of the first item found, we can refer to this as
421
+ follows:
389
422
 
390
423
  resp.item_search_response[0].items[0].item[0].asin
391
424
 
@@ -393,101 +426,105 @@ Looking at each component of this chain in turn:
393
426
 
394
427
  - resp is an AWSObject with a single instance variable, @item_search_response.
395
428
  This is because the entire XML response is contained within a single
396
- <ItemSearchResponse> tag pair, so there's nothing else at the top level.
429
+ <ItemSearchResponse> element, so there's nothing else at the top level.
397
430
 
398
431
  - resp.item_search_response is assigned an array of ItemSearchResponse
399
- objects. Because there's only a single <ItemSearchResponse> tag pair in the
432
+ objects. Because there's only a single <ItemSearchResponse> element in the
400
433
  whole document (containing the rest of the XML), the array contains only a
401
434
  single element.
402
435
 
403
436
  - resp.item_search_response[0] has an instance variable, @items, which is
404
437
  assigned an array of Items objects. Here again, only a single element is
405
- created, because there's only one <Items> tag pair in the XML.
438
+ created, because there's only one corresponding <Items> element in the XML.
406
439
 
407
440
  - resp.item_search_response[0].items[0] has an instance variable, @item, which
408
- is an array containing the item(s) returned by the search. It is a
441
+ is an array containing the actual item(s) located by the search. It is a
409
442
  multi-element array, however, because more than one item was found, as
410
443
  represented by the multiple <Item> elements in the XML.
411
444
 
412
445
  The creation of so many single element arrays is unfortunate. It makes user
413
446
  code verboser, uglier and consequently harder to read.
414
447
 
415
- Some such arrays do, in fact, have the potential to be multi-element, because
416
- the corresponding XML tag _can_ appear multiple times in the AWS response. A
417
- book, for example, _may_ have more than one <Author>. Many other types of
418
- array, however, are necessarily single element arrays. The same book, for
419
- example, is unlikely to have more than one <Title>.
448
+ You might wonder why Ruby/AWS doesn't just assign the single element itself,
449
+ rather than the array that contains it.
450
+
451
+ The answer is that most of these single-element arrays actually do have the
452
+ potential to be multi-element, because the corresponding XML tag _can_ appear
453
+ multiple times in an AWS response. A book, for example, _may_ have more than
454
+ one <Author>. Many other types of array, however, are necessarily single
455
+ element arrays. That same book, for example, is unlikely to have more than one
456
+ <Title>. This is context-dependent and difficult to define programatically.
420
457
 
421
- As another concrete example, an ItemSearch will probably return many <Item>
458
+ As another concrete example, an ItemSearch will probably yield many <Item>
422
459
  elements in the <ItemSearchResponse>, but these will invariably be nested in a
423
- single <Items> tag. The @items instance variable of the ItemSearchResponse
424
- object will therefore always have a size of 1.
460
+ single <Items> element. The @items instance variable of the ItemSearchResponse
461
+ object will therefore always be a single-element array.
425
462
 
426
- In other words, the following statements are always true when an ItemSearch
427
- successfully finds items:
463
+ In other words, the following statements are both invariably true when an
464
+ ItemSearch successfully locates items:
428
465
 
429
466
  - resp.item_search_response[0].items.size == 1
430
467
 
431
468
  - resp.item_search_response[0].items[0].item.size >= 1
432
469
 
433
470
  The awkwardness of using such single element arrays is alleviated in Ruby/AWS
434
- by the use of the AWSArray subclass. This ever-so-slightly magic class of
435
- array allows element 0 of single-element arrays to be dereferenced using the
436
- base array name, i.e. without a subscript.
471
+ by the use of the AWSArray subclass. An instance of this class differs from a
472
+ standard array by allowing element 0 of a single-element array to be
473
+ dereferenced using just the array name, i.e. without a subscript.
437
474
 
438
- In other words, a reference to foo.bar will actually return foo[0].bar, so
439
- long as foo.size == 1. Note that this only works because the array instance
440
- itself, foo, has no bar method, so the intention is unambiguous and foo can
441
- pass the call of bar down to foo[0]. foo.size, on the other hand, will
442
- _always_ refer to foo and never to foo[0], because Array#size _is_ an existing
443
- method.
475
+ In other words, a reference to foo.bar will actually return foo[0].bar when
476
+ foo.size == 1. Note that this can only work because the array itself, foo, has
477
+ no bar method, so the intention is unambiguous and foo can delegate the
478
+ invocation of the method to foo[0]. foo.size, on the other hand, will _always_
479
+ invoke foo's bar method, never delegating to foo[0], because of the existence
480
+ of the Array#size method.
444
481
 
445
482
  This allows the ASIN of the first item returned in the above XML to be
446
483
  referred to using the following shorthand:
447
484
 
448
485
  resp.item_search_response.items.item[0].asin
449
486
 
450
- It's worth reiterating that it's still necessary to refer to item[0] using a
451
- subscript in this example, because the <Items> tag in the XML contains
452
- multiple <Item> tags, making item.size > 1.
487
+ It's worth reiterating that it's still necessary in this example to refer to
488
+ item[0] using a subscript, because the <Items> element in the XML contains
489
+ multiple <Item> elements, making item.size > 1.
453
490
 
454
491
  Use this syntactic shorthand to your advantage, but understand when you're
455
- likely to be dealing with a single element array and when a multiple. This
456
- will become apparent as you gain familiarity with AWS v4.
492
+ likely to be dealing with a single element array vs. a multiple. This will
493
+ become apparent as you gain familiarity with AWS v4.
457
494
 
458
- An exception will be thrown if an unknown method is called on a multi-element
459
- array, as it can't be known which element the method invocation should be
460
- passed to. This will almost certainly be the result of an incorrect assumption
461
- that an array contains only a single element when it actually contains
462
- multiple.
495
+ An exception will be raised if an unknown method is called on a multi-element
496
+ array, as it can't be known to which array element the method invocation
497
+ should be delegated. This will almost certainly stem from an incorrect
498
+ assumption that an array contains only a single element when, in actual fact,
499
+ it contains multiple elements.
463
500
 
464
- A further important detail to note is that not all AWS operations in the same
501
+ A further important detail to note is that not all AWS operations of the same
465
502
  class return the same data. For example, an ItemSearch using the Books search
466
- index will return items that, amongst other things, create an ItemAttributes
503
+ index will return items that, amongst other things, have an ItemAttributes
467
504
  object containing further objects of class Author, ISBN, etc. An ItemSearch
468
- using the DVD search index, however, will have no Author or ISBN, but _will_
469
- have a Director and probably one or more Actor objects.
505
+ using the DVD search index, by contrast, will have no Author or ISBN, but
506
+ will likely have a Director and probably one or more Actor objects.
470
507
 
471
508
  Because of the disparity in same-class object attributes, Ruby/AWS returns
472
509
  *nil* when an attempt is made to dereference a non-existent instance variable.
473
- This approach was chosen, because it often cannot be known in advance
474
- precisely which data will be returned by a given search. Returning *nil* for
475
- non-existent attributes means that the user does not have to pepper their code
476
- with exception-handling clauses.
510
+ This approach was chosen because, more often than not, it cannot be known in
511
+ advance precisely which data will be returned by a given search operation.
512
+ Returning *nil* for non-existent attributes saves the user from having to
513
+ pepper their code with exception-handling clauses.
477
514
 
478
515
  For example:
479
516
 
480
- resp.item_search_response[0].items[0].item[0].item_attributes.director
517
+ resp.item_search_response[0].items[0].item[0].item_attributes.director
481
518
 
482
519
  will return *nil* for a book, because there was no corresponding Director
483
520
  element in the XML returned by AWS.
484
521
 
485
522
  Similarly:
486
523
 
487
- resp.item_search_response[0].items[0].item[0].item_attributes.foo_bar
524
+ resp.item_search_response[0].items[0].item[0].item_attributes.foo_bar
488
525
 
489
- will _always_ return *nil* for any item, because no kind of ItemSearch will
490
- ever yield an item with a FooBar attribute.
526
+ will _always_ return *nil* for _any_ item, because no kind of ItemSearch will
527
+ ever yield an item with a FooBar element.
491
528
 
492
529
 
493
530
  Parameter checking
@@ -498,18 +535,19 @@ particular type of search. For example, an ItemSearch can use a Sort parameter
498
535
  with a value of 'titlerank' if the SearchIndex is 'Books'. However, this value
499
536
  wouldn't make much sense in the 'Automotive' SearchIndex.
500
537
 
501
- The very presence of a certain parameter can be illegal in a certain contexts.
502
- For example, specifying the parameter 'Author' with any value would be
538
+ The very presence of a certain parameter can be illegal in certain contexts.
539
+ For example, specifying the parameter 'Author' with _any_ value would be
503
540
  nonsensical in the 'PetSupplies' SearchIndex.
504
541
 
505
542
  To complicate things further, the validity of parameters and their values
506
543
  differs not only by search type, but also by Amazon locale (amazon.com,
507
- amazon.co.uk, amazon.de, etc.) and is prone to change with each minor revision
508
- of the Amazon AWS API.
544
+ amazon.co.uk, amazon.de, etc.) and is prone to change with minor revisions of
545
+ the Amazon AWS API.
509
546
 
510
547
  Even worse, the operations themselves can be illegal in certain locales.
511
- TransactionLookup operations, for example, don't currently work in the UK
512
- locale, but do work in the US locale.
548
+ TransactionLookup operations, for example, don't work in the UK locale at the
549
+ time of writing, but do work in the US locale. As a rule of thumb, we can say
550
+ that almost everything works in the US locale and _may_ work in others.
513
551
 
514
552
  Ruby/Amazon attempted to track these complex and dynamic relationships to
515
553
  prevent illegal or ineffective operations from being attempted. It was a
@@ -517,24 +555,25 @@ time-consuming and tedious task to track the evolving API (which often changed
517
555
  in subtle ways without prior [or even belated] notice from Amazon), find all
518
556
  of the corner cases and handle undocumented quirks.
519
557
 
520
- With the highly dynamic nature of the Amazon environment, plus the sheer
521
- number of operations, parameters, possible legal values and locales in the AWS
522
- v4 API, this strict approach would be completely impractical. Ruby/AWS
523
- therefore doesn't even try.
558
+ With the highly dynamic nature of the Amazon environment and its many locales,
559
+ plus the sheer number of operations, parameters and their possibly legal
560
+ values in the AWS v4 API, this strict approach would be completely
561
+ impractical for Ruby/AWS. It therefore doesn't even try.
524
562
 
525
563
  Instead, it's now up to you to ensure that you perform legal operations and
526
- pass in sensible parameters and values for the locale in which you're working.
564
+ pass sensible parameters and values for the locale in which you're working.
565
+ The context is now your responsibility.
527
566
 
528
567
  The one exception to this rule is search index checking for ItemSearch
529
568
  operations. Code that attempts to use an invalid SearchIndex will raise an
530
- exception. The list of allowable search indices can be found in
531
- Amazon::AWS::Operation::ItemSearch::SEARCH_INDICES.
569
+ exception. The list of allowable search indices can be found in the
570
+ Amazon::AWS::Operation::ItemSearch::SEARCH_INDICES array.
532
571
 
533
572
  Of course, even this check exposes the user to the risk that Amazon may later
534
573
  add new search indices, which would continue to be unrecognised and ruled
535
- invalid by Ruby/AWS until a future update. Whilst I have chosen to implement
536
- this very basic level of checking, it may be removed in the future if it
537
- becomes impractical to keep it current.
574
+ invalid by Ruby/AWS until an update was issued. Whilst I have chosen to
575
+ implement this very basic level of checking, it may be removed in the future
576
+ if it becomes impractical to keep it current.
538
577
 
539
578
  In short, the validity of what goes into a search operation is your own
540
579
  responsibility: garbage in, garbage out.
@@ -542,34 +581,35 @@ responsibility: garbage in, garbage out.
542
581
  Thankfully, with the AWS Developer Guide at your side, it's largely common
543
582
  sense which parameters and values can be used with each type of search. It's
544
583
  less obvious when these differ by locale. For example, the 'Beauty'
545
- SearchIndex was valid in the 'us', but not in the 'uk' until the 2009-01-06
546
- revision of the AWS API.
584
+ SearchIndex was valid in the 'us' locale, but not in the 'uk' locale until the
585
+ 2009-01-06 revision of the AWS API.
547
586
 
548
587
  Unfortunately, AWS abounds with such inconsistencies and they are prone to
549
- change at any time.
588
+ change at any time. Amazon, themselves, seem to struggle to document all of
589
+ these quirks, a situation probably aggravated by the US focus of the AWS
590
+ staff.
550
591
 
551
- The only way to apprise yourself of such quirks is to read Amazon's latest
552
- developer documentation (and closely follow the release notes of each minor
553
- API revision to make sure things haven't changed). If you don't want to be
554
- exposed to such API changes, use the 'api' parameter in the user configuration
555
- file to request a particular version of the API.
592
+ The only way to apprise yourself of such peculiarities is to read Amazon's
593
+ latest developer documentation (and closely follow the release notes of each
594
+ minor API revision to make sure things haven't changed). If you don't want to
595
+ be exposed to such API changes, use the 'api' parameter in the user
596
+ configuration file to request a particular version of the API.
556
597
 
557
598
  The AWS Developer Connection pages may also be of use to you. In particular,
558
599
  the forum for discussing AWS has proved useful to me over the years:
559
600
 
560
601
  http://developer.amazonwebservices.com/connect/forum.jspa?forumID=9
561
602
 
562
- For those illegal operations that make it through and are passed to the Amazon
563
- servers, the good news is that Amazon carries out extensive request-time
564
- parameter checking in AWS v4 (much better than in v3) and will generate an
565
- error when an illegal set of parameters and values is given. Ruby/AWS will
566
- dynamically generate an exception class for the reported type of error and
567
- raise an exception of that class.
603
+ For those illegal operations that make it through to the Amazon servers, the
604
+ good news is that Amazon carries out extensive run-time parameter checking in
605
+ AWS v4 (much better than in v3) and will generate an error when an illegal set
606
+ of parameters and/or values is given. Ruby/AWS will dynamically generate a
607
+ class for the type of error reported and raise an exception of that class.
568
608
 
569
609
  Using this approach, Ruby/AWS doesn't have to perform checks that Amazon will
570
- perform later anyway. This helps keep the code base leaner, the library
571
- faster, and reduces the chances of Ruby/AWS disallowing operations that will
572
- one day be allowed in a minor revision of AWS.
610
+ perform, anyway. This helps keep the code base leaner, the library faster, and
611
+ reduces the chance that Ruby/AWS will disallow an operation that becomes valid
612
+ following a minor revision of AWS.
573
613
 
574
614
 
575
615
  Documentation
@@ -580,14 +620,14 @@ command, executed from the directory created when you unpacked the archive:
580
620
 
581
621
  rdoc -SUx CVS lib
582
622
 
583
- The documentation on how to use this library is currently incomplete, but that
584
- is steadily being remedied.
623
+ The documentation on how to use this library is currently incomplete, but it
624
+ should be enough to get you started.
585
625
 
586
626
  You can also use the Ruby/AWS mailing-list:
587
627
 
588
628
  http://www.caliban.org/mailman/listinfo/ruby-aws
589
629
 
590
- to discuss all Ruby/AWS-related subjects and issues.
630
+ to discuss any Ruby/AWS-related subjects and issues.
591
631
 
592
632
 
593
633
  Examples
@@ -1,5 +1,5 @@
1
1
  #--
2
- # $Id: README.rdoc,v 1.22 2009/03/28 23:04:23 ianmacd Exp $
2
+ # $Id: README.rdoc,v 1.23 2009/05/26 15:25:19 ianmacd Exp $
3
3
  #++
4
4
  #
5
5
  #
@@ -53,19 +53,22 @@
53
53
  # CartClear
54
54
  # CartGet
55
55
  #
56
- # In addition, multiple operations and batch requests are also supported.
56
+ # Finally, multiple operations and batch requests are also supported.
57
57
  #
58
- # Ruby/AWS also offers advanced features not directly available in the AWS
59
- # API, such as the ability to retrieve *all* results pages for a particular
60
- # search, rather than having to manually deal with AWS responses of 10 results
61
- # per page.
58
+ # Ruby/AWS supports request authentication, using your secret key to sign your
59
+ # requests to AWS.
60
+ #
61
+ # Beyond wrapping features readily available in the AWS API, Ruby/AWS also
62
+ # offers advanced features not directly supported by the AWS API, such as the
63
+ # ability to retrieve *all* results pages for a particular search, rather than
64
+ # having to manually deal with multiple AWS responses of 10 results per page.
62
65
  #
63
66
  # You can also retrieve product images and optionally overlay them with
64
67
  # percentage discount icons.
65
68
  #
66
69
  # Another advanced feature is the ability to cache responses returned by AWS.
67
70
  # If the cache is used (as it is by default), the results of each unique
68
- # query will be cached and used for 24 hours. The cache can be manually
71
+ # search will be cached and used for 24 hours. The cache can be manually
69
72
  # flushed of all or just the expired entries.
70
73
  #
71
74
  # One other useful advanced feature is the ability to determine the
@@ -82,9 +85,9 @@
82
85
  # to install Ruby/AWS. You can choose between an installation script and a
83
86
  # RubyGems[http://www.rubygems.org/] installation.
84
87
  #
85
- # Note, however, if choosing the gem installation, that whilst Ruby/AWS's
86
- # RubyForge UNIX name is now ruby-aaws. The ruby-aws name was taken by
87
- # {another project}[http://rubyforge.org/projects/ruby-aws/] and this clash
88
+ # Note, however, if opting for the gem installation, that Ruby/AWS's RubyForge
89
+ # UNIX name is now ruby-aaws. The ruby-aws name was taken by {another
90
+ # project}[http://rubyforge.org/projects/ruby-aws/] and this namespace clash
88
91
  # prevented remote installation of the Ruby/AWS gem.
89
92
  #
90
93
  #
@@ -95,17 +98,17 @@
95
98
  # ID}[https://aws-portal.amazon.com/gp/aws/developer/registration/index.html].
96
99
  #
97
100
  # You should also apply for an {Associates
98
- # account}[http://docs.amazonwebservices.com/AWSECommerceService/2009-01-06/GSG/BecominganAssociate.html],
101
+ # account}[http://docs.amazonwebservices.com/AWSECommerceService/2009-03-31/GSG/BecominganAssociate.html],
99
102
  # although this isn't strictly necessary. If you do not explicitly provide an
100
- # Associates tag in your calls through Ruby/AWS, the tag of the Ruby/AWS
101
- # author will be used by default.
103
+ # Associates tag in the operations you conduct via Ruby/AWS, the tag of the
104
+ # Ruby/AWS author will be used by default.
102
105
  #
103
106
  #
104
107
  # == See Also
105
108
  #
106
- # Ultimately, the way to get the most from this library is to read the AWS
109
+ # Ultimately, the way to get the most from Ruby/AWS is to read the AWS
107
110
  # documentation to get a feel for what is possible, and then experiment with
108
- # this library to see how the AWS calls are mapped into the Ruby world. You
111
+ # the library to see how the calls to AWS are mapped to the Ruby world. You
109
112
  # should also review this library's
110
113
  # RDoc[http://www.ruby-doc.org/core/classes/RDoc.html]
111
114
  # documentation[http://www.caliban.org/ruby/ruby-aws/] as well as the
@@ -113,26 +116,28 @@
113
116
  #
114
117
  # Additionally, there's a
115
118
  # {mailing-list}[http://www.caliban.org/mailman/listinfo/ruby-aws] available,
116
- # where you can discuss all Ruby/AWS-related subjects and issues.
119
+ # where you can discuss any Ruby/AWS-related subjects and issues.
117
120
  #
118
- # Please see the Amazon Web Services
119
- # documentation[http://developer.amazonwebservices.com/connect/kbcategory.jspa?categoryID=5]
121
+ # Please see the Amazon Web Services API
122
+ # documentation[http://developer.amazonwebservices.com/connect/kbcategory.jspa?categoryID=5],
123
+ # not forgetting the {release
124
+ # notes}[http://developer.amazonwebservices.com/connect/kbcategory.jspa?categoryID=17]
120
125
  # for definitive information on the capabilities and inner workings of the AWS
121
126
  # API.
122
127
  #
123
128
  #
124
129
  # == Download
125
130
  #
126
- # Version 0.5.1
127
- # === {gzip'ed tar archive}[http://www.caliban.org/files/ruby/ruby-aws-0.5.1.tar.gz]
128
- # === {Ruby Gem}[http://www.caliban.org/files/ruby/ruby-aaws-0.5.1.gem]
129
- # === {Fedora 9 RPM}[http://www.caliban.org/files/redhat/RPMS/noarch/ruby-aws-0.5.1-1.fc9.noarch.rpm]
130
- # === {Fedora 9 doc RPM}[http://www.caliban.org/files/redhat/RPMS/noarch/ruby-aws-doc-0.5.1-1.fc9.noarch.rpm]
131
- # === {Fedora 9 source RPM}[http://www.caliban.org/files/redhat/SRPMS/ruby-aws-0.5.1-1.fc9.src.rpm]
131
+ # Version 0.6.0
132
+ # === {gzip'ed tar archive}[http://www.caliban.org/files/ruby/ruby-aws-0.6.0.tar.gz]
133
+ # === {Ruby Gem}[http://www.caliban.org/files/ruby/ruby-aaws-0.6.0.gem]
134
+ # === {Fedora 9 RPM}[http://www.caliban.org/files/redhat/RPMS/noarch/ruby-aws-0.6.0-1.fc9.noarch.rpm]
135
+ # === {Fedora 9 doc RPM}[http://www.caliban.org/files/redhat/RPMS/noarch/ruby-aws-doc-0.6.0-1.fc9.noarch.rpm]
136
+ # === {Fedora 9 source RPM}[http://www.caliban.org/files/redhat/SRPMS/ruby-aws-0.6.0-1.fc9.src.rpm]
132
137
  #
133
138
  #
134
139
  # ---
135
140
  # Author:: Ian Macdonald <mailto:ian@caliban.org>
136
- # Version:: 0.5.1
141
+ # Version:: 0.6.0
137
142
  # Copyright:: (C) 2008-2009 Ian Macdonald
138
143
  # Licence:: GPL[http://www.gnu.org/copyleft/gpl.html]
@@ -1,4 +1,4 @@
1
- # $Id: amazon.rb,v 1.26 2009/01/19 16:45:11 ianmacd Exp $
1
+ # $Id: amazon.rb,v 1.28 2009/05/26 15:25:20 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,11 +23,12 @@ 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( /([^ a-zA-Z0-9_.-]+)/n ) do
29
+ string.gsub( /([^a-zA-Z0-9_.~-]+)/n ) do
28
30
  '%' + $1.unpack( 'H2' * $1.size ).join( '%' ).upcase
29
- end.tr( ' ', '+' )
31
+ end
30
32
  end
31
33
 
32
34
 
@@ -1,4 +1,4 @@
1
- # $Id: aws.rb,v 1.89 2009/03/28 23:04:23 ianmacd Exp $
1
+ # $Id: aws.rb,v 1.97 2009/05/26 15:24:31 ianmacd Exp $
2
2
  #
3
3
  #:include: ../../README.rdoc
4
4
 
@@ -6,13 +6,14 @@ 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 'iconv'
12
12
  require 'rexml/document'
13
+ require 'uri'
13
14
 
14
15
  NAME = '%s/%s' % [ Amazon::NAME, 'AWS' ]
15
- VERSION = '0.5.1'
16
+ VERSION = '0.6.0'
16
17
  USER_AGENT = '%s %s' % [ NAME, VERSION ]
17
18
 
18
19
  # Default Associate tags to use per locale.
@@ -30,7 +31,7 @@ module Amazon
30
31
  # changed via the user configuration file.
31
32
  #
32
33
  SERVICE = { 'Service' => 'AWSECommerceService',
33
- 'Version' => '2009-02-01'
34
+ 'Version' => '2009-03-31'
34
35
  }
35
36
 
36
37
  # Maximum number of 301 and 302 HTTP responses to follow, should Amazon
@@ -66,6 +67,11 @@ module Amazon
66
67
  # ReviewPage 20
67
68
 
68
69
 
70
+ # A hash to store character encoding converters.
71
+ #
72
+ @@encodings = {}
73
+
74
+
69
75
  # Exception class for HTTP errors.
70
76
  #
71
77
  class HTTPError < AmazonError; end
@@ -96,11 +102,12 @@ module Amazon
96
102
  'us' => Endpoint.new( 'http://ecs.amazonaws.com/onca/xml' )
97
103
  }
98
104
 
105
+
99
106
  # Fetch a page, either from the cache or by HTTP. This is used internally.
100
107
  #
101
- def AWS.get_page(request, query) # :nodoc:
108
+ def AWS.get_page(request) # :nodoc:
102
109
 
103
- url = ENDPOINT[request.locale].path + query
110
+ url = ENDPOINT[request.locale].path + request.query
104
111
  cache_url = ENDPOINT[request.locale].host + url
105
112
 
106
113
  # Check for cached page and return that if it's there.
@@ -110,6 +117,14 @@ module Amazon
110
117
  return body if body
111
118
  end
112
119
 
120
+ # Check whether we have a secret key available for signing the request.
121
+ # If so, sign the request for authentication.
122
+ #
123
+ if request.config['secret_key_id']
124
+ request.sign
125
+ url = ENDPOINT[request.locale].path + request.query
126
+ end
127
+
113
128
  # Get the existing connection. If there isn't one, force a new one.
114
129
  #
115
130
  conn = request.conn || request.reconnect.conn
@@ -124,7 +139,9 @@ module Amazon
124
139
  # just not passed by here recently), the HTTP connection to the server
125
140
  # will probably have timed out.
126
141
  #
127
- rescue Errno::ECONNRESET, Errno::EPIPE => error
142
+ rescue EOFError, Errno::ECONNABORTED, Errno::ECONNREFUSED,
143
+ Errno::ECONNRESET, Errno::EPIPE, Errno::ETIMEDOUT,
144
+ Timeout::Error => error
128
145
  Amazon.dprintf( 'Connection to server lost: %s. Retrying...', error )
129
146
  conn = request.reconnect.conn
130
147
  retry
@@ -159,16 +176,23 @@ module Amazon
159
176
  end
160
177
 
161
178
 
162
- def AWS.assemble_query(items) # :nodoc:
179
+ def AWS.assemble_query(items, encoding=nil) # :nodoc:
180
+
163
181
  query = ''
182
+ @@encodings[encoding] ||= Iconv.new( 'utf-8', encoding ) if encoding
164
183
 
165
184
  # We must sort the items into an array to get reproducible ordering
166
185
  # of the query parameters. Otherwise, URL caching would not work. We
167
- # must also convert the keys to strings, in case Symbols have been used
168
- # as the keys.
186
+ # must also convert the parameter values to strings, in case Symbols
187
+ # have been used as the values.
169
188
  #
170
189
  items.sort { |a,b| a.to_s <=> b.to_s }.each do |k, v|
171
- query << '&%s=%s' % [ k, Amazon.url_encode( v.to_s ) ]
190
+ if encoding
191
+ query << '&%s=%s' %
192
+ [ k, Amazon.url_encode( @@encodings[encoding].iconv( v.to_s ) ) ]
193
+ else
194
+ query << '&%s=%s' % [ k, Amazon.url_encode( v.to_s ) ]
195
+ end
172
196
  end
173
197
 
174
198
  # Replace initial ampersand with question-mark.
@@ -819,13 +843,6 @@ module Amazon
819
843
  # indices.
820
844
  # - *Video* combines the DVD and VHS search indices.
821
845
  #
822
- # Note that {page
823
- # 53}[http://docs.amazonwebservices.com/AWSECommerceService/2009-01-06/DG/SearchIndices.html]
824
- # of the PDF of the AWS Developer Guide (revision 2009-01-06) contains
825
- # an outdated description of *Blended* with too few subindices. {Page
826
- # 95}[http://docs.amazonwebservices.com/AWSECommerceService/2009-01-06/DG/CommonItemSearchParameters.html]
827
- # of the PDF contains the correct list.
828
- #
829
846
  SEARCH_INDICES = %w[
830
847
  All
831
848
  Apparel
@@ -1,4 +1,4 @@
1
- # $Id: search.rb,v 1.30 2009/02/19 16:19:47 ianmacd Exp $
1
+ # $Id: search.rb,v 1.35 2009/05/26 16:27:12 ianmacd Exp $
2
2
  #
3
3
 
4
4
  module Amazon
@@ -8,6 +8,7 @@ module Amazon
8
8
  require 'amazon/aws'
9
9
  require 'net/http'
10
10
  require 'rexml/document'
11
+ require 'openssl'
11
12
 
12
13
  # Load this library with:
13
14
  #
@@ -27,8 +28,14 @@ module Amazon
27
28
  #
28
29
  class LocaleError < Amazon::AWS::Error::AWSError; end
29
30
 
30
- attr_reader :conn, :locale, :user_agent
31
+ # Requests can be authenticated using the SHA-256 Secure Hash
32
+ # Algorithm.
33
+ #
34
+ DIGEST = OpenSSL::Digest::Digest.new( 'sha256' )
35
+
36
+ attr_reader :conn, :config, :locale, :query, :user_agent
31
37
  attr_writer :cache
38
+ attr_accessor :encoding
32
39
 
33
40
  # This method is used to generate an AWS search request object.
34
41
  #
@@ -82,7 +89,13 @@ module Amazon
82
89
  else
83
90
  nil
84
91
  end
85
- @api = @config['api'] || nil
92
+
93
+ # Set the following two variables from the config file. Will be
94
+ # *nil* if not present in config file.
95
+ #
96
+ @api = @config['api']
97
+ @encoding = @config['encoding']
98
+
86
99
  self.locale = locale
87
100
  end
88
101
 
@@ -178,6 +191,43 @@ module Amazon
178
191
  private :error_check
179
192
 
180
193
 
194
+ # Add a timestamp to a request object's query string.
195
+ #
196
+ def timestamp
197
+ @query << '&Timestamp=%s' %
198
+ [ Amazon.url_encode( Time.now.utc.strftime( '%FT%TZ' ) ) ]
199
+ end
200
+ private :timestamp
201
+
202
+
203
+ # Add a signature to a request object's query string. This implicitly
204
+ # also adds a timestamp.
205
+ #
206
+ def sign
207
+ timestamp
208
+ params = @query[1..-1].split( '&' ).sort.join( '&' )
209
+
210
+ sign_str = "GET\n%s\n%s\n%s" % [ ENDPOINT[@locale].host,
211
+ ENDPOINT[@locale].path,
212
+ params ]
213
+
214
+ Amazon.dprintf( 'Calculating SHA256 HMAC of "%s"...', sign_str )
215
+
216
+ hmac = OpenSSL::HMAC.digest( DIGEST,
217
+ @config['secret_key_id'],
218
+ sign_str )
219
+ Amazon.dprintf( 'SHA256 HMAC is "%s"', hmac.inspect )
220
+
221
+ base64_hmac = [ hmac ].pack( 'm' ).chomp
222
+ Amazon.dprintf( 'Base64-encoded HMAC is "%s".', base64_hmac )
223
+
224
+ signature = Amazon.url_encode( base64_hmac )
225
+
226
+ params << '&Signature=%s' % [ signature ]
227
+ @query = '?' + params
228
+ end
229
+
230
+
181
231
  # Perform a search of the AWS database. _operation_ is one of the
182
232
  # objects subclassed from _Operation_, such as _ItemSearch_,
183
233
  # _ItemLookup_, etc. It may also be a _MultipleOperation_ object.
@@ -204,19 +254,19 @@ module Amazon
204
254
  # whether a higher number of pages is requested.
205
255
  #
206
256
  def search(operation, response_group, nr_pages=1)
207
- q_params = Amazon::AWS::SERVICE.
208
- merge( { 'AWSAccessKeyId' => @key_id,
209
- 'AssociateTag' => @tag } ).
210
- merge( operation.params ).
211
- merge( response_group.params )
257
+ parameters = Amazon::AWS::SERVICE.
258
+ merge( { 'AWSAccessKeyId' => @key_id,
259
+ 'AssociateTag' => @tag } ).
260
+ merge( operation.params ).
261
+ merge( response_group.params )
212
262
 
213
263
  # Check to see whether a particular version of the API has been
214
264
  # requested. If so, overwrite Version with the new value.
215
265
  #
216
- q_params.merge!( { 'Version' => @api } ) if @api
266
+ parameters.merge!( { 'Version' => @api } ) if @api
217
267
 
218
- query = Amazon::AWS.assemble_query( q_params )
219
- page = Amazon::AWS.get_page( self, query )
268
+ @query = Amazon::AWS.assemble_query( parameters, @encoding )
269
+ page = Amazon::AWS.get_page( self )
220
270
  doc = Document.new( page )
221
271
 
222
272
  # Some errors occur at the very top level of the XML. For example,
@@ -315,9 +365,10 @@ module Amazon
315
365
  # Iterate over pages 2 and higher, but go no higher than MAX_PAGES.
316
366
  #
317
367
  2.upto( nr_pages < max_pages ? nr_pages : max_pages ) do |page_nr|
318
- query = Amazon::AWS.assemble_query(
319
- q_params.merge( { page_parameter => page_nr } ) )
320
- page = Amazon::AWS.get_page( self, query )
368
+ @query = Amazon::AWS.assemble_query(
369
+ parameters.merge( { page_parameter => page_nr } ),
370
+ @encoding)
371
+ page = Amazon::AWS.get_page( self )
321
372
  doc = Document.new( page )
322
373
 
323
374
  # Check for errors.
@@ -327,7 +378,7 @@ module Amazon
327
378
 
328
379
  # Create a new AWS object and walk the XML response tree.
329
380
  #
330
- aws = AWS::AWSObject.new
381
+ aws = AWS::AWSObject.new( operation )
331
382
  aws.walk( doc )
332
383
 
333
384
  # When dealing with multiple pages, we return not just an
@@ -1,4 +1,4 @@
1
- # $Id: setup.rb,v 1.3 2008/06/22 11:50:23 ianmacd Exp $
1
+ # $Id: setup.rb,v 1.4 2009/05/25 23:35:54 ianmacd Exp $
2
2
  #
3
3
 
4
4
  # Attempt to load Ruby/AWS using RubyGems.
@@ -24,6 +24,7 @@ class AWSTest < Test::Unit::TestCase
24
24
  @req = Request.new
25
25
  @req.locale = 'uk'
26
26
  @req.cache = false
27
+ @req.encoding = 'utf-8'
27
28
  end
28
29
 
29
30
  undef_method :default_test
@@ -1,4 +1,4 @@
1
- # $Id: tc_item_search.rb,v 1.1 2008/05/19 10:17:26 ianmacd Exp $
1
+ # $Id: tc_item_search.rb,v 1.3 2009/05/26 16:18:14 ianmacd Exp $
2
2
  #
3
3
 
4
4
  require 'test/unit'
@@ -6,8 +6,13 @@ require './setup'
6
6
 
7
7
  class TestItemSearch < AWSTest
8
8
 
9
- def test_item_search
10
- is = ItemSearch.new( 'Books', { 'Title' => 'Ruby' } )
9
+ def test_item_search_iso_8859_15
10
+
11
+ # Ensure that character set encoding works properly by manually trying
12
+ # ISO-8859-15, a.k.a. Latin-15.
13
+ #
14
+ @req.encoding = 'iso-8859-15'
15
+ is = ItemSearch.new( 'Books', { 'Title' => 'Caf�' } )
11
16
  response = @req.search( is, @rg )
12
17
 
13
18
  results = response.kernel
@@ -18,4 +23,36 @@ class TestItemSearch < AWSTest
18
23
 
19
24
  end
20
25
 
26
+ def test_item_search_utf8
27
+
28
+ # Manually set UTF-8 encoding.
29
+ #
30
+ @req.encoding = 'utf-8'
31
+ is = ItemSearch.new( 'Books', { 'Title' => 'Café' } )
32
+ response = @req.search( is, @rg )
33
+
34
+ results = response.kernel
35
+
36
+ # Ensure we got some actual results back.
37
+ #
38
+ assert( results.size > 0 )
39
+
40
+ end
41
+
42
+ def test_item_search_multiple_pages
43
+
44
+ is = ItemSearch.new( 'Books', { 'Title' => 'programming' } )
45
+ responses = @req.search( is, @rg, 5 )
46
+
47
+ results = []
48
+ responses.each do |response|
49
+ results += response.kernel
50
+ end
51
+
52
+ # Ensure we got more than 10 results back.
53
+ #
54
+ assert( results.size > 10 )
55
+
56
+ end
57
+
21
58
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ruby-aaws
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.1
4
+ version: 0.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ian Macdonald
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-03-29 00:00:00 +01:00
12
+ date: 2009-05-26 00:00:00 +02:00
13
13
  default_executable:
14
14
  dependencies: []
15
15