sucker 0.1.2 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README.md +39 -0
- data/lib/sucker/request.rb +6 -8
- data/lib/sucker.rb +1 -3
- data/spec/integration/item_lookup_spec.rb +7 -9
- data/spec/integration/seller_listing_search_spec.rb +4 -5
- data/spec/spec_helper.rb +0 -2
- data/spec/unit/sucker/request_spec.rb +62 -57
- metadata +6 -40
- data/README.textile +0 -45
data/README.md
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
Sucker
|
2
|
+
======
|
3
|
+
|
4
|
+

|
5
|
+
|
6
|
+
Sucker is a light-weight Ruby wrapper to the Amazon Product Advertising API. It runs on Curb and Crack.
|
7
|
+
|
8
|
+
Examples
|
9
|
+
--------
|
10
|
+
|
11
|
+
Set up a worker.
|
12
|
+
|
13
|
+
@worker = Sucker.new(
|
14
|
+
:locale => "us",
|
15
|
+
:key => "API KEY",
|
16
|
+
:secret => "API SECRET")
|
17
|
+
|
18
|
+
Fiddle with curl.
|
19
|
+
|
20
|
+
@worker.curl { |c| c.interface = "eth1" }
|
21
|
+
|
22
|
+
Set up a request.
|
23
|
+
|
24
|
+
@worker << {
|
25
|
+
"Operation" => "ItemLookup",
|
26
|
+
"IdType" => "ASIN",
|
27
|
+
"ItemId" => ["0816614024", "0143105825"] }
|
28
|
+
|
29
|
+
Hit Amazon and do something with the response.
|
30
|
+
|
31
|
+
pp @worker.get["ItemLookupResponse"]["Items"]["Item"]
|
32
|
+
|
33
|
+
Hit Amazon again.
|
34
|
+
|
35
|
+
@worker << {
|
36
|
+
"ItemId" => ["0393329259", "0393317757"] }
|
37
|
+
@worker.get
|
38
|
+
|
39
|
+
Check the integration specs for some more examples.
|
data/lib/sucker/request.rb
CHANGED
@@ -43,12 +43,15 @@ module Sucker
|
|
43
43
|
@curl
|
44
44
|
end
|
45
45
|
|
46
|
-
#
|
47
|
-
|
48
|
-
|
46
|
+
# Makes a request to Amazon and returns the response as a hash
|
47
|
+
# Todo: Handle errors
|
48
|
+
def get
|
49
|
+
raise ArgumentError, 'Set key, secret, and valid locale' if !valid?
|
49
50
|
|
50
51
|
curl.url = uri.to_s
|
51
52
|
curl.perform
|
53
|
+
|
54
|
+
Crack::XML.parse(curl.body_str)
|
52
55
|
end
|
53
56
|
|
54
57
|
# A helper method that sets the AWS Access Key ID
|
@@ -56,11 +59,6 @@ module Sucker
|
|
56
59
|
parameters["AWSAccessKeyId"] = key
|
57
60
|
end
|
58
61
|
|
59
|
-
# Returns a hash of the response
|
60
|
-
def to_h
|
61
|
-
Crack::XML.parse(curl.body_str)
|
62
|
-
end
|
63
|
-
|
64
62
|
private
|
65
63
|
|
66
64
|
# Escapes parameters and concatenates them into a query string
|
data/lib/sucker.rb
CHANGED
@@ -4,11 +4,9 @@ require "curb"
|
|
4
4
|
require "sucker/request"
|
5
5
|
|
6
6
|
module Sucker
|
7
|
-
VERSION = "0.
|
7
|
+
VERSION = "0.2.0".freeze
|
8
8
|
AMAZON_API_VERSION = "2009-11-01".freeze
|
9
9
|
|
10
|
-
class SuckerError < StandardError; end
|
11
|
-
|
12
10
|
def self.new(args={})
|
13
11
|
Sucker::Request.new(args)
|
14
12
|
end
|
@@ -3,23 +3,22 @@ require "spec_helper"
|
|
3
3
|
module Sucker
|
4
4
|
describe "Item Lookup" do
|
5
5
|
before do
|
6
|
-
@
|
6
|
+
@worker = Sucker.new(
|
7
7
|
:locale => "us",
|
8
8
|
:key => amazon["key"],
|
9
9
|
:secret => amazon["secret"])
|
10
10
|
|
11
|
-
# @
|
11
|
+
# @worker.curl { |curl| curl.verbose = true }
|
12
12
|
|
13
|
-
@
|
13
|
+
@worker << {
|
14
14
|
"Operation" => "ItemLookup",
|
15
15
|
"IdType" => "ASIN" }
|
16
16
|
end
|
17
17
|
|
18
18
|
context "single item" do
|
19
19
|
before do
|
20
|
-
@
|
21
|
-
@
|
22
|
-
@item = @sucker.to_h["ItemLookupResponse"]["Items"]["Item"]
|
20
|
+
@worker << { "ItemId" => "0816614024" }
|
21
|
+
@item = @worker.get["ItemLookupResponse"]["Items"]["Item"]
|
23
22
|
end
|
24
23
|
|
25
24
|
it "returns an item" do
|
@@ -37,9 +36,8 @@ module Sucker
|
|
37
36
|
|
38
37
|
context "multiple items" do
|
39
38
|
before do
|
40
|
-
@
|
41
|
-
@
|
42
|
-
@items = @sucker.to_h["ItemLookupResponse"]["Items"]["Item"]
|
39
|
+
@worker << { "ItemId" => ["0816614024", "0143105825"] }
|
40
|
+
@items = @worker.get["ItemLookupResponse"]["Items"]["Item"]
|
43
41
|
end
|
44
42
|
|
45
43
|
it "returns two items" do
|
@@ -3,18 +3,17 @@ require "spec_helper"
|
|
3
3
|
module Sucker
|
4
4
|
describe "Seller Listing Search" do
|
5
5
|
before do
|
6
|
-
@
|
6
|
+
@worker = Sucker.new(
|
7
7
|
:locale => "us",
|
8
8
|
:key => amazon["key"],
|
9
9
|
:secret => amazon["secret"])
|
10
10
|
|
11
|
-
# @
|
11
|
+
# @worker.curl { |curl| curl.verbose = true }
|
12
12
|
|
13
|
-
@
|
13
|
+
@worker << {
|
14
14
|
"Operation" => "SellerListingSearch",
|
15
15
|
"SellerId" => "A31N271NVIORU3" }
|
16
|
-
@
|
17
|
-
@listings = @sucker.to_h["SellerListingSearchResponse"]["SellerListings"]
|
16
|
+
@listings = @worker.get["SellerListingSearchResponse"]["SellerListings"]
|
18
17
|
end
|
19
18
|
|
20
19
|
it "returns page count" do
|
data/spec/spec_helper.rb
CHANGED
@@ -3,7 +3,7 @@ require "spec_helper"
|
|
3
3
|
module Sucker
|
4
4
|
describe "Request" do
|
5
5
|
before do
|
6
|
-
@
|
6
|
+
@worker = Sucker.new
|
7
7
|
end
|
8
8
|
|
9
9
|
context "public" do
|
@@ -12,153 +12,158 @@ module Sucker
|
|
12
12
|
default_parameters = {
|
13
13
|
"Service" => "AWSECommerceService",
|
14
14
|
"Version" => Sucker::AMAZON_API_VERSION }
|
15
|
-
@
|
15
|
+
@worker.parameters.should eql default_parameters
|
16
16
|
end
|
17
17
|
end
|
18
18
|
|
19
19
|
context "#<<" do
|
20
|
-
it "merges a hash into the
|
21
|
-
@
|
22
|
-
@
|
20
|
+
it "merges a hash into the parameters" do
|
21
|
+
@worker << { "foo" => "bar" }
|
22
|
+
@worker.parameters["foo"].should eql "bar"
|
23
23
|
end
|
24
24
|
end
|
25
25
|
|
26
26
|
context "#curl" do
|
27
27
|
it "returns a cURL object" do
|
28
|
-
@
|
28
|
+
@worker.curl.should be_an_instance_of Curl::Easy
|
29
29
|
end
|
30
30
|
|
31
31
|
it "configures the cURL object" do
|
32
|
-
@
|
32
|
+
@worker.curl.interface.should be_nil
|
33
33
|
|
34
|
-
@
|
34
|
+
@worker.curl do |curl|
|
35
35
|
curl.interface = "eth1"
|
36
36
|
end
|
37
37
|
|
38
|
-
@
|
38
|
+
@worker.curl.interface.should eql "eth1"
|
39
39
|
end
|
40
40
|
end
|
41
41
|
|
42
|
-
context "#
|
43
|
-
it "returns nil if valid? returns false" do
|
44
|
-
@sucker.stub!(:valid?).and_return(false)
|
45
|
-
@sucker.fetch.should be_nil
|
46
|
-
end
|
47
|
-
end
|
48
|
-
|
49
|
-
context "#to_h" do
|
42
|
+
context "#get" do
|
50
43
|
before do
|
51
|
-
@
|
44
|
+
@worker.locale = "us"
|
45
|
+
@worker.key = "key"
|
46
|
+
@worker.secret = "secret"
|
47
|
+
|
48
|
+
# Stub curl
|
49
|
+
curl = @worker.curl
|
50
|
+
curl.stub(:get).and_return(nil)
|
51
|
+
curl.stub!(:body_str).and_return(fixture("single_item_lookup.us"))
|
52
52
|
end
|
53
53
|
|
54
|
-
it "
|
55
|
-
@
|
54
|
+
it "returns a hash" do
|
55
|
+
@worker.get.should be_an_instance_of Hash
|
56
56
|
end
|
57
|
+
|
58
|
+
it "raises an ArgumentError if valid? returns false" do
|
59
|
+
@worker.stub!(:valid?).and_return(false)
|
60
|
+
lambda{ @worker.get }.should raise_error ArgumentError
|
61
|
+
end
|
57
62
|
end
|
58
63
|
end
|
59
64
|
|
60
65
|
context "private" do
|
61
66
|
context "#build_query" do
|
62
67
|
it "canonicalizes parameters" do
|
63
|
-
query = @
|
68
|
+
query = @worker.send(:build_query)
|
64
69
|
query.should eql "Service=AWSECommerceService&Version=#{Sucker::AMAZON_API_VERSION}"
|
65
70
|
end
|
66
71
|
|
67
72
|
it "sorts parameters" do
|
68
|
-
@
|
69
|
-
query = @
|
73
|
+
@worker.parameters["Foo"] = "bar"
|
74
|
+
query = @worker.send(:build_query)
|
70
75
|
query.should match /^Foo=bar/
|
71
76
|
end
|
72
77
|
|
73
78
|
it "converts a parameter whose value is an array to a string" do
|
74
|
-
@
|
75
|
-
query = @
|
79
|
+
@worker.parameters["Foo"] = ["bar", "baz"]
|
80
|
+
query = @worker.send(:build_query)
|
76
81
|
query.should match /^Foo=bar%2Cbaz/
|
77
82
|
end
|
78
83
|
end
|
79
84
|
|
80
85
|
context "#digest" do
|
81
86
|
it "returns a digest object" do
|
82
|
-
@
|
87
|
+
@worker.send(:digest).should be_an_instance_of OpenSSL::Digest::Digest
|
83
88
|
end
|
84
89
|
end
|
85
90
|
|
86
91
|
context "#key=" do
|
87
92
|
it "sets the Amazon AWS access key in the parameters" do
|
88
|
-
@
|
89
|
-
@
|
93
|
+
@worker.key = "key"
|
94
|
+
@worker.parameters["AWSAccessKeyId"].should eql "key"
|
90
95
|
end
|
91
96
|
end
|
92
97
|
|
93
98
|
context "#host" do
|
94
99
|
it "returns a host" do
|
95
|
-
@
|
96
|
-
@
|
100
|
+
@worker.locale = "us"
|
101
|
+
@worker.send(:host).should eql "ecs.amazonaws.com"
|
97
102
|
end
|
98
103
|
end
|
99
104
|
|
100
105
|
context "#path" do
|
101
106
|
it "returns a path" do
|
102
|
-
@
|
107
|
+
@worker.send(:path).should eql "/onca/xml"
|
103
108
|
end
|
104
109
|
end
|
105
110
|
|
106
111
|
context "#sign_query" do
|
107
112
|
it "returns a signed query string" do
|
108
|
-
@
|
109
|
-
@
|
110
|
-
query = @
|
113
|
+
@worker.secret = "secret"
|
114
|
+
@worker.locale = "us"
|
115
|
+
query = @worker.send :sign_query
|
111
116
|
query.should match /&Signature=.*/
|
112
117
|
end
|
113
118
|
end
|
114
119
|
|
115
120
|
context "#timestamp_parameters" do
|
116
121
|
it "upserts a timestamp to the parameters" do
|
117
|
-
@
|
118
|
-
@
|
122
|
+
@worker.send :timestamp_parameters
|
123
|
+
@worker.parameters["Timestamp"].should match /^\d+-\d+-\d+T\d+:\d+:\d+Z$/
|
119
124
|
end
|
120
125
|
end
|
121
126
|
|
122
127
|
context "#uri" do
|
123
128
|
it "returns the URI with which to query Amazon" do
|
124
|
-
@
|
125
|
-
@
|
126
|
-
@
|
127
|
-
@
|
129
|
+
@worker.key = "key"
|
130
|
+
@worker.locale = "us"
|
131
|
+
@worker.secret = "secret"
|
132
|
+
@worker.send(:uri).should be_an_instance_of URI::HTTP
|
128
133
|
end
|
129
134
|
end
|
130
135
|
|
131
136
|
context "valid?" do
|
132
137
|
it "returns true if key, secret, and a valid locale are set" do
|
133
|
-
@
|
134
|
-
@
|
135
|
-
@
|
136
|
-
@
|
138
|
+
@worker.key = "key"
|
139
|
+
@worker.locale = "us"
|
140
|
+
@worker.secret = "secret"
|
141
|
+
@worker.send(:valid?).should be_true
|
137
142
|
end
|
138
143
|
|
139
144
|
it "returns false if key is not set" do
|
140
|
-
@
|
141
|
-
@
|
142
|
-
@
|
145
|
+
@worker.locale = "us"
|
146
|
+
@worker.secret = "secret"
|
147
|
+
@worker.send(:valid?).should be_false
|
143
148
|
end
|
144
149
|
|
145
150
|
it "returns false if secret is not set" do
|
146
|
-
@
|
147
|
-
@
|
148
|
-
@
|
151
|
+
@worker.locale = "us"
|
152
|
+
@worker.key = "key"
|
153
|
+
@worker.send(:valid?).should be_false
|
149
154
|
end
|
150
155
|
|
151
156
|
it "returns false if locale is not set" do
|
152
|
-
@
|
153
|
-
@
|
154
|
-
@
|
157
|
+
@worker.key = "key"
|
158
|
+
@worker.secret = "secret"
|
159
|
+
@worker.send(:valid?).should be_false
|
155
160
|
end
|
156
161
|
|
157
162
|
it "returns false if locale is not valid" do
|
158
|
-
@
|
159
|
-
@
|
160
|
-
@
|
161
|
-
@
|
163
|
+
@worker.key = "key"
|
164
|
+
@worker.locale = "US"
|
165
|
+
@worker.secret = "secret"
|
166
|
+
@worker.send(:valid?).should be_false
|
162
167
|
end
|
163
168
|
end
|
164
169
|
end
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sucker
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 23
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 0
|
8
|
-
- 1
|
9
8
|
- 2
|
10
|
-
|
9
|
+
- 0
|
10
|
+
version: 0.2.0
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Hakan Ensari
|
@@ -16,7 +16,7 @@ autorequire:
|
|
16
16
|
bindir: bin
|
17
17
|
cert_chain: []
|
18
18
|
|
19
|
-
date: 2010-07-
|
19
|
+
date: 2010-07-26 00:00:00 +01:00
|
20
20
|
default_executable:
|
21
21
|
dependencies:
|
22
22
|
- !ruby/object:Gem::Dependency
|
@@ -52,40 +52,6 @@ dependencies:
|
|
52
52
|
- 1
|
53
53
|
version: 0.7.7.1
|
54
54
|
requirement: *id002
|
55
|
-
- !ruby/object:Gem::Dependency
|
56
|
-
prerelease: false
|
57
|
-
type: :development
|
58
|
-
name: rspec
|
59
|
-
version_requirements: &id003 !ruby/object:Gem::Requirement
|
60
|
-
none: false
|
61
|
-
requirements:
|
62
|
-
- - "="
|
63
|
-
- !ruby/object:Gem::Version
|
64
|
-
hash: 62196417
|
65
|
-
segments:
|
66
|
-
- 2
|
67
|
-
- 0
|
68
|
-
- 0
|
69
|
-
- beta
|
70
|
-
- 17
|
71
|
-
version: 2.0.0.beta.17
|
72
|
-
requirement: *id003
|
73
|
-
- !ruby/object:Gem::Dependency
|
74
|
-
prerelease: false
|
75
|
-
type: :development
|
76
|
-
name: ruby-debug
|
77
|
-
version_requirements: &id004 !ruby/object:Gem::Requirement
|
78
|
-
none: false
|
79
|
-
requirements:
|
80
|
-
- - "="
|
81
|
-
- !ruby/object:Gem::Version
|
82
|
-
hash: 49
|
83
|
-
segments:
|
84
|
-
- 0
|
85
|
-
- 10
|
86
|
-
- 3
|
87
|
-
version: 0.10.3
|
88
|
-
requirement: *id004
|
89
55
|
description: Sucker is a thin Ruby wrapper to the Amazon Product Advertising API.
|
90
56
|
email: code@papercavalier.com
|
91
57
|
executables: []
|
@@ -94,12 +60,12 @@ extensions: []
|
|
94
60
|
|
95
61
|
extra_rdoc_files:
|
96
62
|
- LICENSE
|
97
|
-
- README.
|
63
|
+
- README.md
|
98
64
|
files:
|
99
65
|
- LICENSE
|
100
66
|
- lib/sucker.rb
|
101
67
|
- lib/sucker/request.rb
|
102
|
-
- README.
|
68
|
+
- README.md
|
103
69
|
- spec/integration/item_lookup_spec.rb
|
104
70
|
- spec/integration/seller_listing_search_spec.rb
|
105
71
|
- spec/spec_helper.rb
|
data/README.textile
DELETED
@@ -1,45 +0,0 @@
|
|
1
|
-
h1. Sucker
|
2
|
-
|
3
|
-
Sucker is a thin Ruby wrapper to the Amazon Product Advertising API. It's built on Curb and Crack.
|
4
|
-
|
5
|
-
I wrote this because ruby_aaws feels somewhat bloated and we are too lazy to conjure a straightforward way to run the latter through multiple network interfaces.
|
6
|
-
|
7
|
-
h2. Examples
|
8
|
-
|
9
|
-
Woo a worker.
|
10
|
-
|
11
|
-
bc. @worker = Sucker.new(
|
12
|
-
:locale => "us",
|
13
|
-
:key => "API KEY",
|
14
|
-
:secret => "API SECRET")
|
15
|
-
|
16
|
-
Fiddle with curl.
|
17
|
-
|
18
|
-
bc. @worker.curl { |c| c.interface = "eth1" }
|
19
|
-
|
20
|
-
Set up a request.
|
21
|
-
|
22
|
-
bc. @worker << {
|
23
|
-
"Operation" => "ItemLookup",
|
24
|
-
"IdType" => "ASIN",
|
25
|
-
"ItemId" => ["0816614024", "0143105825"] }
|
26
|
-
|
27
|
-
Hit the Amazon API.
|
28
|
-
|
29
|
-
bc. @worker.fetch
|
30
|
-
|
31
|
-
Do something with the response.
|
32
|
-
|
33
|
-
bc. pp @worker.to_h
|
34
|
-
|
35
|
-
Hit the Amazon API again.
|
36
|
-
|
37
|
-
bc. @worker << {
|
38
|
-
"ItemId" => ["0393329259", "0393317757"] }
|
39
|
-
@worker.fetch
|
40
|
-
|
41
|
-
Check the integration tests in the spec folder for some more examples.
|
42
|
-
|
43
|
-
h2. Tangential Endnote
|
44
|
-
|
45
|
-
!http://upload.wikimedia.org/wikipedia/en/7/71/Vacuum_cleaner_1910.JPG!
|