vacuum 1.1.1 → 1.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +140 -43
- data/lib/vacuum/request.rb +4 -4
- data/lib/vacuum/response.rb +15 -0
- data/lib/vacuum/version.rb +1 -1
- data/test/test_integration.rb +1 -0
- data/test/test_vacuum.rb +37 -9
- metadata +3 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 99bd9a237d04b447017964b0b8f672d95f2d06ba
|
4
|
+
data.tar.gz: 7cca17378340136b4af9d4038b26822b7e07e3e3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d6162aca52ed85ae0ee728d0fcd7cb21269e316478fe685e401c1181793e039bf85cf72dc5099772f43deaf51965623ceb3e2fae1e31e56f9aaa0c83ff562b47
|
7
|
+
data.tar.gz: 9cab62d3c97f2a6f0d604d0d32d454ac4d58fea793b3977bdf8352746273bb20a55cb66adebe69c2575c76dc0caaa7d9c7d951f09c07fcd431b3c932c2aa9222
|
data/README.md
CHANGED
@@ -1,96 +1,193 @@
|
|
1
1
|
# Vacuum
|
2
|
+
[![Travis](https://travis-ci.org/hakanensari/vacuum.svg)](https://travis-ci.org/hakanensari/vacuum)
|
2
3
|
|
3
|
-
[
|
4
|
+
Vacuum is a fast, light-weight Ruby wrapper to the [Amazon Product Advertising API](https://affiliate-program.amazon.com/gp/advertising/api/detail/main.html).
|
4
5
|
|
5
|
-
|
6
|
-
|
7
|
-
![vacuum][3]
|
6
|
+
![vacuum](http://f.cl.ly/items/2k2X0e2u0G3k1c260D2u/vacuum.png)
|
8
7
|
|
9
8
|
## Usage
|
10
9
|
|
11
10
|
### Setup
|
12
11
|
|
13
|
-
|
12
|
+
Create a request:
|
14
13
|
|
15
14
|
```ruby
|
16
|
-
|
15
|
+
request = Vacuum.new
|
17
16
|
```
|
18
17
|
|
19
|
-
The locale
|
20
|
-
two-letter country code:
|
18
|
+
The locale will default to the US. To use another locale, reference its two-letter country code:
|
21
19
|
|
22
20
|
```ruby
|
23
|
-
|
21
|
+
request = Vacuum.new('GB')
|
24
22
|
```
|
25
23
|
|
26
24
|
Configure the request credentials:
|
27
25
|
|
28
26
|
```ruby
|
29
|
-
|
30
|
-
aws_access_key_id:
|
27
|
+
request.configure(
|
28
|
+
aws_access_key_id: 'key',
|
31
29
|
aws_secret_access_key: 'secret',
|
32
|
-
associate_tag:
|
30
|
+
associate_tag: 'tag'
|
33
31
|
)
|
34
32
|
```
|
35
33
|
|
36
|
-
|
34
|
+
You can omit the above if you set your key and secret as environment variables:
|
37
35
|
|
38
36
|
```sh
|
39
37
|
export AWS_ACCESS_KEY_ID=key
|
40
38
|
export AWS_SECRET_ACCESS_KEY=secret
|
41
39
|
```
|
42
40
|
|
43
|
-
You will still need to set
|
41
|
+
You will still need to set an associate tag:
|
44
42
|
|
45
43
|
```ruby
|
46
|
-
|
44
|
+
request.associate_tag = 'tag'
|
47
45
|
```
|
48
46
|
|
47
|
+
Provided you are looking to earn commission, you have to register independently with each locale you query. Otherwise, you may reuse any dummy associate tag.
|
48
|
+
|
49
49
|
### Request
|
50
50
|
|
51
|
-
|
51
|
+
#### Browse Node Lookup
|
52
|
+
|
53
|
+
**BrowseNodeLookup** returns a specified browse node’s name and ancestors:
|
52
54
|
|
53
55
|
```ruby
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
}
|
58
|
-
|
56
|
+
response = request.browse_node_lookup(
|
57
|
+
query: {
|
58
|
+
'BrowseNodeId' => 123
|
59
|
+
}
|
60
|
+
)
|
59
61
|
```
|
60
|
-
The above executes an item search operation. The names of available methods
|
61
|
-
derive from the operations listed in the API docs and include
|
62
|
-
`browse_node_lookup`, `cart_add`, `cart_clear`, `cart_create`, `cart_get`,
|
63
|
-
`cart_modify`, `item_lookup`, `item_search`, and `similarity_lookup`.
|
64
62
|
|
65
|
-
|
66
|
-
|
63
|
+
#### Cart Operations
|
64
|
+
|
65
|
+
The **CartCreate** operation creates a remote shopping cart:
|
67
66
|
|
68
67
|
```ruby
|
69
|
-
|
68
|
+
response = request.cart_create(
|
69
|
+
query: {
|
70
|
+
'HMAC' => 'secret',
|
71
|
+
'Item.1.OfferListingId' => '123',
|
72
|
+
'Item.1.Quantity' => 1
|
73
|
+
}
|
74
|
+
)
|
70
75
|
```
|
71
76
|
|
72
|
-
|
77
|
+
The **CartAdd** operation adds items to an existing remote shopping cart:
|
78
|
+
|
79
|
+
```ruby
|
80
|
+
response = request.cart_add(
|
81
|
+
query: {
|
82
|
+
'CartId' => '123',
|
83
|
+
'HMAC' => 'secret',
|
84
|
+
'Item.1.OfferListingId' => '123',
|
85
|
+
'Item.1.Quantity' => 1
|
86
|
+
}
|
87
|
+
)
|
88
|
+
```
|
89
|
+
|
90
|
+
The **CartClear** operation removes all of the items in a remote shopping cart:
|
91
|
+
|
92
|
+
```ruby
|
93
|
+
response = request.cart_clear(
|
94
|
+
query: {
|
95
|
+
'CartId' => '123',
|
96
|
+
'HMAC' => 'secret'
|
97
|
+
}
|
98
|
+
)
|
99
|
+
```
|
100
|
+
|
101
|
+
The **CartGet** operation retrieves the IDs, quantities, and prices of the items, including SavedForLater ones, in a remote shopping cart:
|
102
|
+
|
103
|
+
```ruby
|
104
|
+
response = request.cart_get(
|
105
|
+
query: {
|
106
|
+
'CartId' => '123',
|
107
|
+
'HMAC' => 'secret',
|
108
|
+
'CartItemId' => '123'
|
109
|
+
}
|
110
|
+
)
|
111
|
+
```
|
112
|
+
|
113
|
+
#### Item Lookup
|
114
|
+
|
115
|
+
The **ItemLookup** operation returns some or all of the attributes of an item, depending on the response group specified in the request. By default, the operation returns an item’s ASIN, manufacturer, product group, and title.
|
116
|
+
|
117
|
+
```ruby
|
118
|
+
response = request.item_lookup(
|
119
|
+
query: {
|
120
|
+
'ItemId' => '0679753354'
|
121
|
+
}
|
122
|
+
)
|
123
|
+
```
|
73
124
|
|
74
|
-
|
125
|
+
#### Item Search
|
126
|
+
|
127
|
+
The **ItemSearch** operation returns items that satisfy the search criteria, including one or more search indices.
|
75
128
|
|
76
129
|
```ruby
|
77
|
-
|
130
|
+
response = request.item_search(
|
131
|
+
query: {
|
132
|
+
'Keywords' => 'Architecture',
|
133
|
+
'SearchIndex' => 'Books'
|
134
|
+
}
|
135
|
+
)
|
78
136
|
```
|
79
137
|
|
80
|
-
|
81
|
-
libraries. If working in MRI, you may want to use [Ox][7].
|
138
|
+
#### Similarity Lookup
|
82
139
|
|
83
|
-
|
84
|
-
heavy-lifting:
|
140
|
+
The **SimilarityLookup** operation returns up to ten products per page that are similar to one or more items specified in the request. This operation is typically used to pique a customer’s interest in buying something similar to what they’ve already ordered.
|
85
141
|
|
86
142
|
```ruby
|
87
|
-
|
143
|
+
response = request.similarity_lookup(
|
144
|
+
query: {
|
145
|
+
'ItemId' => '0679753354'
|
146
|
+
}
|
147
|
+
)
|
148
|
+
```
|
149
|
+
|
150
|
+
#### Configuring a request
|
151
|
+
|
152
|
+
Vacuum wraps [Excon](https://github.com/geemus/excon). Use the latter's API to tweak your request.
|
153
|
+
|
154
|
+
For example, to use a persistent connection:
|
155
|
+
|
156
|
+
```ruby
|
157
|
+
response = request.item_search(
|
158
|
+
query: {
|
159
|
+
'ItemId' => '0679753354'
|
160
|
+
},
|
161
|
+
persistent: true
|
162
|
+
)
|
163
|
+
```
|
164
|
+
|
165
|
+
### Response
|
166
|
+
|
167
|
+
The quick and dirty way to consume a response is to parse it into a Ruby hash:
|
168
|
+
|
169
|
+
```ruby
|
170
|
+
response.to_h
|
171
|
+
```
|
172
|
+
|
173
|
+
In production, you may prefer to use a custom parser to do some XML heavy-lifting:
|
174
|
+
|
175
|
+
```ruby
|
176
|
+
class MyParser
|
177
|
+
# A parser has to respond to this.
|
178
|
+
def self.parse(body)
|
179
|
+
new(body)
|
180
|
+
end
|
181
|
+
|
182
|
+
def initialize(body)
|
183
|
+
@body = body
|
184
|
+
end
|
185
|
+
|
186
|
+
# Implement parser here.
|
187
|
+
end
|
188
|
+
|
189
|
+
response.parser = MyParser
|
190
|
+
response.parse
|
88
191
|
```
|
89
192
|
|
90
|
-
|
91
|
-
[2]: http://travis-ci.org/hakanensari/vacuum
|
92
|
-
[3]: http://f.cl.ly/items/2k2X0e2u0G3k1c260D2u/vacuum.png
|
93
|
-
[4]: https://affiliate-program.amazon.com/gp/advertising/api/detail/main.html
|
94
|
-
[5]: https://github.com/geemus/excon
|
95
|
-
[6]: https://github.com/sferik/multi_xml
|
96
|
-
[7]: https://github.com/ohler55/ox
|
193
|
+
If no custom parser is set, `Vacuum::Response#parse` delegates to `#to_h`.
|
data/lib/vacuum/request.rb
CHANGED
@@ -48,7 +48,7 @@ module Vacuum
|
|
48
48
|
#
|
49
49
|
# Raises a Bad Locale error if locale is not valid.
|
50
50
|
def initialize(locale = 'US', secure = false)
|
51
|
-
host = HOSTS.fetch(locale) {
|
51
|
+
host = HOSTS.fetch(locale) { fail BadLocale }
|
52
52
|
@aws_endpoint = "#{secure ? 'https' : 'http' }://#{host}/onca/xml"
|
53
53
|
end
|
54
54
|
|
@@ -62,7 +62,7 @@ module Vacuum
|
|
62
62
|
#
|
63
63
|
# Returns self.
|
64
64
|
def configure(credentials)
|
65
|
-
credentials.each { |key, val|
|
65
|
+
credentials.each { |key, val| send("#{key}=", val) }
|
66
66
|
self
|
67
67
|
end
|
68
68
|
|
@@ -92,9 +92,9 @@ module Vacuum
|
|
92
92
|
#
|
93
93
|
# Returns a Vacuum Response.
|
94
94
|
OPERATIONS.each do |operation|
|
95
|
-
method_name = operation.gsub(/(.)([A-Z])/,'\1_\2').downcase
|
95
|
+
method_name = operation.gsub(/(.)([A-Z])/, '\1_\2').downcase
|
96
96
|
define_method(method_name) do |params, opts = {}|
|
97
|
-
params.
|
97
|
+
params.key?(:query) ? opts = params : opts.update(query: params)
|
98
98
|
opts[:query].update('Operation' => operation)
|
99
99
|
|
100
100
|
Response.new(get(opts))
|
data/lib/vacuum/response.rb
CHANGED
@@ -2,7 +2,22 @@ require 'delegate'
|
|
2
2
|
require 'multi_xml'
|
3
3
|
|
4
4
|
module Vacuum
|
5
|
+
# A wrapper around the Amazon Product Advertising API response.
|
5
6
|
class Response < SimpleDelegator
|
7
|
+
class << self
|
8
|
+
attr_accessor :parser
|
9
|
+
end
|
10
|
+
|
11
|
+
def parser
|
12
|
+
@parser || self.class.parser
|
13
|
+
end
|
14
|
+
|
15
|
+
attr_writer :parser
|
16
|
+
|
17
|
+
def parse
|
18
|
+
parser ? parser.parse(body) : to_h
|
19
|
+
end
|
20
|
+
|
6
21
|
def to_h
|
7
22
|
MultiXml.parse(body)
|
8
23
|
end
|
data/lib/vacuum/version.rb
CHANGED
data/test/test_integration.rb
CHANGED
data/test/test_vacuum.rb
CHANGED
@@ -22,23 +22,51 @@ class TestVacuum < Minitest::Test
|
|
22
22
|
end
|
23
23
|
|
24
24
|
def test_fetches_parsable_response
|
25
|
-
Excon.stub({},
|
26
|
-
@req.configure(aws_access_key_id: 'key', aws_secret_access_key: 'secret', associate_tag: 'tag')
|
25
|
+
Excon.stub({}, body: '<foo/>')
|
27
26
|
res = @req.item_lookup({}, mock: true)
|
28
|
-
refute_empty res.
|
27
|
+
refute_empty res.parse
|
29
28
|
end
|
30
29
|
|
31
30
|
def test_alternative_query_syntax
|
32
|
-
Excon.stub({},
|
33
|
-
|
34
|
-
|
35
|
-
res = req.item_lookup(query: {}, mock: true)
|
36
|
-
refute_empty res.to_h
|
31
|
+
Excon.stub({}, body: '<foo/>')
|
32
|
+
res = @req.item_lookup(query: {}, mock: true)
|
33
|
+
refute_empty res.parse
|
37
34
|
end
|
38
35
|
|
39
36
|
def test_force_encodes_body
|
40
37
|
res = Object.new
|
41
|
-
def res.body
|
38
|
+
def res.body
|
39
|
+
''.force_encoding('ASCII-8BIT')
|
40
|
+
end
|
42
41
|
assert_equal 'UTF-8', Response.new(res).body.encoding.name
|
43
42
|
end
|
43
|
+
|
44
|
+
def test_sets_custom_parser_on_class_level
|
45
|
+
original_parser = Response.parser
|
46
|
+
Excon.stub({}, body: '<foo/>')
|
47
|
+
parser = MiniTest::Mock.new
|
48
|
+
parser.expect(:parse, '123', ['<foo/>'])
|
49
|
+
Response.parser = parser
|
50
|
+
res = @req.item_lookup(query: {}, mock: true)
|
51
|
+
assert_equal '123', res.parse
|
52
|
+
Response.parser = original_parser # clean up
|
53
|
+
end
|
54
|
+
|
55
|
+
def test_sets_custom_parser_on_instance_level
|
56
|
+
Excon.stub({}, body: '<foo/>')
|
57
|
+
res = @req.item_lookup(query: {}, mock: true)
|
58
|
+
parser = MiniTest::Mock.new
|
59
|
+
parser.expect(:parse, '123', ['<foo/>'])
|
60
|
+
res.parser = parser
|
61
|
+
assert_equal '123', res.parse
|
62
|
+
end
|
63
|
+
|
64
|
+
def test_casts_to_hash
|
65
|
+
Excon.stub({}, body: '<foo/>')
|
66
|
+
parser = MiniTest::Mock.new
|
67
|
+
res = @req.item_lookup(query: {}, mock: true)
|
68
|
+
assert_kind_of Hash, res.to_h
|
69
|
+
res.parser = parser
|
70
|
+
assert_kind_of Hash, res.to_h
|
71
|
+
end
|
44
72
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: vacuum
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Hakan Ensari
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-
|
11
|
+
date: 2014-12-12 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: jeff
|
@@ -96,7 +96,7 @@ dependencies:
|
|
96
96
|
version: '0'
|
97
97
|
description: A wrapper to the Amazon Product Advertising API
|
98
98
|
email:
|
99
|
-
-
|
99
|
+
- me@hakanensari.com
|
100
100
|
executables: []
|
101
101
|
extensions: []
|
102
102
|
extra_rdoc_files: []
|