asin 0.4.0 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGELOG.rdoc +7 -1
- data/Gemfile.lock +10 -7
- data/README.rdoc +18 -4
- data/asin.gemspec +1 -0
- data/lib/asin.rb +5 -330
- data/lib/asin/client.rb +341 -0
- data/lib/asin/configuration.rb +3 -2
- data/lib/asin/{cart.rb → simple_cart.rb} +0 -0
- data/lib/asin/{item.rb → simple_item.rb} +0 -0
- data/lib/asin/version.rb +1 -1
- data/rakefile.rb +1 -1
- data/spec/cart_spec.rb +1 -1
- data/spec/search_spec.rb +12 -2
- metadata +72 -67
data/CHANGELOG.rdoc
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
asin (0.
|
4
|
+
asin (0.5.0)
|
5
5
|
crack (~> 0.1.8)
|
6
6
|
hashie (~> 1.0.0)
|
7
7
|
httpi (~> 0.9.2)
|
@@ -9,29 +9,31 @@ PATH
|
|
9
9
|
GEM
|
10
10
|
remote: http://rubygems.org/
|
11
11
|
specs:
|
12
|
-
chalofa_ruby-progressbar (0.0.9.1)
|
13
12
|
crack (0.1.8)
|
14
13
|
diff-lcs (1.1.2)
|
15
|
-
fuubar (0.0.
|
16
|
-
chalofa_ruby-progressbar (~> 0.0.9)
|
14
|
+
fuubar (0.0.5)
|
17
15
|
rspec (~> 2.0)
|
18
16
|
rspec-instafail (~> 0.1.4)
|
17
|
+
ruby-progressbar (~> 0.0.10)
|
19
18
|
hashie (1.0.0)
|
20
19
|
httpclient (2.2.0.2)
|
21
20
|
httpi (0.9.4)
|
22
21
|
pyu-ntlm-http (>= 0.1.3.1)
|
23
22
|
rack
|
24
23
|
pyu-ntlm-http (0.1.3.1)
|
25
|
-
rack (1.
|
24
|
+
rack (1.3.0)
|
25
|
+
rash (0.3.0)
|
26
|
+
hashie (~> 1.0.0)
|
26
27
|
rspec (2.6.0)
|
27
28
|
rspec-core (~> 2.6.0)
|
28
29
|
rspec-expectations (~> 2.6.0)
|
29
30
|
rspec-mocks (~> 2.6.0)
|
30
|
-
rspec-core (2.6.
|
31
|
+
rspec-core (2.6.4)
|
31
32
|
rspec-expectations (2.6.0)
|
32
33
|
diff-lcs (~> 1.1.2)
|
33
|
-
rspec-instafail (0.1.
|
34
|
+
rspec-instafail (0.1.8)
|
34
35
|
rspec-mocks (2.6.0)
|
36
|
+
ruby-progressbar (0.0.10)
|
35
37
|
|
36
38
|
PLATFORMS
|
37
39
|
ruby
|
@@ -40,4 +42,5 @@ DEPENDENCIES
|
|
40
42
|
asin!
|
41
43
|
fuubar (~> 0.0.4)
|
42
44
|
httpclient (~> 2.2.0.2)
|
45
|
+
rash (~> 0.3.0)
|
43
46
|
rspec (~> 2.6.0)
|
data/README.rdoc
CHANGED
@@ -39,13 +39,13 @@ ASIN is designed as a module, so you can include it into any object you like:
|
|
39
39
|
# lookup an ASIN
|
40
40
|
lookup '1430218150'
|
41
41
|
|
42
|
-
But you can also use the +
|
42
|
+
But you can also use the +instance+ method to get a proxy-object:
|
43
43
|
|
44
44
|
# just require
|
45
45
|
require 'asin'
|
46
46
|
|
47
47
|
# create an ASIN client
|
48
|
-
client = ASIN.
|
48
|
+
client = ASIN::Client.instance
|
49
49
|
|
50
50
|
# lookup an item with the amazon standard identification number (asin)
|
51
51
|
item = client.lookup '1430218150'
|
@@ -74,7 +74,7 @@ There is an additional set of methods to support AWS cart operations:
|
|
74
74
|
require 'asin'
|
75
75
|
|
76
76
|
# create an ASIN client
|
77
|
-
client = ASIN.
|
77
|
+
client = ASIN::Client.instance
|
78
78
|
|
79
79
|
# create a cart with an item
|
80
80
|
cart = client.create_cart({:asin => '1430218150', :quantity => 1})
|
@@ -101,6 +101,20 @@ There is an additional set of methods to support AWS cart operations:
|
|
101
101
|
cart.saved_items
|
102
102
|
=> [<#Hashie::Mash ASIN="1430218150" CartItemId="U3G241HVLLB8N6" ... >]
|
103
103
|
|
104
|
+
== Item / Cart Response
|
105
|
+
|
106
|
+
ASIN is customizable in the way it returns Responses from Amazon.
|
107
|
+
By default it will return +SimpleItem+ or +SimpleCart+ instances,
|
108
|
+
but you can override this behavior for using your custom Classes:
|
109
|
+
|
110
|
+
client.configure :item_type => YourItemClass
|
111
|
+
client.configure :cart_type => YourCartClass
|
112
|
+
|
113
|
+
You can also use built-in +:raw+, +:mash+ or +:rash+ types.
|
114
|
+
Since +rash+ is an additional library, you need to add it to your gemfile if you want to use it:
|
115
|
+
|
116
|
+
gem 'rash'
|
117
|
+
|
104
118
|
== HTTPI
|
105
119
|
|
106
120
|
ASIN uses HTTPI[https://github.com/rubiii/httpi] as a HTTP-Client adapter.
|
@@ -113,4 +127,4 @@ As a default HTTPI uses _httpclient_ so you should add that dependency to your p
|
|
113
127
|
|
114
128
|
Have a look at the RDOC[http://rdoc.info/projects/phoet/asin] for this project, if you want further information.
|
115
129
|
|
116
|
-
For more information on the REST calls, have a look at the whole Amazon E-Commerce-API[http://docs.amazonwebservices.com/
|
130
|
+
For more information on the REST calls, have a look at the whole Amazon E-Commerce-API[http://docs.amazonwebservices.com/AWSECommerceService/2010-11-01/DG/].
|
data/asin.gemspec
CHANGED
@@ -24,6 +24,7 @@ Gem::Specification.new do |s|
|
|
24
24
|
s.add_dependency('httpi', '~> 0.9.2')
|
25
25
|
|
26
26
|
s.add_development_dependency('httpclient', '~> 2.2.0.2')
|
27
|
+
s.add_development_dependency('rash', '~> 0.3.0')
|
27
28
|
s.add_development_dependency('rspec', '~> 2.6.0')
|
28
29
|
s.add_development_dependency('fuubar', '~> 0.0.4')
|
29
30
|
end
|
data/lib/asin.rb
CHANGED
@@ -1,332 +1,7 @@
|
|
1
|
-
# -*- coding: utf-8 -*-
|
2
|
-
require 'httpi'
|
3
|
-
require 'crack/xml'
|
4
|
-
require 'cgi'
|
5
|
-
require 'base64'
|
6
|
-
require 'logger'
|
7
|
-
|
8
|
-
require 'asin/item'
|
9
|
-
require 'asin/cart'
|
10
|
-
require 'asin/version'
|
11
|
-
require 'asin/configuration'
|
12
|
-
|
13
|
-
# ASIN (Amazon Simple INterface) is a gem for easy access of the Amazon E-Commerce-API.
|
14
|
-
# It is simple to configure and use. Since it's very small and flexible, it is easy to extend it to your needs.
|
15
|
-
#
|
16
|
-
# Author:: Peter Schröder (mailto:phoetmail@googlemail.com)
|
17
|
-
#
|
18
|
-
# == Usage
|
19
|
-
#
|
20
|
-
# The ASIN module is designed as a mixin.
|
21
|
-
#
|
22
|
-
# require 'asin'
|
23
|
-
# include ASIN
|
24
|
-
#
|
25
|
-
# In order to use the Amazon API properly, you need to be a registered user (http://aws.amazon.com).
|
26
|
-
#
|
27
|
-
# The registration process will give you a +secret-key+ and an +access-key+ (AWSAccessKeyId).
|
28
|
-
#
|
29
|
-
# Both are needed to use ASIN (see Configuration for more details):
|
30
|
-
#
|
31
|
-
# configure :secret => 'your-secret', :key => 'your-key'
|
32
|
-
#
|
33
|
-
# == Search
|
34
|
-
#
|
35
|
-
# After configuring your environment you can call the +lookup+ method to retrieve an +SimpleItem+ via the
|
36
|
-
# Amazon Standard Identification Number (ASIN):
|
37
|
-
#
|
38
|
-
# item = lookup '1430218150'
|
39
|
-
# item.title
|
40
|
-
# => "Learn Objective-C on the Mac (Learn Series)"
|
41
|
-
#
|
42
|
-
# OR search with fulltext/ASIN/ISBN
|
43
|
-
#
|
44
|
-
# items = search 'Learn Objective-C'
|
45
|
-
# items.first.title
|
46
|
-
# => "Learn Objective-C on the Mac (Learn Series)"
|
47
|
-
#
|
48
|
-
# The +SimpleItem+ uses a Hashie::Mash as its internal data representation and you can get fetched data from it:
|
49
|
-
#
|
50
|
-
# item.raw.ItemAttributes.ListPrice.FormattedPrice
|
51
|
-
# => "$39.99"
|
52
|
-
#
|
53
|
-
# == Further Configuration
|
54
|
-
#
|
55
|
-
# If you need more controll over the request that is sent to the
|
56
|
-
# Amazon API (http://docs.amazonwebservices.com/AWSEcommerceService/4-0/),
|
57
|
-
# you can override some defaults or add additional query-parameters to the REST calls:
|
58
|
-
#
|
59
|
-
# configure :host => 'webservices.amazon.de'
|
60
|
-
# lookup(asin, :ResponseGroup => :Medium)
|
61
|
-
#
|
62
|
-
# == Cart
|
63
|
-
#
|
64
|
-
# ASIN helps with AWS cart-operations.
|
65
|
-
# It currently supports the CartCreate, CartGet, CartAdd, CartModify and CartClear operations:
|
66
|
-
#
|
67
|
-
# cart = create_cart({:asin => '1430218150', :quantity => 1})
|
68
|
-
# cart.valid?
|
69
|
-
# cart.items
|
70
|
-
# => true
|
71
|
-
# => [<#Hashie::Mash ASIN="1430218150" CartItemId="U3G241HVLLB8N6" ... >]
|
72
|
-
#
|
73
|
-
# cart = get_cart('176-9182855-2326919', 'KgeVCA0YJTbuN/7Ibakrk/KnHWA=')
|
74
|
-
# cart.empty?
|
75
|
-
# => false
|
76
|
-
#
|
77
|
-
# cart = clear_cart(cart)
|
78
|
-
# cart.empty?
|
79
|
-
# => true
|
80
|
-
#
|
81
|
-
# cart = add_items(cart, {:asin => '1430216263', :quantity => 2})
|
82
|
-
# cart.empty?
|
83
|
-
# => false
|
84
|
-
#
|
85
|
-
# cart = update_items(cart, {:cart_item_id => cart.items.first.CartItemId, :action => :SaveForLater}, {:cart_item_id => cart.items.first.CartItemId, :quantity => 7})
|
86
|
-
# cart.valid?
|
87
|
-
# cart.saved_items
|
88
|
-
# => true
|
89
|
-
# => [<#Hashie::Mash ASIN="1430218150" CartItemId="U3G241HVLLB8N6" ... >]
|
90
|
-
#
|
91
1
|
module ASIN
|
92
|
-
|
93
|
-
DIGEST = OpenSSL::Digest::Digest.new('sha256')
|
94
|
-
PATH = '/onca/xml'
|
95
|
-
|
96
|
-
# Convenience method to create an ASIN client.
|
97
|
-
#
|
98
|
-
# A client is not necessary though, you can simply include the ASIN module otherwise.
|
99
|
-
#
|
100
|
-
def self.client
|
101
|
-
client = Object.new
|
102
|
-
client.extend ASIN
|
103
|
-
client
|
104
|
-
end
|
105
|
-
|
106
|
-
# Configures the basic request parameters for ASIN.
|
107
|
-
#
|
108
|
-
# Expects at least +secret+ and +key+ for the API call:
|
109
|
-
#
|
110
|
-
# configure :secret => 'your-secret', :key => 'your-key'
|
111
|
-
#
|
112
|
-
# See ASIN::Configuration for more infos.
|
113
|
-
#
|
114
|
-
def configure(options={})
|
115
|
-
Configuration.configure(options)
|
116
|
-
end
|
117
|
-
|
118
|
-
# Performs an +ItemLookup+ REST call against the Amazon API.
|
119
|
-
#
|
120
|
-
# Expects an ASIN (Amazon Standard Identification Number) and returns an +SimpleItem+:
|
121
|
-
#
|
122
|
-
# item = lookup '1430218150'
|
123
|
-
# item.title
|
124
|
-
# => "Learn Objective-C on the Mac (Learn Series)"
|
125
|
-
#
|
126
|
-
# ==== Options:
|
127
|
-
#
|
128
|
-
# Additional parameters for the API call like this:
|
129
|
-
#
|
130
|
-
# lookup(asin, :ResponseGroup => :Medium)
|
131
|
-
#
|
132
|
-
def lookup(asin, params={:ResponseGroup => :Medium})
|
133
|
-
response = call(params.merge(:Operation => :ItemLookup, :ItemId => asin))
|
134
|
-
handle_item(response['ItemLookupResponse']['Items']['Item'])
|
135
|
-
end
|
136
|
-
|
137
|
-
# Performs an +ItemSearch+ REST call against the Amazon API.
|
138
|
-
#
|
139
|
-
# Expects a search-string which can be an arbitrary array of strings (ASINs f.e.) and returns a list of +SimpleItem+s:
|
140
|
-
#
|
141
|
-
# items = search_keywords 'Learn', 'Objective-C'
|
142
|
-
# items.first.title
|
143
|
-
# => "Learn Objective-C on the Mac (Learn Series)"
|
144
|
-
#
|
145
|
-
# ==== Options:
|
146
|
-
#
|
147
|
-
# Additional parameters for the API call like this:
|
148
|
-
#
|
149
|
-
# search_keywords('nirvana', 'never mind', :SearchIndex => :Music)
|
150
|
-
#
|
151
|
-
# Have a look at the different search index values on the Amazon-Documentation[http://docs.amazonwebservices.com/AWSEcommerceService/4-0/]
|
152
|
-
#
|
153
|
-
def search_keywords(*keywords)
|
154
|
-
params = keywords.last.is_a?(Hash) ? keywords.pop : {:SearchIndex => :Books, :ResponseGroup => :Medium}
|
155
|
-
response = call(params.merge(:Operation => :ItemSearch, :Keywords => keywords.join(' ')))
|
156
|
-
(response['ItemSearchResponse']['Items']['Item'] || []).map {|item| handle_item(item)}
|
157
|
-
end
|
158
|
-
|
159
|
-
# Performs an +ItemSearch+ REST call against the Amazon API.
|
160
|
-
#
|
161
|
-
# Expects a Hash of search params where and returns a list of +SimpleItem+s:
|
162
|
-
#
|
163
|
-
# items = search :SearchIndex => :Music
|
164
|
-
#
|
165
|
-
# ==== Options:
|
166
|
-
#
|
167
|
-
# Additional parameters for the API call like this:
|
168
|
-
#
|
169
|
-
# search(:Keywords => 'nirvana', :SearchIndex => :Music)
|
170
|
-
#
|
171
|
-
# Have a look at the different search index values on the Amazon-Documentation[http://docs.amazonwebservices.com/AWSEcommerceService/4-0/]
|
172
|
-
#
|
173
|
-
def search(params={:SearchIndex => :Books, :ResponseGroup => :Medium})
|
174
|
-
response = call(params.merge(:Operation => :ItemSearch))
|
175
|
-
(response['ItemSearchResponse']['Items']['Item'] || []).map {|item| handle_item(item)}
|
176
|
-
end
|
177
|
-
|
178
|
-
# Performs an +CartCreate+ REST call against the Amazon API.
|
179
|
-
#
|
180
|
-
# Expects one ore more item-hashes and returns a +SimpleCart+:
|
181
|
-
#
|
182
|
-
# cart = create_cart({:asin => '1430218150', :quantity => 1})
|
183
|
-
#
|
184
|
-
# ==== Options:
|
185
|
-
#
|
186
|
-
# Additional parameters for the API call like this:
|
187
|
-
#
|
188
|
-
# create_cart({:asin => '1430218150', :quantity => 1}, {:asin => '1430216263', :quantity => 1, :action => :SaveForLater})
|
189
|
-
#
|
190
|
-
# Have a look at the different cart item operation values on the Amazon-Documentation[http://docs.amazonwebservices.com/AWSEcommerceService/4-0/]
|
191
|
-
#
|
192
|
-
def create_cart(*items)
|
193
|
-
cart(:CartCreate, create_item_params(items))
|
194
|
-
end
|
195
|
-
|
196
|
-
# Performs an +CartGet+ REST call against the Amazon API.
|
197
|
-
#
|
198
|
-
# Expects the CartId and the HMAC to identify the returning +SimpleCart+:
|
199
|
-
#
|
200
|
-
# cart = get_cart('176-9182855-2326919', 'KgeVCA0YJTbuN/7Ibakrk/KnHWA=')
|
201
|
-
#
|
202
|
-
def get_cart(cart_id, hmac)
|
203
|
-
cart(:CartGet, {:CartId => cart_id, :HMAC => hmac})
|
204
|
-
end
|
205
|
-
|
206
|
-
# Performs an +CartAdd+ REST call against the Amazon API.
|
207
|
-
#
|
208
|
-
# Expects a +SimpleCart+ created with +create_cart+ and one ore more Item-Hashes and returns an updated +SimpleCart+:
|
209
|
-
#
|
210
|
-
# cart = add_items(cart, {:asin => '1430216263', :quantity => 2})
|
211
|
-
#
|
212
|
-
# ==== Options:
|
213
|
-
#
|
214
|
-
# Additional parameters for the API call like this:
|
215
|
-
#
|
216
|
-
# add_items(cart, {:asin => '1430218150', :quantity => 1}, {:asin => '1430216263', :quantity => 1, :action => :SaveForLater})
|
217
|
-
#
|
218
|
-
# Have a look at the different cart item operation values on the Amazon-Documentation[http://docs.amazonwebservices.com/AWSEcommerceService/4-0/]
|
219
|
-
#
|
220
|
-
def add_items(cart, *items)
|
221
|
-
cart(:CartAdd, create_item_params(items).merge({:CartId => cart.cart_id, :HMAC => cart.hmac}))
|
222
|
-
end
|
223
|
-
|
224
|
-
# Performs an +CartModify+ REST call against the Amazon API.
|
225
|
-
#
|
226
|
-
# Expects a +SimpleCart+ created with +create_cart+ and one ore more Item-Hashes to modify and returns an updated +SimpleCart+:
|
227
|
-
#
|
228
|
-
# cart = update_items(cart, {:cart_item_id => cart.items.first.CartItemId, :quantity => 7})
|
229
|
-
#
|
230
|
-
# ==== Options:
|
231
|
-
#
|
232
|
-
# Additional parameters for the API call like this:
|
233
|
-
#
|
234
|
-
# update_items(cart, {:cart_item_id => cart.items.first.CartItemId, :action => :SaveForLater}, {:cart_item_id => cart.items.first.CartItemId, :quantity => 7})
|
235
|
-
#
|
236
|
-
# Have a look at the different cart item operation values on the Amazon-Documentation[http://docs.amazonwebservices.com/AWSEcommerceService/4-0/]
|
237
|
-
#
|
238
|
-
def update_items(cart, *items)
|
239
|
-
cart(:CartModify, create_item_params(items).merge({:CartId => cart.cart_id, :HMAC => cart.hmac}))
|
240
|
-
end
|
241
|
-
|
242
|
-
# Performs an +CartClear+ REST call against the Amazon API.
|
243
|
-
#
|
244
|
-
# Expects a +SimpleCart+ created with +create_cart+ and returns an empty +SimpleCart+:
|
245
|
-
#
|
246
|
-
# cart = clear_cart(cart)
|
247
|
-
#
|
248
|
-
def clear_cart(cart)
|
249
|
-
cart(:CartClear, {:CartId => cart.cart_id, :HMAC => cart.hmac})
|
250
|
-
end
|
251
|
-
|
252
|
-
private
|
253
|
-
|
254
|
-
def handle_item(item)
|
255
|
-
Configuration.item_type.is_a?(Class) ? Configuration.item_type.new(item) : item
|
256
|
-
end
|
257
|
-
|
258
|
-
def create_item_params(items)
|
259
|
-
keyword_mappings = {
|
260
|
-
:asin => 'ASIN',
|
261
|
-
:quantity => 'Quantity',
|
262
|
-
:cart_item_id => 'CartItemId',
|
263
|
-
:offer_listing_id => 'OfferListingId',
|
264
|
-
:action => 'Action'
|
265
|
-
}
|
266
|
-
params = {}
|
267
|
-
items.each_with_index do |item, i|
|
268
|
-
item.each do |key, value|
|
269
|
-
next unless keyword = keyword_mappings[key]
|
270
|
-
params["Item.#{i}.#{keyword}"] = value.to_s
|
271
|
-
end
|
272
|
-
end
|
273
|
-
params
|
274
|
-
end
|
275
|
-
|
276
|
-
def cart(operation, params={})
|
277
|
-
response = call(params.merge(:Operation => operation))
|
278
|
-
cart = response["#{operation}Response"]['Cart']
|
279
|
-
Configuration.cart_type.is_a?(Class) ? Configuration.cart_type.new(cart) : cart
|
280
|
-
end
|
281
|
-
|
282
|
-
|
283
|
-
def credentials_valid?
|
284
|
-
Configuration.secret && Configuration.key
|
285
|
-
end
|
286
|
-
|
287
|
-
def call(params)
|
288
|
-
raise "you have to configure ASIN: 'configure :secret => 'your-secret', :key => 'your-key''" unless credentials_valid?
|
289
|
-
|
290
|
-
log(:debug, "calling with params=#{params}")
|
291
|
-
signed = create_signed_query_string(params)
|
292
|
-
|
293
|
-
url = "http://#{Configuration.host}#{PATH}?#{signed}"
|
294
|
-
log(:info, "performing rest call to url='#{url}'")
|
295
|
-
|
296
|
-
response = HTTPI.get(url)
|
297
|
-
if response.code == 200
|
298
|
-
# force utf-8 chars, works only on 1.9 string
|
299
|
-
resp = response.body
|
300
|
-
resp = resp.force_encoding('UTF-8') if resp.respond_to? :force_encoding
|
301
|
-
log(:debug, "got response='#{resp}'")
|
302
|
-
Crack::XML.parse(resp)
|
303
|
-
else
|
304
|
-
log(:error, "got response='#{response.body}'")
|
305
|
-
raise "request failed with response-code='#{response.code}'"
|
306
|
-
end
|
307
|
-
end
|
308
|
-
|
309
|
-
def create_signed_query_string(params)
|
310
|
-
# nice tutorial http://cloudcarpenters.com/blog/amazon_products_api_request_signing/
|
311
|
-
params[:Service] = :AWSECommerceService
|
312
|
-
params[:AWSAccessKeyId] = Configuration.key
|
313
|
-
# utc timestamp needed for signing
|
314
|
-
params[:Timestamp] = Time.now.utc.strftime('%Y-%m-%dT%H:%M:%SZ')
|
315
|
-
|
316
|
-
# signing needs to order the query alphabetically
|
317
|
-
query = params.map{|key, value| "#{key}=#{CGI.escape(value.to_s)}" }.sort.join('&').gsub('+','%20')
|
318
|
-
|
319
|
-
# yeah, you really need to sign the get-request not the query
|
320
|
-
request_to_sign = "GET\n#{Configuration.host}\n#{PATH}\n#{query}"
|
321
|
-
hmac = OpenSSL::HMAC.digest(DIGEST, Configuration.secret, request_to_sign)
|
322
|
-
|
323
|
-
# don't forget to remove the newline from base64
|
324
|
-
signature = CGI.escape(Base64.encode64(hmac).chomp)
|
325
|
-
"#{query}&Signature=#{signature}"
|
326
|
-
end
|
327
|
-
|
328
|
-
def log(severity, message)
|
329
|
-
Configuration.logger.send severity, message if Configuration.logger
|
330
|
-
end
|
331
|
-
|
332
2
|
end
|
3
|
+
ASIN.autoload :Client, 'asin/client'
|
4
|
+
ASIN.autoload :SimpleItem, 'asin/simple_item'
|
5
|
+
ASIN.autoload :SimpleCart, 'asin/simple_cart'
|
6
|
+
ASIN.autoload :Version, 'asin/version'
|
7
|
+
ASIN.autoload :Configuration, 'asin/configuration'
|
data/lib/asin/client.rb
ADDED
@@ -0,0 +1,341 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
2
|
+
require 'httpi'
|
3
|
+
require 'crack/xml'
|
4
|
+
require 'cgi'
|
5
|
+
require 'base64'
|
6
|
+
|
7
|
+
# ASIN (Amazon Simple INterface) is a gem for easy access of the Amazon E-Commerce-API.
|
8
|
+
# It is simple to configure and use. Since it's very small and flexible, it is easy to extend it to your needs.
|
9
|
+
#
|
10
|
+
# Author:: Peter Schröder (mailto:phoetmail@googlemail.com)
|
11
|
+
#
|
12
|
+
# == Usage
|
13
|
+
#
|
14
|
+
# The ASIN module is designed as a mixin.
|
15
|
+
#
|
16
|
+
# require 'asin'
|
17
|
+
# include ASIN::Client
|
18
|
+
#
|
19
|
+
# In order to use the Amazon API properly, you need to be a registered user (http://aws.amazon.com).
|
20
|
+
#
|
21
|
+
# The registration process will give you a +secret-key+ and an +access-key+ (AWSAccessKeyId).
|
22
|
+
#
|
23
|
+
# Both are needed to use ASIN (see Configuration for more details):
|
24
|
+
#
|
25
|
+
# configure :secret => 'your-secret', :key => 'your-key'
|
26
|
+
#
|
27
|
+
# == Search
|
28
|
+
#
|
29
|
+
# After configuring your environment you can call the +lookup+ method to retrieve an +SimpleItem+ via the
|
30
|
+
# Amazon Standard Identification Number (ASIN):
|
31
|
+
#
|
32
|
+
# item = lookup '1430218150'
|
33
|
+
# item.title
|
34
|
+
# => "Learn Objective-C on the Mac (Learn Series)"
|
35
|
+
#
|
36
|
+
# OR search with fulltext/ASIN/ISBN
|
37
|
+
#
|
38
|
+
# items = search 'Learn Objective-C'
|
39
|
+
# items.first.title
|
40
|
+
# => "Learn Objective-C on the Mac (Learn Series)"
|
41
|
+
#
|
42
|
+
# The +SimpleItem+ uses a Hashie::Mash as its internal data representation and you can get fetched data from it:
|
43
|
+
#
|
44
|
+
# item.raw.ItemAttributes.ListPrice.FormattedPrice
|
45
|
+
# => "$39.99"
|
46
|
+
#
|
47
|
+
# == Further Configuration
|
48
|
+
#
|
49
|
+
# If you need more controll over the request that is sent to the
|
50
|
+
# Amazon API (http://docs.amazonwebservices.com/AWSEcommerceService/4-0/),
|
51
|
+
# you can override some defaults or add additional query-parameters to the REST calls:
|
52
|
+
#
|
53
|
+
# configure :host => 'webservices.amazon.de'
|
54
|
+
# lookup(asin, :ResponseGroup => :Medium)
|
55
|
+
#
|
56
|
+
# == Cart
|
57
|
+
#
|
58
|
+
# ASIN helps with AWS cart-operations.
|
59
|
+
# It currently supports the CartCreate, CartGet, CartAdd, CartModify and CartClear operations:
|
60
|
+
#
|
61
|
+
# cart = create_cart({:asin => '1430218150', :quantity => 1})
|
62
|
+
# cart.valid?
|
63
|
+
# cart.items
|
64
|
+
# => true
|
65
|
+
# => [<#Hashie::Mash ASIN="1430218150" CartItemId="U3G241HVLLB8N6" ... >]
|
66
|
+
#
|
67
|
+
# cart = get_cart('176-9182855-2326919', 'KgeVCA0YJTbuN/7Ibakrk/KnHWA=')
|
68
|
+
# cart.empty?
|
69
|
+
# => false
|
70
|
+
#
|
71
|
+
# cart = clear_cart(cart)
|
72
|
+
# cart.empty?
|
73
|
+
# => true
|
74
|
+
#
|
75
|
+
# cart = add_items(cart, {:asin => '1430216263', :quantity => 2})
|
76
|
+
# cart.empty?
|
77
|
+
# => false
|
78
|
+
#
|
79
|
+
# cart = update_items(cart, {:cart_item_id => cart.items.first.CartItemId, :action => :SaveForLater}, {:cart_item_id => cart.items.first.CartItemId, :quantity => 7})
|
80
|
+
# cart.valid?
|
81
|
+
# cart.saved_items
|
82
|
+
# => true
|
83
|
+
# => [<#Hashie::Mash ASIN="1430218150" CartItemId="U3G241HVLLB8N6" ... >]
|
84
|
+
#
|
85
|
+
module ASIN
|
86
|
+
module Client
|
87
|
+
|
88
|
+
DIGEST = OpenSSL::Digest::Digest.new('sha256')
|
89
|
+
PATH = '/onca/xml'
|
90
|
+
|
91
|
+
# Convenience method to create an ASIN client.
|
92
|
+
#
|
93
|
+
# An instance is not necessary though, you can simply include the ASIN module otherwise.
|
94
|
+
#
|
95
|
+
def self.instance
|
96
|
+
ins = Object.new
|
97
|
+
ins.extend ASIN::Client
|
98
|
+
ins
|
99
|
+
end
|
100
|
+
|
101
|
+
# Configures the basic request parameters for ASIN.
|
102
|
+
#
|
103
|
+
# Expects at least +secret+ and +key+ for the API call:
|
104
|
+
#
|
105
|
+
# configure :secret => 'your-secret', :key => 'your-key'
|
106
|
+
#
|
107
|
+
# See ASIN::Configuration for more infos.
|
108
|
+
#
|
109
|
+
def configure(options={})
|
110
|
+
Configuration.configure(options)
|
111
|
+
end
|
112
|
+
|
113
|
+
# Performs an +ItemLookup+ REST call against the Amazon API.
|
114
|
+
#
|
115
|
+
# Expects an ASIN (Amazon Standard Identification Number) and returns an +SimpleItem+:
|
116
|
+
#
|
117
|
+
# item = lookup '1430218150'
|
118
|
+
# item.title
|
119
|
+
# => "Learn Objective-C on the Mac (Learn Series)"
|
120
|
+
#
|
121
|
+
# ==== Options:
|
122
|
+
#
|
123
|
+
# Additional parameters for the API call like this:
|
124
|
+
#
|
125
|
+
# lookup(asin, :ResponseGroup => :Medium)
|
126
|
+
#
|
127
|
+
def lookup(asin, params={:ResponseGroup => :Medium})
|
128
|
+
response = call(params.merge(:Operation => :ItemLookup, :ItemId => asin))
|
129
|
+
handle_item(response['ItemLookupResponse']['Items']['Item'])
|
130
|
+
end
|
131
|
+
|
132
|
+
# Performs an +ItemSearch+ REST call against the Amazon API.
|
133
|
+
#
|
134
|
+
# Expects a search-string which can be an arbitrary array of strings (ASINs f.e.) and returns a list of +SimpleItem+s:
|
135
|
+
#
|
136
|
+
# items = search_keywords 'Learn', 'Objective-C'
|
137
|
+
# items.first.title
|
138
|
+
# => "Learn Objective-C on the Mac (Learn Series)"
|
139
|
+
#
|
140
|
+
# ==== Options:
|
141
|
+
#
|
142
|
+
# Additional parameters for the API call like this:
|
143
|
+
#
|
144
|
+
# search_keywords('nirvana', 'never mind', :SearchIndex => :Music)
|
145
|
+
#
|
146
|
+
# Have a look at the different search index values on the Amazon-Documentation[http://docs.amazonwebservices.com/AWSEcommerceService/4-0/]
|
147
|
+
#
|
148
|
+
def search_keywords(*keywords)
|
149
|
+
params = keywords.last.is_a?(Hash) ? keywords.pop : {:SearchIndex => :Books, :ResponseGroup => :Medium}
|
150
|
+
response = call(params.merge(:Operation => :ItemSearch, :Keywords => keywords.join(' ')))
|
151
|
+
(response['ItemSearchResponse']['Items']['Item'] || []).map {|item| handle_item(item)}
|
152
|
+
end
|
153
|
+
|
154
|
+
# Performs an +ItemSearch+ REST call against the Amazon API.
|
155
|
+
#
|
156
|
+
# Expects a Hash of search params where and returns a list of +SimpleItem+s:
|
157
|
+
#
|
158
|
+
# items = search :SearchIndex => :Music
|
159
|
+
#
|
160
|
+
# ==== Options:
|
161
|
+
#
|
162
|
+
# Additional parameters for the API call like this:
|
163
|
+
#
|
164
|
+
# search(:Keywords => 'nirvana', :SearchIndex => :Music)
|
165
|
+
#
|
166
|
+
# Have a look at the different search index values on the Amazon-Documentation[http://docs.amazonwebservices.com/AWSEcommerceService/4-0/]
|
167
|
+
#
|
168
|
+
def search(params={:SearchIndex => :Books, :ResponseGroup => :Medium})
|
169
|
+
response = call(params.merge(:Operation => :ItemSearch))
|
170
|
+
(response['ItemSearchResponse']['Items']['Item'] || []).map {|item| handle_item(item)}
|
171
|
+
end
|
172
|
+
|
173
|
+
# Performs an +CartCreate+ REST call against the Amazon API.
|
174
|
+
#
|
175
|
+
# Expects one ore more item-hashes and returns a +SimpleCart+:
|
176
|
+
#
|
177
|
+
# cart = create_cart({:asin => '1430218150', :quantity => 1})
|
178
|
+
#
|
179
|
+
# ==== Options:
|
180
|
+
#
|
181
|
+
# Additional parameters for the API call like this:
|
182
|
+
#
|
183
|
+
# create_cart({:asin => '1430218150', :quantity => 1}, {:asin => '1430216263', :quantity => 1, :action => :SaveForLater})
|
184
|
+
#
|
185
|
+
# Have a look at the different cart item operation values on the Amazon-Documentation[http://docs.amazonwebservices.com/AWSEcommerceService/4-0/]
|
186
|
+
#
|
187
|
+
def create_cart(*items)
|
188
|
+
cart(:CartCreate, create_item_params(items))
|
189
|
+
end
|
190
|
+
|
191
|
+
# Performs an +CartGet+ REST call against the Amazon API.
|
192
|
+
#
|
193
|
+
# Expects the CartId and the HMAC to identify the returning +SimpleCart+:
|
194
|
+
#
|
195
|
+
# cart = get_cart('176-9182855-2326919', 'KgeVCA0YJTbuN/7Ibakrk/KnHWA=')
|
196
|
+
#
|
197
|
+
def get_cart(cart_id, hmac)
|
198
|
+
cart(:CartGet, {:CartId => cart_id, :HMAC => hmac})
|
199
|
+
end
|
200
|
+
|
201
|
+
# Performs an +CartAdd+ REST call against the Amazon API.
|
202
|
+
#
|
203
|
+
# Expects a +SimpleCart+ created with +create_cart+ and one ore more Item-Hashes and returns an updated +SimpleCart+:
|
204
|
+
#
|
205
|
+
# cart = add_items(cart, {:asin => '1430216263', :quantity => 2})
|
206
|
+
#
|
207
|
+
# ==== Options:
|
208
|
+
#
|
209
|
+
# Additional parameters for the API call like this:
|
210
|
+
#
|
211
|
+
# add_items(cart, {:asin => '1430218150', :quantity => 1}, {:asin => '1430216263', :quantity => 1, :action => :SaveForLater})
|
212
|
+
#
|
213
|
+
# Have a look at the different cart item operation values on the Amazon-Documentation[http://docs.amazonwebservices.com/AWSEcommerceService/4-0/]
|
214
|
+
#
|
215
|
+
def add_items(cart, *items)
|
216
|
+
cart(:CartAdd, create_item_params(items).merge({:CartId => cart.cart_id, :HMAC => cart.hmac}))
|
217
|
+
end
|
218
|
+
|
219
|
+
# Performs an +CartModify+ REST call against the Amazon API.
|
220
|
+
#
|
221
|
+
# Expects a +SimpleCart+ created with +create_cart+ and one ore more Item-Hashes to modify and returns an updated +SimpleCart+:
|
222
|
+
#
|
223
|
+
# cart = update_items(cart, {:cart_item_id => cart.items.first.CartItemId, :quantity => 7})
|
224
|
+
#
|
225
|
+
# ==== Options:
|
226
|
+
#
|
227
|
+
# Additional parameters for the API call like this:
|
228
|
+
#
|
229
|
+
# update_items(cart, {:cart_item_id => cart.items.first.CartItemId, :action => :SaveForLater}, {:cart_item_id => cart.items.first.CartItemId, :quantity => 7})
|
230
|
+
#
|
231
|
+
# Have a look at the different cart item operation values on the Amazon-Documentation[http://docs.amazonwebservices.com/AWSEcommerceService/4-0/]
|
232
|
+
#
|
233
|
+
def update_items(cart, *items)
|
234
|
+
cart(:CartModify, create_item_params(items).merge({:CartId => cart.cart_id, :HMAC => cart.hmac}))
|
235
|
+
end
|
236
|
+
|
237
|
+
# Performs an +CartClear+ REST call against the Amazon API.
|
238
|
+
#
|
239
|
+
# Expects a +SimpleCart+ created with +create_cart+ and returns an empty +SimpleCart+:
|
240
|
+
#
|
241
|
+
# cart = clear_cart(cart)
|
242
|
+
#
|
243
|
+
def clear_cart(cart)
|
244
|
+
cart(:CartClear, {:CartId => cart.cart_id, :HMAC => cart.hmac})
|
245
|
+
end
|
246
|
+
|
247
|
+
private()
|
248
|
+
|
249
|
+
def handle_item(item)
|
250
|
+
handle_type(item, Configuration.item_type)
|
251
|
+
end
|
252
|
+
|
253
|
+
def handle_type(data, type)
|
254
|
+
if type.is_a?(Class)
|
255
|
+
type.new(data)
|
256
|
+
elsif type == :mash
|
257
|
+
require 'hashie'
|
258
|
+
Hashie::Mash.new(data)
|
259
|
+
elsif type == :rash
|
260
|
+
require 'rash'
|
261
|
+
Hashie::Rash.new(data)
|
262
|
+
else
|
263
|
+
data
|
264
|
+
end
|
265
|
+
end
|
266
|
+
|
267
|
+
def create_item_params(items)
|
268
|
+
keyword_mappings = {
|
269
|
+
:asin => 'ASIN',
|
270
|
+
:quantity => 'Quantity',
|
271
|
+
:cart_item_id => 'CartItemId',
|
272
|
+
:offer_listing_id => 'OfferListingId',
|
273
|
+
:action => 'Action'
|
274
|
+
}
|
275
|
+
params = {}
|
276
|
+
items.each_with_index do |item, i|
|
277
|
+
item.each do |key, value|
|
278
|
+
next unless keyword = keyword_mappings[key]
|
279
|
+
params["Item.#{i}.#{keyword}"] = value.to_s
|
280
|
+
end
|
281
|
+
end
|
282
|
+
params
|
283
|
+
end
|
284
|
+
|
285
|
+
def cart(operation, params={})
|
286
|
+
response = call(params.merge(:Operation => operation))
|
287
|
+
cart = response["#{operation}Response"]['Cart']
|
288
|
+
handle_type(cart, Configuration.cart_type)
|
289
|
+
end
|
290
|
+
|
291
|
+
|
292
|
+
def credentials_valid?
|
293
|
+
Configuration.secret && Configuration.key
|
294
|
+
end
|
295
|
+
|
296
|
+
def call(params)
|
297
|
+
raise "you have to configure ASIN: 'configure :secret => 'your-secret', :key => 'your-key''" unless credentials_valid?
|
298
|
+
|
299
|
+
log(:debug, "calling with params=#{params}")
|
300
|
+
signed = create_signed_query_string(params)
|
301
|
+
|
302
|
+
url = "http://#{Configuration.host}#{PATH}?#{signed}"
|
303
|
+
log(:info, "performing rest call to url='#{url}'")
|
304
|
+
|
305
|
+
response = HTTPI.get(url)
|
306
|
+
if response.code == 200
|
307
|
+
# force utf-8 chars, works only on 1.9 string
|
308
|
+
resp = response.body
|
309
|
+
resp = resp.force_encoding('UTF-8') if resp.respond_to? :force_encoding
|
310
|
+
log(:debug, "got response='#{resp}'")
|
311
|
+
Crack::XML.parse(resp)
|
312
|
+
else
|
313
|
+
log(:error, "got response='#{response.body}'")
|
314
|
+
raise "request failed with response-code='#{response.code}'"
|
315
|
+
end
|
316
|
+
end
|
317
|
+
|
318
|
+
def create_signed_query_string(params)
|
319
|
+
# nice tutorial http://cloudcarpenters.com/blog/amazon_products_api_request_signing/
|
320
|
+
params[:Service] = :AWSECommerceService
|
321
|
+
params[:AWSAccessKeyId] = Configuration.key
|
322
|
+
# utc timestamp needed for signing
|
323
|
+
params[:Timestamp] = Time.now.utc.strftime('%Y-%m-%dT%H:%M:%SZ')
|
324
|
+
|
325
|
+
# signing needs to order the query alphabetically
|
326
|
+
query = params.map{|key, value| "#{key}=#{CGI.escape(value.to_s)}" }.sort.join('&').gsub('+','%20')
|
327
|
+
|
328
|
+
# yeah, you really need to sign the get-request not the query
|
329
|
+
request_to_sign = "GET\n#{Configuration.host}\n#{PATH}\n#{query}"
|
330
|
+
hmac = OpenSSL::HMAC.digest(DIGEST, Configuration.secret, request_to_sign)
|
331
|
+
|
332
|
+
# don't forget to remove the newline from base64
|
333
|
+
signature = CGI.escape(Base64.encode64(hmac).chomp)
|
334
|
+
"#{query}&Signature=#{signature}"
|
335
|
+
end
|
336
|
+
|
337
|
+
def log(severity, message)
|
338
|
+
Configuration.logger.send severity, message if Configuration.logger
|
339
|
+
end
|
340
|
+
end
|
341
|
+
end
|
data/lib/asin/configuration.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
require "yaml"
|
2
|
+
require 'logger'
|
2
3
|
|
3
4
|
module ASIN
|
4
5
|
class Configuration
|
@@ -34,8 +35,8 @@ module ASIN
|
|
34
35
|
# [key] the API access key
|
35
36
|
# [host] the host, which defaults to 'webservices.amazon.com'
|
36
37
|
# [logger] a different logger than logging to STDERR (nil for no logging)
|
37
|
-
# [item_type] a different class for SimpleItem, use :raw for a plain
|
38
|
-
# [cart_type] a different class for SimpleCart, use :raw for a plain
|
38
|
+
# [item_type] a different class for SimpleItem, use :mash / :rash for Hashie::Mash / Hashie::Rash or :raw for a plain hash
|
39
|
+
# [cart_type] a different class for SimpleCart, use :mash / :rash for Hashie::Mash / Hashie::Rash or :raw for a plain hash
|
39
40
|
#
|
40
41
|
def configure(options={})
|
41
42
|
init_config
|
File without changes
|
File without changes
|
data/lib/asin/version.rb
CHANGED
data/rakefile.rb
CHANGED
@@ -11,7 +11,7 @@ end
|
|
11
11
|
|
12
12
|
Rake::RDocTask.new(:rdoc_dev) do |rd|
|
13
13
|
rd.rdoc_files.include(File.readlines('.document').map(&:strip))
|
14
|
-
rd.options + ['-a', '--
|
14
|
+
rd.options + ['-a', '--line-numbers', '--charset=UTF-8']
|
15
15
|
end
|
16
16
|
|
17
17
|
task :default=>:spec
|
data/spec/cart_spec.rb
CHANGED
data/spec/search_spec.rb
CHANGED
@@ -4,7 +4,7 @@ module ASIN
|
|
4
4
|
describe ASIN do
|
5
5
|
before do
|
6
6
|
ASIN::Configuration.reset
|
7
|
-
@helper = ASIN.
|
7
|
+
@helper = ASIN::Client.instance
|
8
8
|
@helper.configure :logger => nil
|
9
9
|
|
10
10
|
@secret = ENV['ASIN_SECRET']
|
@@ -93,6 +93,16 @@ module ASIN
|
|
93
93
|
@helper.lookup(ANY_ASIN)['ItemAttributes']['Title'].should_not be_nil
|
94
94
|
end
|
95
95
|
|
96
|
+
it "should return a mash value" do
|
97
|
+
@helper.configure :item_type => :mash
|
98
|
+
@helper.lookup(ANY_ASIN).ItemAttributes.Title.should_not be_nil
|
99
|
+
end
|
100
|
+
|
101
|
+
it "should return a rash value" do
|
102
|
+
@helper.configure :item_type => :rash
|
103
|
+
@helper.lookup(ANY_ASIN).item_attributes.title.should_not be_nil
|
104
|
+
end
|
105
|
+
|
96
106
|
it "should search_keywords a book with fulltext" do
|
97
107
|
items = @helper.search_keywords 'Learn', 'Objective-C'
|
98
108
|
items.should have(10).things
|
@@ -102,7 +112,7 @@ module ASIN
|
|
102
112
|
|
103
113
|
it "should search_keywords never mind music" do
|
104
114
|
items = @helper.search_keywords 'nirvana', 'never mind', :SearchIndex => :Music
|
105
|
-
items.should have(
|
115
|
+
items.should have(9).things
|
106
116
|
|
107
117
|
items.first.title.should =~ /Nevermind/
|
108
118
|
end
|
metadata
CHANGED
@@ -1,94 +1,101 @@
|
|
1
|
-
--- !ruby/object:Gem::Specification
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
2
|
name: asin
|
3
|
-
version: !ruby/object:Gem::Version
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.5.0
|
4
5
|
prerelease:
|
5
|
-
version: 0.4.0
|
6
6
|
platform: ruby
|
7
|
-
authors:
|
8
|
-
-
|
7
|
+
authors:
|
8
|
+
- Peter Schröder
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
|
13
|
-
date: 2011-05-20 00:00:00 +02:00
|
12
|
+
date: 2011-07-07 00:00:00.000000000 +02:00
|
14
13
|
default_executable:
|
15
|
-
dependencies:
|
16
|
-
- !ruby/object:Gem::Dependency
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
17
16
|
name: crack
|
18
|
-
|
19
|
-
requirement: &id001 !ruby/object:Gem::Requirement
|
17
|
+
requirement: &2153571760 !ruby/object:Gem::Requirement
|
20
18
|
none: false
|
21
|
-
requirements:
|
19
|
+
requirements:
|
22
20
|
- - ~>
|
23
|
-
- !ruby/object:Gem::Version
|
21
|
+
- !ruby/object:Gem::Version
|
24
22
|
version: 0.1.8
|
25
23
|
type: :runtime
|
26
|
-
version_requirements: *id001
|
27
|
-
- !ruby/object:Gem::Dependency
|
28
|
-
name: hashie
|
29
24
|
prerelease: false
|
30
|
-
|
25
|
+
version_requirements: *2153571760
|
26
|
+
- !ruby/object:Gem::Dependency
|
27
|
+
name: hashie
|
28
|
+
requirement: &2153571260 !ruby/object:Gem::Requirement
|
31
29
|
none: false
|
32
|
-
requirements:
|
30
|
+
requirements:
|
33
31
|
- - ~>
|
34
|
-
- !ruby/object:Gem::Version
|
32
|
+
- !ruby/object:Gem::Version
|
35
33
|
version: 1.0.0
|
36
34
|
type: :runtime
|
37
|
-
version_requirements: *id002
|
38
|
-
- !ruby/object:Gem::Dependency
|
39
|
-
name: httpi
|
40
35
|
prerelease: false
|
41
|
-
|
36
|
+
version_requirements: *2153571260
|
37
|
+
- !ruby/object:Gem::Dependency
|
38
|
+
name: httpi
|
39
|
+
requirement: &2153570800 !ruby/object:Gem::Requirement
|
42
40
|
none: false
|
43
|
-
requirements:
|
41
|
+
requirements:
|
44
42
|
- - ~>
|
45
|
-
- !ruby/object:Gem::Version
|
43
|
+
- !ruby/object:Gem::Version
|
46
44
|
version: 0.9.2
|
47
45
|
type: :runtime
|
48
|
-
version_requirements: *id003
|
49
|
-
- !ruby/object:Gem::Dependency
|
50
|
-
name: httpclient
|
51
46
|
prerelease: false
|
52
|
-
|
47
|
+
version_requirements: *2153570800
|
48
|
+
- !ruby/object:Gem::Dependency
|
49
|
+
name: httpclient
|
50
|
+
requirement: &2153570340 !ruby/object:Gem::Requirement
|
53
51
|
none: false
|
54
|
-
requirements:
|
52
|
+
requirements:
|
55
53
|
- - ~>
|
56
|
-
- !ruby/object:Gem::Version
|
54
|
+
- !ruby/object:Gem::Version
|
57
55
|
version: 2.2.0.2
|
58
56
|
type: :development
|
59
|
-
version_requirements: *id004
|
60
|
-
- !ruby/object:Gem::Dependency
|
61
|
-
name: rspec
|
62
57
|
prerelease: false
|
63
|
-
|
58
|
+
version_requirements: *2153570340
|
59
|
+
- !ruby/object:Gem::Dependency
|
60
|
+
name: rash
|
61
|
+
requirement: &2168479800 !ruby/object:Gem::Requirement
|
64
62
|
none: false
|
65
|
-
requirements:
|
63
|
+
requirements:
|
66
64
|
- - ~>
|
67
|
-
- !ruby/object:Gem::Version
|
65
|
+
- !ruby/object:Gem::Version
|
66
|
+
version: 0.3.0
|
67
|
+
type: :development
|
68
|
+
prerelease: false
|
69
|
+
version_requirements: *2168479800
|
70
|
+
- !ruby/object:Gem::Dependency
|
71
|
+
name: rspec
|
72
|
+
requirement: &2168479340 !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ~>
|
76
|
+
- !ruby/object:Gem::Version
|
68
77
|
version: 2.6.0
|
69
78
|
type: :development
|
70
|
-
version_requirements: *id005
|
71
|
-
- !ruby/object:Gem::Dependency
|
72
|
-
name: fuubar
|
73
79
|
prerelease: false
|
74
|
-
|
80
|
+
version_requirements: *2168479340
|
81
|
+
- !ruby/object:Gem::Dependency
|
82
|
+
name: fuubar
|
83
|
+
requirement: &2168478880 !ruby/object:Gem::Requirement
|
75
84
|
none: false
|
76
|
-
requirements:
|
85
|
+
requirements:
|
77
86
|
- - ~>
|
78
|
-
- !ruby/object:Gem::Version
|
87
|
+
- !ruby/object:Gem::Version
|
79
88
|
version: 0.0.4
|
80
89
|
type: :development
|
81
|
-
|
90
|
+
prerelease: false
|
91
|
+
version_requirements: *2168478880
|
82
92
|
description: Amazon Simple INterface.
|
83
|
-
email:
|
93
|
+
email:
|
84
94
|
- phoetmail@googlemail.com
|
85
95
|
executables: []
|
86
|
-
|
87
96
|
extensions: []
|
88
|
-
|
89
97
|
extra_rdoc_files: []
|
90
|
-
|
91
|
-
files:
|
98
|
+
files:
|
92
99
|
- .document
|
93
100
|
- .gitignore
|
94
101
|
- .rvmrc
|
@@ -98,9 +105,10 @@ files:
|
|
98
105
|
- README.rdoc
|
99
106
|
- asin.gemspec
|
100
107
|
- lib/asin.rb
|
101
|
-
- lib/asin/
|
108
|
+
- lib/asin/client.rb
|
102
109
|
- lib/asin/configuration.rb
|
103
|
-
- lib/asin/
|
110
|
+
- lib/asin/simple_cart.rb
|
111
|
+
- lib/asin/simple_item.rb
|
104
112
|
- lib/asin/version.rb
|
105
113
|
- rakefile.rb
|
106
114
|
- spec/asin.yml
|
@@ -110,32 +118,29 @@ files:
|
|
110
118
|
has_rdoc: true
|
111
119
|
homepage: http://github.com/phoet/asin
|
112
120
|
licenses: []
|
113
|
-
|
114
121
|
post_install_message:
|
115
122
|
rdoc_options: []
|
116
|
-
|
117
|
-
require_paths:
|
123
|
+
require_paths:
|
118
124
|
- lib
|
119
|
-
required_ruby_version: !ruby/object:Gem::Requirement
|
125
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
120
126
|
none: false
|
121
|
-
requirements:
|
122
|
-
- -
|
123
|
-
- !ruby/object:Gem::Version
|
124
|
-
version:
|
125
|
-
required_rubygems_version: !ruby/object:Gem::Requirement
|
127
|
+
requirements:
|
128
|
+
- - ! '>='
|
129
|
+
- !ruby/object:Gem::Version
|
130
|
+
version: '0'
|
131
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
126
132
|
none: false
|
127
|
-
requirements:
|
128
|
-
- -
|
129
|
-
- !ruby/object:Gem::Version
|
130
|
-
version:
|
133
|
+
requirements:
|
134
|
+
- - ! '>='
|
135
|
+
- !ruby/object:Gem::Version
|
136
|
+
version: '0'
|
131
137
|
requirements: []
|
132
|
-
|
133
138
|
rubyforge_project: asin
|
134
|
-
rubygems_version: 1.
|
139
|
+
rubygems_version: 1.6.2
|
135
140
|
signing_key:
|
136
141
|
specification_version: 3
|
137
142
|
summary: Simple interface to AWS Lookup, Search and Cart operations.
|
138
|
-
test_files:
|
143
|
+
test_files:
|
139
144
|
- spec/asin.yml
|
140
145
|
- spec/cart_spec.rb
|
141
146
|
- spec/search_spec.rb
|