sucker 1.0.0.beta.2 → 1.0.0.beta.3

Sign up to get free protection for your applications and to get access to all the features.
data/History.md ADDED
@@ -0,0 +1,14 @@
1
+ Version 1.0.0.beta3
2
+ ========
3
+
4
+ Release date: 2010-10-25
5
+
6
+ Added
7
+ -----
8
+
9
+ * #find yields to a block if given one
10
+
11
+ Deprecated
12
+ ----------
13
+
14
+ * Renamed #node to #find
data/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  (The MIT License)
2
2
 
3
- Copyright (c) 2009 Paper Cavalier
3
+ Copyright (c) 2010 Paper Cavalier
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining
6
6
  a copy of this software and associated documentation files (the
@@ -19,4 +19,4 @@ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
19
19
  IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
20
20
  CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
21
21
  TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
22
- SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,66 @@
1
+ Sucker
2
+ ======
3
+
4
+ Sucker is a Ruby wrapper to the [Amazon Product Advertising API](https://affiliate-program.amazon.co.uk/gp/advertising/api/detail/main.html). It runs on [curb](http://github.com/taf2/curb) and [the Nokogiri implementation of the XML Mini module](http://github.com/rails/rails/blob/master/activesupport/lib/active_support/xml_mini/nokogiri.rb) in Active Support. It's fast and supports __the entire API__.
5
+
6
+ ![Sucker](http://upload.wikimedia.org/wikipedia/commons/thumb/f/f8/FEMA_-_32011_-_FEMA_Joint_Field_Office_%28JFO%29_preparation_in_Ohio.jpg/480px-FEMA_-_32011_-_FEMA_Joint_Field_Office_%28JFO%29_preparation_in_Ohio.jpg)
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
+ Prepare a request.
19
+
20
+ asin_batch = %w{
21
+ 0816614024 0143105825 0485113600 0816616779 0942299078
22
+ 0816614008 144006654X 0486400360 0486417670 087220474X }
23
+ worker << {
24
+ "Operation" => "ItemLookup",
25
+ "IdType" => "ASIN",
26
+ "ItemId" => asin_batch,
27
+ "ResponseGroup" => ["ItemAttributes", "OfferFull"] }
28
+
29
+ Perform the request.
30
+
31
+ response = worker.get
32
+
33
+ Debug.
34
+
35
+ p response.valid?,
36
+ response.code,
37
+ response.time,
38
+ response.body,
39
+ response.xml,
40
+ response.to_hash
41
+
42
+ Iterate over items in your item lookup.
43
+
44
+ response.find("Item") { |item| ... }
45
+
46
+ Iterate over errors.
47
+
48
+ response.find("Error") { |error| ... }
49
+
50
+ Repeat ad infinitum.
51
+
52
+ Check my [integration specs](http://github.com/papercavalier/sucker/tree/master/spec/integration/) for more examples. See [twenty items](http://github.com/papercavalier/sucker/tree/master/spec/integration/twenty_items_spec.rb) and [multiple locales](http://github.com/papercavalier/sucker/tree/master/spec/integration/multiple_locales_spec.rb) for relatively advanced usage.
53
+
54
+ Last but not least, dive into the [API docs](https://affiliate-program.amazon.co.uk/gp/advertising/api/detail/main.html) to construct your own queries.
55
+
56
+ Stubbing
57
+ --------
58
+
59
+ Use [VCR](http://github.com/myronmarston/vcr) to stub your requests.
60
+
61
+ Caveat: Match URIs on host only and create a new cassette for each stubbed query. [This is how I do it](http://github.com/papercavalier/sucker/blob/master/spec/support/vcr.rb).
62
+
63
+ Compatibility
64
+ -------------
65
+
66
+ Specs pass against Ruby 1.8.7, Ruby 1.9.2, and Rubinius 1.1.
@@ -37,6 +37,14 @@ module Sucker #:nodoc
37
37
  end
38
38
 
39
39
  # A helper method that merges a hash into existing parameters
40
+ #
41
+ # worker = Sucker.new
42
+ # worker << {
43
+ # "Operation" => "ItemLookup",
44
+ # "IdType" => "ASIN",
45
+ # "ItemId" => "0816614024",
46
+ # "ResponseGroup" => "ItemAttributes" }
47
+ #
40
48
  def <<(hash)
41
49
  self.parameters.merge!(hash)
42
50
  end
@@ -82,10 +90,10 @@ module Sucker #:nodoc
82
90
  parameters["AWSAccessKeyId"] = token
83
91
  end
84
92
 
85
- # Sets Amazon API version.
93
+ # Sets the Amazon API version
86
94
  #
87
95
  # worker = Sucker.new
88
- # worker.version = '"2010-06-01"'
96
+ # worker.version = '2010-06-01'
89
97
  #
90
98
  def version=(version)
91
99
  self.parameters["Version"] = version
@@ -18,15 +18,22 @@ module Sucker #:nodoc
18
18
  self.time = curl.total_time
19
19
  end
20
20
 
21
- # Queries an xpath and returns result as an array of hashes
21
+ # Queries an xpath and returns an array of matching nodes
22
22
  #
23
- # For instance, to get all items in an ItemLookup query:
23
+ # Will yield each match if a block is given
24
24
  #
25
25
  # response = worker.get
26
- # response.node("Item").each { |item| ... }
26
+ # response.find("Item") { |item| ... }
27
27
  #
28
- def node(path)
29
- xml.xpath("//xmlns:#{path}").map { |node| strip_content(node.to_hash[path]) }
28
+ def find(path)
29
+ node = xml.xpath("//xmlns:#{path}").map { |node| strip_content(node.to_hash[path]) }
30
+ node.each { |e| yield e } if block_given?
31
+ node
32
+ end
33
+
34
+ def node(path) # :nodoc:
35
+ warn "[DEPRECATION] `node` is deprecated. Use `find` instead."
36
+ find(path)
30
37
  end
31
38
 
32
39
  # Parses the response into a simple hash
@@ -58,7 +65,7 @@ module Sucker #:nodoc
58
65
 
59
66
  private
60
67
 
61
- # Let's massage the somewhat-verbose XML Mini hash into better shape
68
+ # Let's massage that hash
62
69
  def strip_content(node)
63
70
  case node
64
71
  when Array
@@ -1,3 +1,3 @@
1
1
  module Sucker #:nodoc
2
- VERSION = "1.0.0.beta.2"
2
+ VERSION = "1.0.0.beta.3"
3
3
  end
@@ -0,0 +1,27 @@
1
+ require "spec_helper"
2
+
3
+ module Sucker
4
+ describe "Alternate versions" do
5
+ use_vcr_cassette "integration/alternate_versions", :record => :new_episodes
6
+
7
+ let(:worker) do
8
+ worker = Sucker.new(
9
+ :locale => "uk",
10
+ :key => amazon["key"],
11
+ :secret => amazon["secret"])
12
+ worker << {
13
+ "Operation" => "ItemLookup",
14
+ "IdType" => "ASIN",
15
+ "ResponseGroup" => "AlternateVersions",
16
+ "ItemId" => "0141044012" }
17
+ worker
18
+ end
19
+
20
+ it "returns alternate versions" do
21
+ response = worker.get
22
+ alternate_versions = response.find("AlternateVersion")
23
+ alternate_versions.should be_an_instance_of Array
24
+ alternate_versions.first.should have_key "ASIN"
25
+ end
26
+ end
27
+ end
@@ -23,13 +23,13 @@ module Sucker
23
23
  end
24
24
 
25
25
  it "returns two errors" do
26
- errors = response.node("Error")
26
+ errors = response.find("Error")
27
27
  errors.size.should eql 2
28
28
  errors.first["Message"].should include "not a valid value"
29
29
  end
30
30
 
31
31
  it "returns one item" do
32
- items = response.node("ItemAttributes")
32
+ items = response.find("ItemAttributes")
33
33
  items.size.should eql 1
34
34
  end
35
35
  end
@@ -18,7 +18,7 @@ module Sucker
18
18
  "MerchantId" => "All",
19
19
  "ResponseGroup" => ["ItemAttributes", "OfferFull"],
20
20
  "ItemId" => "2070119874" }
21
- worker.get.node("Item").first
21
+ worker.get.find("Item").first
22
22
  end
23
23
 
24
24
  it "returns an item" do
@@ -15,7 +15,7 @@ module Sucker
15
15
  "IdType" => "ASIN",
16
16
  "ResponseGroup" => "Images",
17
17
  "ItemId" => "0816614024" }
18
- worker.get.node("Item").first
18
+ worker.get.find("Item").first
19
19
  end
20
20
 
21
21
  it "has an ASIN" do
@@ -25,7 +25,7 @@ module Sucker
25
25
  worker.get
26
26
  end
27
27
 
28
- let(:item) { response.node("Item").first }
28
+ let(:item) { response.find("Item").first }
29
29
 
30
30
  it "returns an item" do
31
31
  item.should be_an_instance_of Hash
@@ -41,8 +41,8 @@ module Sucker
41
41
  end
42
42
 
43
43
  it "returns no errors" do
44
- response.node("Error").should be_empty
45
- response.node("Error").should be_an_instance_of Array
44
+ response.find("Error").should be_empty
45
+ response.find("Error").should be_an_instance_of Array
46
46
  end
47
47
  end
48
48
 
@@ -51,7 +51,7 @@ module Sucker
51
51
 
52
52
  let(:items) do
53
53
  worker << { "ItemId" => ["0816614024", "0143105825"] }
54
- worker.get.node("Item")
54
+ worker.get.find("Item")
55
55
  end
56
56
 
57
57
  it "returns two items" do
@@ -31,7 +31,7 @@ module Sucker
31
31
 
32
32
  response = worker.get
33
33
  response.should be_valid
34
- response.node("TotalPages").first.should be_an_instance_of String
34
+ response.find("TotalPages").first.should be_an_instance_of String
35
35
  end
36
36
  end
37
37
  end
@@ -16,7 +16,7 @@ module Sucker
16
16
  "IdType" => "ASIN",
17
17
  "ResponseGroup" => ["ItemAttributes", "OfferFull"],
18
18
  "ItemId" => "482224816X" }
19
- worker.get.node("Item").first
19
+ worker.get.find("Item").first
20
20
  end
21
21
 
22
22
  it "returns an array of items" do
@@ -0,0 +1,28 @@
1
+ require "spec_helper"
2
+
3
+ module Sucker
4
+ describe "Keyword Search" do
5
+ use_vcr_cassette "integration/keyword_search", :record => :new_episodes
6
+
7
+ let(:worker) do
8
+ worker = Sucker.new(
9
+ :locale => "us",
10
+ :key => amazon["key"],
11
+ :secret => amazon["secret"])
12
+ worker << {
13
+ "Operation" => "ItemSearch",
14
+ "SearchIndex" => "Books",
15
+ "Keywords" => "zizek lacan",
16
+ "Sort" => "relevancerank" } # also try salesrank and reviewrank
17
+ worker
18
+ end
19
+
20
+ it "returns matches" do
21
+ items = worker.get.find("Item")
22
+ items.size.should > 0
23
+ items.each do |item|
24
+ item["ItemAttributes"]["Title"].should_not be_nil
25
+ end
26
+ end
27
+ end
28
+ end
@@ -11,8 +11,6 @@ module Sucker
11
11
  params = {
12
12
  "Operation" => "ItemLookup",
13
13
  "IdType" => "ASIN",
14
- "Condition" => "All",
15
- "MerchantId" => "All",
16
14
  "ResponseGroup" => "ItemAttributes",
17
15
  "ItemId" => "0816614024" }
18
16
 
@@ -27,11 +25,10 @@ module Sucker
27
25
  end
28
26
  end
29
27
 
30
- bindings = []
31
- threads.each do |thread|
28
+ bindings = threads.map do |thread|
32
29
  thread.join
33
- item = thread[:response].node("Item").first
34
- bindings << item["ItemAttributes"]["Binding"]
30
+ item = thread[:response].find("Item").first
31
+ item["ItemAttributes"]["Binding"]
35
32
  end
36
33
 
37
34
  bindings.uniq.should =~ %w{ Paperback Taschenbuch Broché ペーパーバック }
@@ -0,0 +1,36 @@
1
+ require "spec_helper"
2
+
3
+ # http://docs.amazonwebservices.com/AWSECommerceService/2010-09-01/DG/index.html?PowerSearchSyntax.html
4
+ #
5
+ # author: ambrose and binding: (abridged or large print) and pubdate: after 11-1996
6
+ # subject: history and (Spain or Mexico) and not military and language: Spanish
7
+ # (subject: marketing and author: kotler) or (publisher: harper and subject: "high technology")
8
+ # keywords: "high tech*" and not fiction and pubdate: during 1999
9
+ # isbn: 0446394319 or 0306806819 or 1567993850
10
+
11
+ module Sucker
12
+ describe "Power search" do
13
+ use_vcr_cassette "integration/power_search", :record => :new_episodes
14
+
15
+ let(:worker) do
16
+ worker = Sucker.new(
17
+ :locale => "us",
18
+ :key => amazon["key"],
19
+ :secret => amazon["secret"])
20
+ worker << {
21
+ "Operation" => "ItemSearch",
22
+ "SearchIndex" => "Books",
23
+ "Power" => "author:lacan or deleuze and not fiction",
24
+ "Sort" => "relevancerank" }
25
+ worker
26
+ end
27
+
28
+ it "returns matches" do
29
+ items = worker.get.find("Item")
30
+ items.size.should > 0
31
+ items.each do |item|
32
+ item["ItemAttributes"]["Title"].should_not be_nil
33
+ end
34
+ end
35
+ end
36
+ end
@@ -23,8 +23,8 @@ module Sucker
23
23
  it "finds parent and related items" do
24
24
  worker << { "ItemId" => "0415246334" }
25
25
  response = worker.get
26
- response.node("RelatedItem").size.should eql 1
27
- parent_asin = response.node("RelatedItem").first["Item"]["ASIN"]
26
+ response.find("RelatedItem").size.should eql 1
27
+ parent_asin = response.find("RelatedItem").first["Item"]["ASIN"]
28
28
  end
29
29
  end
30
30
 
@@ -34,7 +34,7 @@ module Sucker
34
34
  it "finds related items" do
35
35
  worker << { "ItemId" => "B000ASPUES" }
36
36
  response = worker.get
37
- response.node("RelatedItem").size.should > 1
37
+ response.find("RelatedItem").size.should > 1
38
38
  end
39
39
  end
40
40
  end
@@ -14,7 +14,7 @@ module Sucker
14
14
  "Operation" => "SellerListingSearch",
15
15
  "SellerId" => "A2JYSO6W6KEP83" }
16
16
 
17
- worker.get.node("SellerListings").first
17
+ worker.get.find("SellerListings").first
18
18
  end
19
19
 
20
20
  it "returns page count" do
@@ -31,7 +31,7 @@ module Sucker
31
31
  "ItemLookup.1.ItemId" => asins[0, 10],
32
32
  "ItemLookup.2.ItemId" => asins[10, 10] }
33
33
 
34
- worker.get.node("Item")
34
+ worker.get.find("Item")
35
35
  end
36
36
 
37
37
  it "returns 20 items" do
@@ -40,16 +40,25 @@ module Sucker
40
40
  end
41
41
  end
42
42
 
43
- context "#node" do
44
- it "returns a collection of hashified nodes" do
45
- node = response.node("ItemAttributes")
43
+ context "#find" do
44
+ it "returns an array of matching nodes" do
45
+ node = response.find("ItemAttributes")
46
46
  node.map { |book| book["ISBN"] }.should eql asins
47
47
  end
48
48
 
49
49
  it "returns an empty array if there are no matches" do
50
- node = response.node("Foo")
50
+ node = response.find("Foo")
51
51
  node.should eql []
52
52
  end
53
+
54
+ it "yields to a block if given one" do
55
+ has_yielded = false
56
+ response.find("ItemAttributes") do |item|
57
+ has_yielded = true
58
+ item.should be_an_instance_of Hash
59
+ end
60
+ has_yielded.should be_true
61
+ end
53
62
  end
54
63
 
55
64
  context "#to_hash" do
metadata CHANGED
@@ -1,15 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sucker
3
3
  version: !ruby/object:Gem::Version
4
- hash: 62196359
4
+ hash: 62196357
5
5
  prerelease: true
6
6
  segments:
7
7
  - 1
8
8
  - 0
9
9
  - 0
10
10
  - beta
11
- - 2
12
- version: 1.0.0.beta.2
11
+ - 3
12
+ version: 1.0.0.beta.3
13
13
  platform: ruby
14
14
  authors:
15
15
  - Hakan Ensari
@@ -18,7 +18,7 @@ autorequire:
18
18
  bindir: bin
19
19
  cert_chain: []
20
20
 
21
- date: 2010-10-22 00:00:00 +01:00
21
+ date: 2010-10-25 00:00:00 +01:00
22
22
  default_executable:
23
23
  dependencies:
24
24
  - !ruby/object:Gem::Dependency
@@ -196,15 +196,19 @@ files:
196
196
  - lib/sucker/version.rb
197
197
  - lib/sucker.rb
198
198
  - LICENSE
199
- - README.markdown
199
+ - README.md
200
+ - History.md
200
201
  - spec/fixtures/asins.txt
202
+ - spec/integration/alternate_versions_spec.rb
201
203
  - spec/integration/errors_spec.rb
202
204
  - spec/integration/france_spec.rb
203
205
  - spec/integration/images_spec.rb
204
206
  - spec/integration/item_lookup_spec.rb
205
207
  - spec/integration/item_search_spec.rb
206
208
  - spec/integration/japan_spec.rb
209
+ - spec/integration/keyword_search_spec.rb
207
210
  - spec/integration/multiple_locales_spec.rb
211
+ - spec/integration/power_search_spec.rb
208
212
  - spec/integration/related_items_spec.rb
209
213
  - spec/integration/seller_listing_search_spec.rb
210
214
  - spec/integration/twenty_items_spec.rb
@@ -254,13 +258,16 @@ specification_version: 3
254
258
  summary: A Ruby wrapper to the Amazon Product Advertising API
255
259
  test_files:
256
260
  - spec/fixtures/asins.txt
261
+ - spec/integration/alternate_versions_spec.rb
257
262
  - spec/integration/errors_spec.rb
258
263
  - spec/integration/france_spec.rb
259
264
  - spec/integration/images_spec.rb
260
265
  - spec/integration/item_lookup_spec.rb
261
266
  - spec/integration/item_search_spec.rb
262
267
  - spec/integration/japan_spec.rb
268
+ - spec/integration/keyword_search_spec.rb
263
269
  - spec/integration/multiple_locales_spec.rb
270
+ - spec/integration/power_search_spec.rb
264
271
  - spec/integration/related_items_spec.rb
265
272
  - spec/integration/seller_listing_search_spec.rb
266
273
  - spec/integration/twenty_items_spec.rb
data/README.markdown DELETED
@@ -1,69 +0,0 @@
1
- Sucker
2
- ======
3
-
4
- Sucker is a Ruby wrapper to the [Amazon Product Advertising API](https://affiliate-program.amazon.co.uk/gp/advertising/api/detail/main.html). It runs on [curb](http://github.com/taf2/curb) and the Nokogiri implementation of the XML Mini module in Active Support. It is blazing fast and supports __the entire API__.
5
-
6
- ![Sucker](http://upload.wikimedia.org/wikipedia/commons/thumb/f/f8/FEMA_-_32011_-_FEMA_Joint_Field_Office_%28JFO%29_preparation_in_Ohio.jpg/480px-FEMA_-_32011_-_FEMA_Joint_Field_Office_%28JFO%29_preparation_in_Ohio.jpg)
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
- Prep a request.
19
-
20
- asin_batch = %w{
21
- 0816614024 0143105825 0485113600 0816616779 0942299078
22
- 0816614008 144006654X 0486400360 0486417670 087220474X }
23
- worker << {
24
- "Operation" => "ItemLookup",
25
- "IdType" => "ASIN",
26
- "ItemId" => asin_batch,
27
- "ResponseGroup" => ["ItemAttributes", "OfferFull"] }
28
-
29
- Perform the request.
30
-
31
- response = worker.get
32
-
33
- Debug.
34
-
35
- if response.valid?
36
- p response.code,
37
- response.time,
38
- response.body,
39
- response.xml,
40
- response.to_hash
41
- end
42
-
43
- Say you performed an item lookup. Iterate over all items and errors.
44
-
45
- response.node("Item").each { |item| ... }
46
- response.node("Error").each { |error| ... }
47
-
48
- Perform a new request in a more DSL-y way.
49
-
50
- worker << { "ItemId" => "0486454398" }
51
- worker.get.node("Item").each { |item| ... }
52
-
53
- Repeat ad infinitum.
54
-
55
- Check the [integration specs](http://github.com/papercavalier/sucker/tree/master/spec/integration/) for more examples. In particullar, see [twenty items](http://github.com/papercavalier/sucker/tree/master/spec/integration/twenty_items_spec.rb) and [multiple locales](http://github.com/papercavalier/sucker/tree/master/spec/integration/multiple_locales_spec.rb) for advanced usage.
56
-
57
- Finally, dive into the [API docs](https://affiliate-program.amazon.co.uk/gp/advertising/api/detail/main.html) to construct your own queries.
58
-
59
- Stubbing
60
- --------
61
-
62
- Use [VCR](http://github.com/myronmarston/vcr) to stub your requests. [This file](http://github.com/papercavalier/sucker/blob/master/spec/support/vcr.rb) should help you set up VCR with RSpec.
63
-
64
- Don't match requests on URI. The parameters include a timestamp that results in each URI being unique.
65
-
66
- Compatibility
67
- -------------
68
-
69
- Specs pass against Ruby 1.8.7, Ruby 1.9.2, and Rubinius 1.1.