asin 0.3.0 → 0.4.0.beta1
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile.lock +20 -18
- data/README.rdoc +57 -12
- data/asin.gemspec +6 -6
- data/lib/asin.rb +221 -91
- data/lib/asin/cart.rb +54 -0
- data/lib/asin/configuration.rb +40 -16
- data/lib/asin/item.rb +5 -5
- data/lib/asin/version.rb +1 -1
- data/rakefile.rb +3 -28
- data/spec/asin.yml +4 -0
- data/spec/cart_spec.rb +159 -0
- data/spec/search_spec.rb +95 -0
- data/spec/spec_helper.rb +4 -0
- metadata +17 -13
- data/.travis.yml +0 -1
- data/spec/asin_spec.rb +0 -74
data/Gemfile.lock
CHANGED
@@ -1,35 +1,37 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
asin (0.
|
4
|
+
asin (0.4.0.beta1)
|
5
5
|
crack (~> 0.1.8)
|
6
6
|
hashie (~> 1.0.0)
|
7
|
-
httpi (~> 0.
|
7
|
+
httpi (~> 0.9.2)
|
8
8
|
|
9
9
|
GEM
|
10
10
|
remote: http://rubygems.org/
|
11
11
|
specs:
|
12
|
+
chalofa_ruby-progressbar (0.0.9.1)
|
12
13
|
crack (0.1.8)
|
13
14
|
diff-lcs (1.1.2)
|
14
|
-
fuubar (0.0.
|
15
|
+
fuubar (0.0.4)
|
16
|
+
chalofa_ruby-progressbar (~> 0.0.9)
|
15
17
|
rspec (~> 2.0)
|
16
18
|
rspec-instafail (~> 0.1.4)
|
17
|
-
ruby-progressbar (~> 0.0.9)
|
18
19
|
hashie (1.0.0)
|
19
|
-
httpclient (2.1.
|
20
|
-
httpi (0.
|
20
|
+
httpclient (2.1.7.2)
|
21
|
+
httpi (0.9.2)
|
22
|
+
ntlm-http (>= 0.1.1)
|
21
23
|
rack
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
rspec-
|
26
|
-
rspec-
|
27
|
-
|
28
|
-
rspec-
|
24
|
+
ntlm-http (0.1.1)
|
25
|
+
rack (1.2.2)
|
26
|
+
rspec (2.5.0)
|
27
|
+
rspec-core (~> 2.5.0)
|
28
|
+
rspec-expectations (~> 2.5.0)
|
29
|
+
rspec-mocks (~> 2.5.0)
|
30
|
+
rspec-core (2.5.1)
|
31
|
+
rspec-expectations (2.5.0)
|
29
32
|
diff-lcs (~> 1.1.2)
|
30
|
-
rspec-instafail (0.1.
|
31
|
-
rspec-mocks (2.
|
32
|
-
ruby-progressbar (0.0.9)
|
33
|
+
rspec-instafail (0.1.7)
|
34
|
+
rspec-mocks (2.5.0)
|
33
35
|
|
34
36
|
PLATFORMS
|
35
37
|
ruby
|
@@ -37,5 +39,5 @@ PLATFORMS
|
|
37
39
|
DEPENDENCIES
|
38
40
|
asin!
|
39
41
|
fuubar (~> 0.0.3)
|
40
|
-
httpclient (~> 2.1.
|
41
|
-
rspec (~> 2.
|
42
|
+
httpclient (~> 2.1.7.2)
|
43
|
+
rspec (~> 2.5.0)
|
data/README.rdoc
CHANGED
@@ -2,34 +2,49 @@
|
|
2
2
|
|
3
3
|
Status: http://stillmaintained.com/phoet/asin.png
|
4
4
|
|
5
|
-
The gem is tested against 1.9.2
|
5
|
+
The gem is tested against 1.9.2 and 1.8.7 (compatibility with Heroku-Bamboo-Stack[http://docs.heroku.com/stack]) and runs smoothly with Rails 3.
|
6
6
|
|
7
7
|
gem install asin
|
8
|
+
gem install httpclient # optional, see HTTPI
|
8
9
|
|
9
10
|
== Configuration
|
10
11
|
|
11
|
-
|
12
|
-
|
13
|
-
You can put this in a initializer (config/initializers/asin.rb):
|
12
|
+
Rails style initializer (config/initializers/asin.rb):
|
14
13
|
|
15
14
|
ASIN::Configuration.configure do |config|
|
16
15
|
config.secret = 'your-secret'
|
17
16
|
config.key = 'your-key'
|
18
17
|
end
|
19
18
|
|
20
|
-
|
19
|
+
YAML style configuration:
|
20
|
+
|
21
|
+
ASIN::Configuration.configure :yaml => 'config/asin.yml'
|
22
|
+
|
23
|
+
Inline style configuration:
|
24
|
+
|
25
|
+
ASIN::Configuration.configure :secret => 'your-secret', :key => 'your-key'
|
26
|
+
# or
|
27
|
+
client.configure :secret => 'your-secret', :key => 'your-key'
|
28
|
+
|
29
|
+
== Usage
|
30
|
+
|
31
|
+
ASIN is designed as a module, so you can include it into any object you like:
|
21
32
|
|
33
|
+
# require and include
|
22
34
|
require 'asin'
|
23
35
|
include ASIN
|
24
36
|
|
25
|
-
#
|
26
|
-
|
37
|
+
# lookup an ASIN
|
38
|
+
lookup '1430218150'
|
27
39
|
|
28
|
-
|
40
|
+
But you can also use the +client+ method to get a client-object:
|
29
41
|
|
42
|
+
# just require
|
43
|
+
require 'asin'
|
44
|
+
|
30
45
|
# create an ASIN client
|
31
46
|
client = ASIN.client
|
32
|
-
|
47
|
+
|
33
48
|
# lookup an item with the amazon standard identification number (asin)
|
34
49
|
item = client.lookup '1430218150'
|
35
50
|
|
@@ -51,6 +66,39 @@ The old configuration syntax is still valid:
|
|
51
66
|
item.raw.ItemAttributes.ListPrice.FormattedPrice
|
52
67
|
=> $39.99
|
53
68
|
|
69
|
+
There is an additional set of methods to support AWS cart operations:
|
70
|
+
|
71
|
+
#just require
|
72
|
+
require 'asin'
|
73
|
+
|
74
|
+
# create an ASIN client
|
75
|
+
client = ASIN.client
|
76
|
+
|
77
|
+
# create a cart with an item
|
78
|
+
cart = client.create_cart({:asin => '1430218150', :quantity => 1})
|
79
|
+
cart.items
|
80
|
+
=> [<#Hashie::Mash ASIN="1430218150" CartItemId="U3G241HVLLB8N6" ... >]
|
81
|
+
|
82
|
+
# get an already existing cart from a CartId and HMAC
|
83
|
+
cart = client.get_cart('176-9182855-2326919', 'KgeVCA0YJTbuN/7Ibakrk/KnHWA=')
|
84
|
+
cart.empty?
|
85
|
+
=> false
|
86
|
+
|
87
|
+
# clear everything from the cart
|
88
|
+
cart = client.clear_cart(cart)
|
89
|
+
cart.empty?
|
90
|
+
=> true
|
91
|
+
|
92
|
+
# add items to the cart
|
93
|
+
cart = client.add_items(cart, {:asin => '1430216263', :quantity => 2})
|
94
|
+
cart.empty?
|
95
|
+
=> false
|
96
|
+
|
97
|
+
# update items in the cart
|
98
|
+
cart = client.update_items(cart, {:cart_item_id => cart.items.first.CartItemId, :action => :SaveForLater}, {:cart_item_id => cart.items.first.CartItemId, :quantity => 7})
|
99
|
+
cart.saved_items
|
100
|
+
=> [<#Hashie::Mash ASIN="1430218150" CartItemId="U3G241HVLLB8N6" ... >]
|
101
|
+
|
54
102
|
== HTTPI
|
55
103
|
|
56
104
|
ASIN uses HTTPI[https://github.com/rubiii/httpi] as a HTTP-Client adapter.
|
@@ -64,6 +112,3 @@ As a default HTTPI uses _httpclient_ so you should add that dependency to your p
|
|
64
112
|
Have a look at the RDOC[http://rdoc.info/projects/phoet/asin] for this project, if you want further information.
|
65
113
|
|
66
114
|
For more information on the REST calls, have a look at the whole Amazon E-Commerce-API[http://docs.amazonwebservices.com/AWSEcommerceService/4-0/].
|
67
|
-
|
68
|
-
The code currently runs best on Ruby-1.9 due to encoding issues with the Amazon REST output (if *YOU* know how to backport this to 1.8.7, you are welcome!).
|
69
|
-
|
data/asin.gemspec
CHANGED
@@ -9,10 +9,10 @@ Gem::Specification.new do |s|
|
|
9
9
|
s.authors = ['Peter Schröder']
|
10
10
|
s.email = ['phoetmail@googlemail.com']
|
11
11
|
s.homepage = 'http://github.com/phoet/asin'
|
12
|
-
s.summary = 'Simple interface to
|
13
|
-
s.description = 'Amazon Simple INterface
|
12
|
+
s.summary = 'Simple interface to AWS Lookup, Search and Cart operations.'
|
13
|
+
s.description = 'Amazon Simple INterface.'
|
14
14
|
|
15
|
-
s.rubyforge_project = "asin"
|
15
|
+
s.rubyforge_project = "asin" # rubyforge, WTF?!
|
16
16
|
|
17
17
|
s.files = `git ls-files`.split("\n")
|
18
18
|
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
@@ -21,9 +21,9 @@ Gem::Specification.new do |s|
|
|
21
21
|
|
22
22
|
s.add_dependency('crack', '~> 0.1.8')
|
23
23
|
s.add_dependency('hashie', '~> 1.0.0')
|
24
|
-
s.add_dependency('httpi', '~> 0.
|
24
|
+
s.add_dependency('httpi', '~> 0.9.2')
|
25
25
|
|
26
|
-
s.add_development_dependency('httpclient', '~> 2.1.
|
27
|
-
s.add_development_dependency('rspec', '~> 2.
|
26
|
+
s.add_development_dependency('httpclient', '~> 2.1.7.2')
|
27
|
+
s.add_development_dependency('rspec', '~> 2.5.0')
|
28
28
|
s.add_development_dependency('fuubar', '~> 0.0.3')
|
29
29
|
end
|
data/lib/asin.rb
CHANGED
@@ -1,3 +1,4 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
1
2
|
require 'httpi'
|
2
3
|
require 'crack/xml'
|
3
4
|
require 'cgi'
|
@@ -5,65 +6,97 @@ require 'base64'
|
|
5
6
|
require 'logger'
|
6
7
|
|
7
8
|
require 'asin/item'
|
9
|
+
require 'asin/cart'
|
8
10
|
require 'asin/version'
|
9
11
|
require 'asin/configuration'
|
10
12
|
|
11
13
|
# ASIN (Amazon Simple INterface) is a gem for easy access of the Amazon E-Commerce-API.
|
12
14
|
# It is simple to configure and use. Since it's very small and flexible, it is easy to extend it to your needs.
|
13
|
-
#
|
15
|
+
#
|
14
16
|
# Author:: Peter Schröder (mailto:phoetmail@googlemail.com)
|
15
|
-
#
|
16
|
-
# ==Usage
|
17
|
-
#
|
17
|
+
#
|
18
|
+
# == Usage
|
19
|
+
#
|
18
20
|
# The ASIN module is designed as a mixin.
|
19
|
-
#
|
21
|
+
#
|
20
22
|
# require 'asin'
|
21
23
|
# include ASIN
|
22
|
-
#
|
24
|
+
#
|
23
25
|
# In order to use the Amazon API properly, you need to be a registered user (http://aws.amazon.com).
|
24
|
-
#
|
26
|
+
#
|
25
27
|
# The registration process will give you a +secret-key+ and an +access-key+ (AWSAccessKeyId).
|
26
|
-
#
|
28
|
+
#
|
27
29
|
# Both are needed to use ASIN (see Configuration for more details):
|
28
|
-
#
|
30
|
+
#
|
29
31
|
# configure :secret => 'your-secret', :key => 'your-key'
|
30
|
-
#
|
31
|
-
#
|
32
|
+
#
|
33
|
+
# == Search
|
34
|
+
#
|
35
|
+
# After configuring your environment you can call the +lookup+ method to retrieve an +Item+ via the
|
32
36
|
# Amazon Standard Identification Number (ASIN):
|
33
|
-
#
|
37
|
+
#
|
34
38
|
# item = lookup '1430218150'
|
35
39
|
# item.title
|
36
40
|
# => "Learn Objective-C on the Mac (Learn Series)"
|
37
41
|
#
|
38
42
|
# OR search with fulltext/ASIN/ISBN
|
39
|
-
#
|
43
|
+
#
|
40
44
|
# items = search 'Learn Objective-C'
|
41
45
|
# items.first.title
|
42
46
|
# => "Learn Objective-C on the Mac (Learn Series)"
|
43
|
-
#
|
47
|
+
#
|
44
48
|
# The +Item+ uses a Hashie::Mash as its internal data representation and you can get fetched data from it:
|
45
|
-
#
|
49
|
+
#
|
46
50
|
# item.raw.ItemAttributes.ListPrice.FormattedPrice
|
47
51
|
# => "$39.99"
|
48
|
-
#
|
49
|
-
# ==Further Configuration
|
50
|
-
#
|
51
|
-
# If you need more controll over the request that is sent to the
|
52
|
+
#
|
53
|
+
# == Further Configuration
|
54
|
+
#
|
55
|
+
# If you need more controll over the request that is sent to the
|
52
56
|
# Amazon API (http://docs.amazonwebservices.com/AWSEcommerceService/4-0/),
|
53
57
|
# you can override some defaults or add additional query-parameters to the REST calls:
|
54
|
-
#
|
58
|
+
#
|
55
59
|
# configure :host => 'webservices.amazon.de'
|
56
60
|
# lookup(asin, :ResponseGroup => :Medium)
|
57
|
-
#
|
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
|
+
#
|
58
91
|
module ASIN
|
59
|
-
|
92
|
+
|
60
93
|
DIGEST = OpenSSL::Digest::Digest.new('sha256')
|
61
94
|
PATH = '/onca/xml'
|
62
95
|
|
63
96
|
# Convenience method to create an ASIN client.
|
64
|
-
#
|
97
|
+
#
|
65
98
|
# A client is not necessary though, you can simply include the ASIN module otherwise.
|
66
|
-
#
|
99
|
+
#
|
67
100
|
def self.client
|
68
101
|
client = Object.new
|
69
102
|
client.extend ASIN
|
@@ -71,48 +104,48 @@ module ASIN
|
|
71
104
|
end
|
72
105
|
|
73
106
|
# Configures the basic request parameters for ASIN.
|
74
|
-
#
|
107
|
+
#
|
75
108
|
# Expects at least +secret+ and +key+ for the API call:
|
76
|
-
#
|
109
|
+
#
|
77
110
|
# configure :secret => 'your-secret', :key => 'your-key'
|
78
|
-
#
|
111
|
+
#
|
79
112
|
# See ASIN::Configuration for more infos.
|
80
|
-
#
|
113
|
+
#
|
81
114
|
def configure(options={})
|
82
115
|
Configuration.configure(options)
|
83
116
|
end
|
84
117
|
|
85
118
|
# Performs an +ItemLookup+ REST call against the Amazon API.
|
86
|
-
#
|
119
|
+
#
|
87
120
|
# Expects an ASIN (Amazon Standard Identification Number) and returns an +Item+:
|
88
|
-
#
|
121
|
+
#
|
89
122
|
# item = lookup '1430218150'
|
90
123
|
# item.title
|
91
124
|
# => "Learn Objective-C on the Mac (Learn Series)"
|
92
|
-
#
|
125
|
+
#
|
93
126
|
# ==== Options:
|
94
|
-
#
|
127
|
+
#
|
95
128
|
# Additional parameters for the API call like this:
|
96
|
-
#
|
129
|
+
#
|
97
130
|
# lookup(asin, :ResponseGroup => :Medium)
|
98
|
-
#
|
131
|
+
#
|
99
132
|
def lookup(asin, params={})
|
100
133
|
response = call(params.merge(:Operation => :ItemLookup, :ItemId => asin))
|
101
134
|
Item.new(response['ItemLookupResponse']['Items']['Item'])
|
102
135
|
end
|
103
|
-
|
136
|
+
|
104
137
|
# Performs an +ItemSearch+ REST call against the Amazon API.
|
105
|
-
#
|
138
|
+
#
|
106
139
|
# Expects a search-string which can be an arbitrary array of strings (ASINs f.e.) and returns a list of +Items+:
|
107
|
-
#
|
140
|
+
#
|
108
141
|
# items = search_keywords 'Learn', 'Objective-C'
|
109
142
|
# items.first.title
|
110
143
|
# => "Learn Objective-C on the Mac (Learn Series)"
|
111
|
-
#
|
144
|
+
#
|
112
145
|
# ==== Options:
|
113
|
-
#
|
146
|
+
#
|
114
147
|
# Additional parameters for the API call like this:
|
115
|
-
#
|
148
|
+
#
|
116
149
|
# search_keywords('nirvana', 'never mind', :SearchIndex => :Music)
|
117
150
|
#
|
118
151
|
# Have a look at the different search index values on the Amazon-Documentation[http://docs.amazonwebservices.com/AWSEcommerceService/4-0/]
|
@@ -122,17 +155,17 @@ module ASIN
|
|
122
155
|
response = call(params.merge(:Operation => :ItemSearch, :Keywords => keywords.join(' ')))
|
123
156
|
(response['ItemSearchResponse']['Items']['Item'] || []).map {|item| Item.new(item)}
|
124
157
|
end
|
125
|
-
|
158
|
+
|
126
159
|
# Performs an +ItemSearch+ REST call against the Amazon API.
|
127
|
-
#
|
160
|
+
#
|
128
161
|
# Expects a Hash of search params where and returns a list of +Items+:
|
129
|
-
#
|
162
|
+
#
|
130
163
|
# items = search :SearchIndex => :Music
|
131
|
-
#
|
164
|
+
#
|
132
165
|
# ==== Options:
|
133
|
-
#
|
166
|
+
#
|
134
167
|
# Additional parameters for the API call like this:
|
135
|
-
#
|
168
|
+
#
|
136
169
|
# search(:Keywords => 'nirvana', :SearchIndex => :Music)
|
137
170
|
#
|
138
171
|
# Have a look at the different search index values on the Amazon-Documentation[http://docs.amazonwebservices.com/AWSEcommerceService/4-0/]
|
@@ -141,57 +174,154 @@ module ASIN
|
|
141
174
|
response = call(params.merge(:Operation => :ItemSearch))
|
142
175
|
(response['ItemSearchResponse']['Items']['Item'] || []).map {|item| Item.new(item)}
|
143
176
|
end
|
144
|
-
|
145
|
-
private
|
146
177
|
|
147
|
-
|
148
|
-
|
178
|
+
# Performs an +CartCreate+ REST call against the Amazon API.
|
179
|
+
#
|
180
|
+
# Expects one ore more Item-Hashes and returns a +Cart+:
|
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 +Cart+:
|
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})
|
149
204
|
end
|
150
205
|
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
else
|
168
|
-
log(:error, "got response='#{response.body}'")
|
169
|
-
raise "request failed with response-code='#{response.code}'"
|
170
|
-
end
|
206
|
+
# Performs an +CartAdd+ REST call against the Amazon API.
|
207
|
+
#
|
208
|
+
# Expects a +Cart+ created with +create_cart+ and one ore more Item-Hashes and returns an updated +Cart+:
|
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}))
|
171
222
|
end
|
172
223
|
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
"#{query}&Signature=#{signature}"
|
224
|
+
# Performs an +CartModify+ REST call against the Amazon API.
|
225
|
+
#
|
226
|
+
# Expects a +Cart+ created with +create_cart+ and one ore more Item-Hashes to modify and returns an updated +Cart+:
|
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}))
|
190
240
|
end
|
191
|
-
|
192
|
-
|
193
|
-
|
241
|
+
|
242
|
+
# Performs an +CartClear+ REST call against the Amazon API.
|
243
|
+
#
|
244
|
+
# Expects a +Cart+ created with +create_cart+ and returns an empty +Cart+:
|
245
|
+
#
|
246
|
+
# cart = clear_cart(cart)
|
247
|
+
#
|
248
|
+
def clear_cart(cart)
|
249
|
+
cart(:CartClear, {:CartId => cart.cart_id, :HMAC => cart.hmac})
|
194
250
|
end
|
195
251
|
|
196
|
-
|
252
|
+
private
|
253
|
+
|
254
|
+
def create_item_params(items)
|
255
|
+
keyword_mappings = {
|
256
|
+
:asin => 'ASIN',
|
257
|
+
:quantity => 'Quantity',
|
258
|
+
:cart_item_id => 'CartItemId',
|
259
|
+
:offer_listing_id => 'OfferListingId',
|
260
|
+
:action => 'Action'
|
261
|
+
}
|
262
|
+
params = {}
|
263
|
+
items.each_with_index do |item, i|
|
264
|
+
item.each do |key, value|
|
265
|
+
next unless keyword = keyword_mappings[key]
|
266
|
+
params["Item.#{i}.#{keyword}"] = value.to_s
|
267
|
+
end
|
268
|
+
end
|
269
|
+
params
|
270
|
+
end
|
271
|
+
|
272
|
+
def cart(operation, params={})
|
273
|
+
response = call(params.merge(:Operation => operation))
|
274
|
+
Cart.new(response["#{operation}Response"]['Cart'])
|
275
|
+
end
|
276
|
+
|
277
|
+
|
278
|
+
def credentials_valid?
|
279
|
+
Configuration.secret && Configuration.key
|
280
|
+
end
|
197
281
|
|
282
|
+
def call(params)
|
283
|
+
raise "you have to configure ASIN: 'configure :secret => 'your-secret', :key => 'your-key''" unless credentials_valid?
|
284
|
+
|
285
|
+
log(:debug, "calling with params=#{params}")
|
286
|
+
signed = create_signed_query_string(params)
|
287
|
+
|
288
|
+
url = "http://#{Configuration.host}#{PATH}?#{signed}"
|
289
|
+
log(:info, "performing rest call to url='#{url}'")
|
290
|
+
|
291
|
+
response = HTTPI.get(url)
|
292
|
+
if response.code == 200
|
293
|
+
# force utf-8 chars, works only on 1.9 string
|
294
|
+
resp = response.body
|
295
|
+
resp = resp.force_encoding('UTF-8') if resp.respond_to? :force_encoding
|
296
|
+
log(:debug, "got response='#{resp}'")
|
297
|
+
Crack::XML.parse(resp)
|
298
|
+
else
|
299
|
+
log(:error, "got response='#{response.body}'")
|
300
|
+
raise "request failed with response-code='#{response.code}'"
|
301
|
+
end
|
302
|
+
end
|
303
|
+
|
304
|
+
def create_signed_query_string(params)
|
305
|
+
# nice tutorial http://cloudcarpenters.com/blog/amazon_products_api_request_signing/
|
306
|
+
params[:Service] = :AWSECommerceService
|
307
|
+
params[:AWSAccessKeyId] = Configuration.key
|
308
|
+
# utc timestamp needed for signing
|
309
|
+
params[:Timestamp] = Time.now.utc.strftime('%Y-%m-%dT%H:%M:%SZ')
|
310
|
+
|
311
|
+
# signing needs to order the query alphabetically
|
312
|
+
query = params.map{|key, value| "#{key}=#{CGI.escape(value.to_s)}" }.sort.join('&').gsub('+','%20')
|
313
|
+
|
314
|
+
# yeah, you really need to sign the get-request not the query
|
315
|
+
request_to_sign = "GET\n#{Configuration.host}\n#{PATH}\n#{query}"
|
316
|
+
hmac = OpenSSL::HMAC.digest(DIGEST, Configuration.secret, request_to_sign)
|
317
|
+
|
318
|
+
# don't forget to remove the newline from base64
|
319
|
+
signature = CGI.escape(Base64.encode64(hmac).chomp)
|
320
|
+
"#{query}&Signature=#{signature}"
|
321
|
+
end
|
322
|
+
|
323
|
+
def log(severity, message)
|
324
|
+
Configuration.logger.send severity, message if Configuration.logger
|
325
|
+
end
|
326
|
+
|
327
|
+
end
|
data/lib/asin/cart.rb
ADDED
@@ -0,0 +1,54 @@
|
|
1
|
+
require 'hashie'
|
2
|
+
|
3
|
+
module ASIN
|
4
|
+
|
5
|
+
# = Cart
|
6
|
+
#
|
7
|
+
# The +Cart+ class is a wrapper for the Amazon XML-REST-Response.
|
8
|
+
#
|
9
|
+
# A Hashie::Mash is used for the internal data representation and can be accessed over the +raw+ attribute.
|
10
|
+
#
|
11
|
+
class Cart
|
12
|
+
|
13
|
+
attr_reader :raw
|
14
|
+
|
15
|
+
def initialize(hash)
|
16
|
+
@raw = Hashie::Mash.new(hash)
|
17
|
+
end
|
18
|
+
|
19
|
+
def cart_id
|
20
|
+
@raw.CartId
|
21
|
+
end
|
22
|
+
|
23
|
+
def hmac
|
24
|
+
@raw.HMAC
|
25
|
+
end
|
26
|
+
|
27
|
+
def url
|
28
|
+
@raw.PurchaseURL
|
29
|
+
end
|
30
|
+
|
31
|
+
def price
|
32
|
+
@raw.SubTotal.FormattedPrice
|
33
|
+
end
|
34
|
+
|
35
|
+
def items
|
36
|
+
return [] unless @raw.CartItems
|
37
|
+
@raw.CartItems.CartItem.is_a?(Array) ? @raw.CartItems.CartItem : [@raw.CartItems.CartItem]
|
38
|
+
end
|
39
|
+
|
40
|
+
def saved_items
|
41
|
+
return [] unless @raw.SavedForLaterItems
|
42
|
+
@raw.SavedForLaterItems.SavedForLaterItem.is_a?(Array) ? @raw.SavedForLaterItems.SavedForLaterItem : [@raw.SavedForLaterItems.SavedForLaterItem]
|
43
|
+
end
|
44
|
+
|
45
|
+
def valid?
|
46
|
+
@raw.Request.IsValid == 'True'
|
47
|
+
end
|
48
|
+
|
49
|
+
def empty?
|
50
|
+
@raw.CartItems.nil?
|
51
|
+
end
|
52
|
+
|
53
|
+
end
|
54
|
+
end
|
data/lib/asin/configuration.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
require "yaml"
|
2
|
+
|
1
3
|
module ASIN
|
2
4
|
class Configuration
|
3
5
|
class << self
|
@@ -5,9 +7,9 @@ module ASIN
|
|
5
7
|
attr_accessor :secret, :key, :host, :logger
|
6
8
|
|
7
9
|
# Rails initializer configuration.
|
8
|
-
#
|
10
|
+
#
|
9
11
|
# Expects at least +secret+ and +key+ for the API call:
|
10
|
-
#
|
12
|
+
#
|
11
13
|
# ASIN::Configuration.configure do |config|
|
12
14
|
# config.secret = 'your-secret'
|
13
15
|
# config.key = 'your-key'
|
@@ -15,18 +17,35 @@ module ASIN
|
|
15
17
|
#
|
16
18
|
# You may pass options as a hash as well:
|
17
19
|
#
|
18
|
-
# ASIN::Configuration.configure
|
19
|
-
#
|
20
|
+
# ASIN::Configuration.configure :secret => 'your-secret', :key => 'your-key'
|
21
|
+
#
|
22
|
+
# Or configure everything using YAML:
|
23
|
+
#
|
24
|
+
# ASIN::Configuration.configure :yaml => 'config/asin.yml'
|
25
|
+
#
|
26
|
+
# ASIN::Configuration.configure :yaml => 'config/asin.yml' do |config, yml|
|
27
|
+
# config.key = yml[Rails.env]['aws_access_key']
|
28
|
+
# end
|
29
|
+
#
|
20
30
|
# ==== Options:
|
21
|
-
#
|
31
|
+
#
|
22
32
|
# [secret] the API secret key
|
23
33
|
# [key] the API access key
|
24
34
|
# [host] the host, which defaults to 'webservices.amazon.com'
|
25
35
|
# [logger] a different logger than logging to STDERR (nil for no logging)
|
26
|
-
#
|
36
|
+
#
|
27
37
|
def configure(options={})
|
28
38
|
init_config
|
29
|
-
if
|
39
|
+
if yml_path = options[:yaml] || options[:yml]
|
40
|
+
yml = File.open(yml_path) { |file| YAML.load(file) }
|
41
|
+
if block_given?
|
42
|
+
yield self, yml
|
43
|
+
else
|
44
|
+
yml.each do |key, value|
|
45
|
+
send(:"#{key}=", value)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
elsif block_given?
|
30
49
|
yield self
|
31
50
|
else
|
32
51
|
options.each do |key, value|
|
@@ -36,17 +55,22 @@ module ASIN
|
|
36
55
|
self
|
37
56
|
end
|
38
57
|
|
58
|
+
# Resets configuration to defaults
|
59
|
+
#
|
60
|
+
def reset
|
61
|
+
init_config(true)
|
62
|
+
end
|
63
|
+
|
39
64
|
private
|
40
65
|
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
66
|
+
def init_config(force=false)
|
67
|
+
return if @init && !force
|
68
|
+
@init = true
|
69
|
+
@secret = ''
|
70
|
+
@key = ''
|
71
|
+
@host = 'webservices.amazon.com'
|
72
|
+
@logger = Logger.new(STDERR)
|
73
|
+
end
|
49
74
|
end
|
50
75
|
end
|
51
76
|
end
|
52
|
-
|
data/lib/asin/item.rb
CHANGED
@@ -3,11 +3,11 @@ require 'hashie'
|
|
3
3
|
module ASIN
|
4
4
|
|
5
5
|
# =Item
|
6
|
-
#
|
6
|
+
#
|
7
7
|
# The +Item+ class is a wrapper for the Amazon XML-REST-Response.
|
8
|
-
#
|
8
|
+
#
|
9
9
|
# A Hashie::Mash is used for the internal data representation and can be accessed over the +raw+ attribute.
|
10
|
-
#
|
10
|
+
#
|
11
11
|
class Item
|
12
12
|
|
13
13
|
attr_reader :raw
|
@@ -20,5 +20,5 @@ module ASIN
|
|
20
20
|
@raw.ItemAttributes.Title
|
21
21
|
end
|
22
22
|
end
|
23
|
-
|
24
|
-
end
|
23
|
+
|
24
|
+
end
|
data/lib/asin/version.rb
CHANGED
data/rakefile.rb
CHANGED
@@ -1,42 +1,17 @@
|
|
1
1
|
require "bundler"
|
2
2
|
require "rake/rdoctask"
|
3
|
-
require "rake/gempackagetask"
|
4
3
|
require 'rspec/core/rake_task'
|
5
4
|
|
5
|
+
Bundler::GemHelper.install_tasks
|
6
|
+
|
6
7
|
RSpec::Core::RakeTask.new do |t|
|
7
8
|
t.rspec_opts = ["--format Fuubar", "--color", "-r ./spec/spec_helper.rb"]
|
8
9
|
t.pattern = 'spec/**/*_spec.rb'
|
9
10
|
end
|
10
11
|
|
11
|
-
Bundler::GemHelper.install_tasks
|
12
|
-
|
13
|
-
spec = eval(File.new("asin.gemspec").readlines.join("\n"))
|
14
|
-
|
15
|
-
Rake::GemPackageTask.new(spec) do |pkg|
|
16
|
-
pkg.need_zip = true
|
17
|
-
pkg.need_tar = true
|
18
|
-
end
|
19
|
-
|
20
12
|
Rake::RDocTask.new(:rdoc_dev) do |rd|
|
21
13
|
rd.rdoc_files.include("lib/**/*.rb", "README.rdoc")
|
22
14
|
rd.options + ['-a', '--inline-source', '--charset=UTF-8']
|
23
15
|
end
|
24
16
|
|
25
|
-
|
26
|
-
task :test do
|
27
|
-
require 'rake/testtask'
|
28
|
-
Rake::TestTask.new do |t|
|
29
|
-
t.libs << "test"
|
30
|
-
t.ruby_opts << "-rubygems"
|
31
|
-
t.test_files = FileList['test/test_*.rb']
|
32
|
-
t.verbose = true
|
33
|
-
end
|
34
|
-
end
|
35
|
-
task :default=>:test
|
36
|
-
|
37
|
-
desc "execute build on travis-ci"
|
38
|
-
task :travis_ci do
|
39
|
-
puts "WE LOOOOOOOOOOOOVE"
|
40
|
-
Rake::Task['spec'].invoke
|
41
|
-
puts "TRAVIS CI"
|
42
|
-
end
|
17
|
+
task :default=>:spec
|
data/spec/asin.yml
ADDED
data/spec/cart_spec.rb
ADDED
@@ -0,0 +1,159 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module ASIN
|
4
|
+
describe ASIN do
|
5
|
+
|
6
|
+
before do
|
7
|
+
ASIN::Configuration.reset
|
8
|
+
@helper = ASIN.client
|
9
|
+
@helper.configure :logger => nil
|
10
|
+
|
11
|
+
@secret = ENV['ASIN_SECRET']
|
12
|
+
@key = ENV['ASIN_KEY']
|
13
|
+
puts "configure #{@secret} and #{@key} for this test"
|
14
|
+
@helper.configure :secret => @secret, :key => @key
|
15
|
+
end
|
16
|
+
|
17
|
+
context "cart" do
|
18
|
+
|
19
|
+
it "should create a cart" do
|
20
|
+
cart = @helper.create_cart({:asin => ANY_ASIN, :quantity => 1}, {:asin => OTHER_ASIN, :quantity => 2})
|
21
|
+
cart.valid?.should be(true)
|
22
|
+
cart.empty?.should be(false)
|
23
|
+
end
|
24
|
+
|
25
|
+
it "should handle item paramters" do
|
26
|
+
params = @helper.send(:create_item_params, [{:asin => 'any_asin', :quantity => 1}, {:cart_item_id => 'any_cart_item_id', :quantity => 2}, {:offer_listing_id => 'any_offer_listing_id', :quantity => 3},{:cart_item_id => 'any_cart_item_id', :action => :SaveForLater}])
|
27
|
+
params.should eql({"Item.0.ASIN"=>"any_asin", "Item.0.Quantity"=>"1", "Item.1.CartItemId"=>"any_cart_item_id", "Item.1.Quantity"=>"2", "Item.2.OfferListingId"=>"any_offer_listing_id", "Item.2.Quantity"=>"3", "Item.3.CartItemId"=>"any_cart_item_id", "Item.3.Action"=>"SaveForLater"})
|
28
|
+
end
|
29
|
+
|
30
|
+
context "with an existing cart" do
|
31
|
+
|
32
|
+
before do
|
33
|
+
@cart = @helper.create_cart({:asin => ANY_ASIN, :quantity => 1})
|
34
|
+
@cart.valid?.should be(true)
|
35
|
+
end
|
36
|
+
|
37
|
+
it "should clear a cart" do
|
38
|
+
cart = @helper.clear_cart(@cart)
|
39
|
+
cart.valid?.should be(true)
|
40
|
+
cart.empty?.should be(true)
|
41
|
+
end
|
42
|
+
|
43
|
+
it "should get a cart" do
|
44
|
+
cart = @helper.get_cart(@cart.cart_id, @cart.hmac)
|
45
|
+
cart.valid?.should be(true)
|
46
|
+
cart.empty?.should be(false)
|
47
|
+
end
|
48
|
+
|
49
|
+
it "should add items to a cart" do
|
50
|
+
cart = @helper.add_items(@cart, {:asin => OTHER_ASIN, :quantity => 2})
|
51
|
+
cart.valid?.should be(true)
|
52
|
+
cart.empty?.should be(false)
|
53
|
+
cart.items.should have(2).things
|
54
|
+
end
|
55
|
+
|
56
|
+
it "should update a cart" do
|
57
|
+
item_id = @cart.items.first.CartItemId
|
58
|
+
cart = @helper.update_items(@cart, {:cart_item_id => item_id, :action => 'SaveForLater'}, {:cart_item_id => item_id, :quantity => 7})
|
59
|
+
cart.saved_items.should have(1).things
|
60
|
+
cart.valid?.should be(true)
|
61
|
+
end
|
62
|
+
|
63
|
+
end
|
64
|
+
|
65
|
+
context Cart do
|
66
|
+
|
67
|
+
before do
|
68
|
+
@helper.configure :secret => @secret, :key => @key
|
69
|
+
@two_items = {"Request"=>
|
70
|
+
{"IsValid"=>"True",
|
71
|
+
"CartAddRequest"=>
|
72
|
+
{"CartId"=>"186-8702292-9782208",
|
73
|
+
"HMAC"=>"Ck5MXUE+OQiC/Jh8u6NhBf5FbV8=",
|
74
|
+
"Items"=>{"Item"=>{"ASIN"=>"1430216263", "Quantity"=>"2"}}}},
|
75
|
+
"CartId"=>"186-8702292-9782208",
|
76
|
+
"HMAC"=>"Ck5MXUE+OQiC/Jh8u6NhBf5FbV8=",
|
77
|
+
"URLEncodedHMAC"=>"Ck5MXUE%2BOQiC%2FJh8u6NhBf5FbV8%3D",
|
78
|
+
"PurchaseURL"=>
|
79
|
+
"https://www.amazon.com/gp/cart/aws-merge.html?cart-id=186-8702292-9782208%26associate-id=ws%26hmac=Ck5MXUE%2BOQiC/Jh8u6NhBf5FbV8=%26SubscriptionId=AKIAJFA5X7RTOKFNPVZQ%26MergeCart=False",
|
80
|
+
"SubTotal"=>
|
81
|
+
{"Amount"=>"6595", "CurrencyCode"=>"USD", "FormattedPrice"=>"$65.95"},
|
82
|
+
"CartItems"=>
|
83
|
+
{"SubTotal"=>
|
84
|
+
{"Amount"=>"6595", "CurrencyCode"=>"USD", "FormattedPrice"=>"$65.95"},
|
85
|
+
"CartItem"=>
|
86
|
+
[{"CartItemId"=>"U3CFEHHIPJNW3L",
|
87
|
+
"ASIN"=>"1430216263",
|
88
|
+
"MerchantId"=>"ATVPDKIKX0DER",
|
89
|
+
"SellerId"=>"A2R2RITDJNW1Q6",
|
90
|
+
"SellerNickname"=>"Amazon.com",
|
91
|
+
"Quantity"=>"2",
|
92
|
+
"Title"=>"Beginning iPhone Development: Exploring the iPhone SDK",
|
93
|
+
"ProductGroup"=>"Book",
|
94
|
+
"Price"=>
|
95
|
+
{"Amount"=>"1978", "CurrencyCode"=>"USD", "FormattedPrice"=>"$19.78"},
|
96
|
+
"ItemTotal"=>
|
97
|
+
{"Amount"=>"3956", "CurrencyCode"=>"USD", "FormattedPrice"=>"$39.56"}},
|
98
|
+
{"CartItemId"=>"U3G241HVLLB8N6",
|
99
|
+
"ASIN"=>"1430218150",
|
100
|
+
"MerchantId"=>"ATVPDKIKX0DER",
|
101
|
+
"SellerId"=>"A2R2RITDJNW1Q6",
|
102
|
+
"SellerNickname"=>"Amazon.com",
|
103
|
+
"Quantity"=>"1",
|
104
|
+
"Title"=>"Learn Objective-C on the Mac (Learn Series)",
|
105
|
+
"ProductGroup"=>"Book",
|
106
|
+
"Price"=>
|
107
|
+
{"Amount"=>"2639", "CurrencyCode"=>"USD", "FormattedPrice"=>"$26.39"},
|
108
|
+
"ItemTotal"=>
|
109
|
+
{"Amount"=>"2639",
|
110
|
+
"CurrencyCode"=>"USD",
|
111
|
+
"FormattedPrice"=>"$26.39"}}]}}
|
112
|
+
@one_item = {"Request"=>
|
113
|
+
{"IsValid"=>"True",
|
114
|
+
"CartCreateRequest"=>
|
115
|
+
{"Items"=>{"Item"=>{"ASIN"=>"1430218150", "Quantity"=>"1"}}}},
|
116
|
+
"CartId"=>"176-9182855-2326919",
|
117
|
+
"HMAC"=>"KgeVCA0YJTbuN/7Ibakrk/KnHWA=",
|
118
|
+
"URLEncodedHMAC"=>"KgeVCA0YJTbuN%2F7Ibakrk%2FKnHWA%3D",
|
119
|
+
"PurchaseURL"=>
|
120
|
+
"https://www.amazon.com/gp/cart/aws-merge.html?cart-id=176-9182855-2326919%26associate-id=ws%26hmac=KgeVCA0YJTbuN/7Ibakrk/KnHWA=%26SubscriptionId=AKIAJFA5X7RTOKFNPVZQ%26MergeCart=False",
|
121
|
+
"SubTotal"=>
|
122
|
+
{"Amount"=>"2639", "CurrencyCode"=>"USD", "FormattedPrice"=>"$26.39"},
|
123
|
+
"CartItems"=>
|
124
|
+
{"SubTotal"=>
|
125
|
+
{"Amount"=>"2639", "CurrencyCode"=>"USD", "FormattedPrice"=>"$26.39"},
|
126
|
+
"CartItem"=>
|
127
|
+
{"CartItemId"=>"U3G241HVLLB8N6",
|
128
|
+
"ASIN"=>"1430218150",
|
129
|
+
"MerchantId"=>"ATVPDKIKX0DER",
|
130
|
+
"SellerId"=>"A2R2RITDJNW1Q6",
|
131
|
+
"SellerNickname"=>"Amazon.com",
|
132
|
+
"Quantity"=>"1",
|
133
|
+
"Title"=>"Learn Objective-C on the Mac (Learn Series)",
|
134
|
+
"ProductGroup"=>"Book",
|
135
|
+
"Price"=>
|
136
|
+
{"Amount"=>"2639", "CurrencyCode"=>"USD", "FormattedPrice"=>"$26.39"},
|
137
|
+
"ItemTotal"=>
|
138
|
+
{"Amount"=>"2639", "CurrencyCode"=>"USD", "FormattedPrice"=>"$26.39"}}}}
|
139
|
+
end
|
140
|
+
|
141
|
+
it "should handle response data" do
|
142
|
+
cart = Cart.new(@two_items)
|
143
|
+
cart.valid?.should be(true)
|
144
|
+
cart.cart_id.should eql('186-8702292-9782208')
|
145
|
+
cart.hmac.should eql('Ck5MXUE+OQiC/Jh8u6NhBf5FbV8=')
|
146
|
+
cart.url.should eql('https://www.amazon.com/gp/cart/aws-merge.html?cart-id=186-8702292-9782208%26associate-id=ws%26hmac=Ck5MXUE%2BOQiC/Jh8u6NhBf5FbV8=%26SubscriptionId=AKIAJFA5X7RTOKFNPVZQ%26MergeCart=False')
|
147
|
+
cart.price.should eql('$65.95')
|
148
|
+
cart.items.first.CartItemId eql('U3G241HVLLB8N6')
|
149
|
+
end
|
150
|
+
|
151
|
+
it "should handle one item" do
|
152
|
+
cart = Cart.new(@two_items)
|
153
|
+
cart.items.first.CartItemId eql('U3G241HVLLB8N6')
|
154
|
+
end
|
155
|
+
|
156
|
+
end
|
157
|
+
end
|
158
|
+
end
|
159
|
+
end
|
data/spec/search_spec.rb
ADDED
@@ -0,0 +1,95 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module ASIN
|
4
|
+
describe ASIN do
|
5
|
+
before do
|
6
|
+
ASIN::Configuration.reset
|
7
|
+
@helper = ASIN.client
|
8
|
+
@helper.configure :logger => nil
|
9
|
+
|
10
|
+
@secret = ENV['ASIN_SECRET']
|
11
|
+
@key = ENV['ASIN_KEY']
|
12
|
+
puts "configure #{@secret} and #{@key} for this test"
|
13
|
+
end
|
14
|
+
|
15
|
+
context "configuration" do
|
16
|
+
it "should fail without secret and key" do
|
17
|
+
lambda { @helper.lookup 'bla' }.should raise_error(RuntimeError)
|
18
|
+
end
|
19
|
+
|
20
|
+
it "should fail with wrong configuration key" do
|
21
|
+
lambda { @helper.configure :wrong => 'key' }.should raise_error(NoMethodError)
|
22
|
+
end
|
23
|
+
|
24
|
+
it "should not override the configuration" do
|
25
|
+
config = @helper.configure :key => 'wont get overridden'
|
26
|
+
config.key.should_not be_nil
|
27
|
+
|
28
|
+
config = @helper.configure :secret => 'is also set'
|
29
|
+
config.key.should_not be_nil
|
30
|
+
config.secret.should_not be_nil
|
31
|
+
end
|
32
|
+
|
33
|
+
it "should work with a configuration block" do
|
34
|
+
conf = ASIN::Configuration.configure do |config|
|
35
|
+
config.key = 'bla'
|
36
|
+
end
|
37
|
+
conf.key.should eql('bla')
|
38
|
+
end
|
39
|
+
|
40
|
+
it "should read configuration from yml" do
|
41
|
+
config = ASIN::Configuration.configure :yaml => 'spec/asin.yml'
|
42
|
+
config.secret.should eql('secret_yml')
|
43
|
+
config.key.should eql('key_yml')
|
44
|
+
config.host.should eql('host_yml')
|
45
|
+
config.logger.should eql('logger_yml')
|
46
|
+
end
|
47
|
+
|
48
|
+
it "should read configuration from yml with block" do
|
49
|
+
conf = ASIN::Configuration.configure :yaml => 'spec/asin.yml' do |config, yml|
|
50
|
+
config.secret = nil
|
51
|
+
config.key = yml['secret']
|
52
|
+
end
|
53
|
+
conf.secret.should be_nil
|
54
|
+
conf.key.should eql('secret_yml')
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
context "lookup and search" do
|
59
|
+
before do
|
60
|
+
@helper.configure :secret => @secret, :key => @key
|
61
|
+
end
|
62
|
+
|
63
|
+
it "should lookup a book" do
|
64
|
+
item = @helper.lookup(ANY_ASIN)
|
65
|
+
item.title.should =~ /Learn Objective/
|
66
|
+
end
|
67
|
+
|
68
|
+
it "should search_keywords a book with fulltext" do
|
69
|
+
items = @helper.search_keywords 'Learn', 'Objective-C'
|
70
|
+
items.should have(10).things
|
71
|
+
|
72
|
+
items.first.title.should =~ /Learn Objective/
|
73
|
+
end
|
74
|
+
|
75
|
+
it "should search_keywords never mind music" do
|
76
|
+
items = @helper.search_keywords 'nirvana', 'never mind', :SearchIndex => :Music
|
77
|
+
items.should have(9).things
|
78
|
+
|
79
|
+
items.first.title.should =~ /Nevermind/
|
80
|
+
end
|
81
|
+
|
82
|
+
it "should search music" do
|
83
|
+
items = @helper.search :SearchIndex => :Music
|
84
|
+
items.should have(0).things
|
85
|
+
end
|
86
|
+
|
87
|
+
it "should search never mind music" do
|
88
|
+
items = @helper.search :Keywords => 'nirvana', :SearchIndex => :Music
|
89
|
+
items.should have(10).things
|
90
|
+
|
91
|
+
items.first.title.should =~ /Nevermind/
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
data/spec/spec_helper.rb
CHANGED
metadata
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: asin
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
prerelease:
|
5
|
-
version: 0.
|
4
|
+
prerelease: 6
|
5
|
+
version: 0.4.0.beta1
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
8
|
- "Peter Schr\xC3\xB6der"
|
@@ -10,7 +10,7 @@ autorequire:
|
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
12
|
|
13
|
-
date: 2011-
|
13
|
+
date: 2011-04-12 00:00:00 +02:00
|
14
14
|
default_executable:
|
15
15
|
dependencies:
|
16
16
|
- !ruby/object:Gem::Dependency
|
@@ -43,7 +43,7 @@ dependencies:
|
|
43
43
|
requirements:
|
44
44
|
- - ~>
|
45
45
|
- !ruby/object:Gem::Version
|
46
|
-
version: 0.
|
46
|
+
version: 0.9.2
|
47
47
|
type: :runtime
|
48
48
|
version_requirements: *id003
|
49
49
|
- !ruby/object:Gem::Dependency
|
@@ -54,7 +54,7 @@ dependencies:
|
|
54
54
|
requirements:
|
55
55
|
- - ~>
|
56
56
|
- !ruby/object:Gem::Version
|
57
|
-
version: 2.1.
|
57
|
+
version: 2.1.7.2
|
58
58
|
type: :development
|
59
59
|
version_requirements: *id004
|
60
60
|
- !ruby/object:Gem::Dependency
|
@@ -65,7 +65,7 @@ dependencies:
|
|
65
65
|
requirements:
|
66
66
|
- - ~>
|
67
67
|
- !ruby/object:Gem::Version
|
68
|
-
version: 2.
|
68
|
+
version: 2.5.0
|
69
69
|
type: :development
|
70
70
|
version_requirements: *id005
|
71
71
|
- !ruby/object:Gem::Dependency
|
@@ -79,7 +79,7 @@ dependencies:
|
|
79
79
|
version: 0.0.3
|
80
80
|
type: :development
|
81
81
|
version_requirements: *id006
|
82
|
-
description: Amazon Simple INterface
|
82
|
+
description: Amazon Simple INterface.
|
83
83
|
email:
|
84
84
|
- phoetmail@googlemail.com
|
85
85
|
executables: []
|
@@ -92,17 +92,19 @@ files:
|
|
92
92
|
- .document
|
93
93
|
- .gitignore
|
94
94
|
- .rvmrc
|
95
|
-
- .travis.yml
|
96
95
|
- Gemfile
|
97
96
|
- Gemfile.lock
|
98
97
|
- README.rdoc
|
99
98
|
- asin.gemspec
|
100
99
|
- lib/asin.rb
|
100
|
+
- lib/asin/cart.rb
|
101
101
|
- lib/asin/configuration.rb
|
102
102
|
- lib/asin/item.rb
|
103
103
|
- lib/asin/version.rb
|
104
104
|
- rakefile.rb
|
105
|
-
- spec/
|
105
|
+
- spec/asin.yml
|
106
|
+
- spec/cart_spec.rb
|
107
|
+
- spec/search_spec.rb
|
106
108
|
- spec/spec_helper.rb
|
107
109
|
has_rdoc: true
|
108
110
|
homepage: http://github.com/phoet/asin
|
@@ -122,16 +124,18 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
122
124
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
123
125
|
none: false
|
124
126
|
requirements:
|
125
|
-
- - "
|
127
|
+
- - ">"
|
126
128
|
- !ruby/object:Gem::Version
|
127
|
-
version:
|
129
|
+
version: 1.3.1
|
128
130
|
requirements: []
|
129
131
|
|
130
132
|
rubyforge_project: asin
|
131
133
|
rubygems_version: 1.5.2
|
132
134
|
signing_key:
|
133
135
|
specification_version: 3
|
134
|
-
summary: Simple interface to
|
136
|
+
summary: Simple interface to AWS Lookup, Search and Cart operations.
|
135
137
|
test_files:
|
136
|
-
- spec/
|
138
|
+
- spec/asin.yml
|
139
|
+
- spec/cart_spec.rb
|
140
|
+
- spec/search_spec.rb
|
137
141
|
- spec/spec_helper.rb
|
data/.travis.yml
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
script: "rake travis_ci"
|
data/spec/asin_spec.rb
DELETED
@@ -1,74 +0,0 @@
|
|
1
|
-
describe ASIN do
|
2
|
-
before do
|
3
|
-
@helper = ASIN.client
|
4
|
-
@helper.configure :logger => nil
|
5
|
-
|
6
|
-
@secret = ENV['ASIN_SECRET']
|
7
|
-
@key = ENV['ASIN_KEY']
|
8
|
-
puts "configure #{@secret} and #{@key} for this test"
|
9
|
-
end
|
10
|
-
|
11
|
-
context "configuration" do
|
12
|
-
it "should fail without secret and key" do
|
13
|
-
lambda { @helper.lookup 'bla' }.should raise_error(RuntimeError)
|
14
|
-
end
|
15
|
-
|
16
|
-
it "should fail with wrong configuration key" do
|
17
|
-
lambda { @helper.configure :wrong => 'key' }.should raise_error(NoMethodError)
|
18
|
-
end
|
19
|
-
|
20
|
-
it "should not override the configuration" do
|
21
|
-
config = @helper.configure :key => 'wont get overridden'
|
22
|
-
config.key.should_not be_nil
|
23
|
-
|
24
|
-
config = @helper.configure :secret => 'is also set'
|
25
|
-
config.key.should_not be_nil
|
26
|
-
config.secret.should_not be_nil
|
27
|
-
end
|
28
|
-
|
29
|
-
it "should work with a configuration block" do
|
30
|
-
config = ASIN::Configuration.configure do |config|
|
31
|
-
config.key = 'bla'
|
32
|
-
end
|
33
|
-
config.key.should eql('bla')
|
34
|
-
end
|
35
|
-
end
|
36
|
-
|
37
|
-
context "lookup and search" do
|
38
|
-
before do
|
39
|
-
@helper.configure :secret => @secret, :key => @key
|
40
|
-
end
|
41
|
-
|
42
|
-
it "should lookup a book" do
|
43
|
-
item = @helper.lookup('1430218150')
|
44
|
-
item.title.should =~ /Learn Objective/
|
45
|
-
end
|
46
|
-
|
47
|
-
it "should search_keywords a book with fulltext" do
|
48
|
-
items = @helper.search_keywords 'Learn', 'Objective-C'
|
49
|
-
items.should have(10).things
|
50
|
-
|
51
|
-
items.first.title.should =~ /Learn Objective/
|
52
|
-
end
|
53
|
-
|
54
|
-
it "should search_keywords never mind music" do
|
55
|
-
items = @helper.search_keywords 'nirvana', 'never mind', :SearchIndex => :Music
|
56
|
-
items.should have(10).things
|
57
|
-
|
58
|
-
items.first.title.should =~ /Nevermind/
|
59
|
-
end
|
60
|
-
|
61
|
-
it "should search music" do
|
62
|
-
items = @helper.search :SearchIndex => :Music
|
63
|
-
items.should have(0).things
|
64
|
-
end
|
65
|
-
|
66
|
-
it "should search never mind music" do
|
67
|
-
items = @helper.search :Keywords => 'nirvana', :SearchIndex => :Music
|
68
|
-
items.should have(10).things
|
69
|
-
|
70
|
-
items.first.title.should =~ /Nevermind/
|
71
|
-
end
|
72
|
-
end
|
73
|
-
end
|
74
|
-
|