sucker 0.7.0 → 0.7.1

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -11,9 +11,10 @@ Examples
11
11
  Set up a worker.
12
12
 
13
13
  worker = Sucker.new(
14
- :locale => "us",
15
- :key => "API KEY",
16
- :secret => "API SECRET")
14
+ :locale => "us",
15
+ :key => "API KEY",
16
+ :secret => "API SECRET",
17
+ :associate_tag => "ASSOCIATE TAG")
17
18
 
18
19
  Fiddle with curl.
19
20
 
@@ -27,18 +28,23 @@ Set up a request.
27
28
  "ItemId" => asin_batch,
28
29
  "ResponseGroup" => ["ItemAttributes", "OfferFull"] }
29
30
 
30
- Hit Amazon and do something with the response.
31
+ Hit Amazon.
31
32
 
32
33
  response = worker.get
33
34
 
34
- # Response internals
35
+ View the internals of the response object.
36
+
35
37
  p response.code,
36
38
  response.time,
37
39
  response.body,
38
40
  response.xml
39
41
 
40
- response.to_h("Item").each { |book| do_something }
41
- response.to_h("Error").each { |error| p error["Message"] }
42
+ Work on the entire document or a particular node.
43
+
44
+ pp response.to_hash
45
+
46
+ response.node("Item").each { |book| do_something }
47
+ response.node("Error").each { |error| do_something }
42
48
 
43
49
  Hit Amazon again.
44
50
 
data/lib/sucker.rb CHANGED
@@ -1,16 +1,16 @@
1
1
  require "active_support/xml_mini/nokogiri"
2
2
  require "cgi"
3
3
  require "curb"
4
- require 'digest/md5'
4
+ require "digest/md5"
5
5
  require "sucker/request"
6
6
  require "sucker/response"
7
7
 
8
8
  # = Sucker
9
9
  # Sucker is a paper-thin Ruby wrapper to the Amazon Product Advertising API.
10
10
  module Sucker
11
- $KCODE = "u" if RUBY_VERSION.include?("1.8")
11
+ $KCODE = "u" if RUBY_VERSION < "1.9"
12
12
 
13
- AMAZON_API_VERSION = "2009-11-01"
13
+ AMAZON_API_VERSION = "2010-06-01"
14
14
 
15
15
  def self.new(args={})
16
16
  Sucker::Request.new(args)
@@ -34,6 +34,11 @@ module Sucker
34
34
  self.parameters.merge!(hash)
35
35
  end
36
36
 
37
+ # A helper method that sets the associate tag
38
+ def associate_tag=(token)
39
+ parameters["AssociateTag"] = token
40
+ end
41
+
37
42
  # A reusable, configurable cURL object
38
43
  def curl
39
44
  @curl ||= Curl::Easy.new
@@ -52,8 +57,8 @@ module Sucker
52
57
  end
53
58
 
54
59
  # A helper method that sets the AWS Access Key ID
55
- def key=(key)
56
- parameters["AWSAccessKeyId"] = key
60
+ def key=(token)
61
+ parameters["AWSAccessKeyId"] = token
57
62
  end
58
63
 
59
64
  private
@@ -1,6 +1,6 @@
1
1
  module Sucker
2
2
 
3
- # A wrapper around the cURL response
3
+ # A Nokogiri-driven wrapper around the cURL response
4
4
  class Response
5
5
  attr_accessor :body, :code, :time, :xml
6
6
 
@@ -10,34 +10,35 @@ module Sucker
10
10
  self.time = curl.total_time
11
11
  end
12
12
 
13
- # Hashifies XML document. Optionally, parses for a node name and returns a collection
14
- # of the hashified nodes.
15
- def to_h(path=nil)
16
- if path
17
- xml.xpath("//xmlns:#{path}").map { |node| content_to_string(node.to_hash[path]) }
18
- else
19
- content_to_string(xml.to_hash)
20
- end
13
+ # Queries an xpath and returns a collection of hashified matches
14
+ def node(path)
15
+ xml.xpath("//xmlns:#{path}").map { |node| strip_content(node.to_hash[path]) }
16
+ end
17
+
18
+ # Hashifies XML document or node
19
+ def to_hash
20
+ strip_content(xml.to_hash)
21
21
  end
22
22
 
23
- alias :to_hash :to_h
23
+ alias :to_h :to_hash
24
24
 
25
+ # The XML document
25
26
  def xml
26
27
  @xml ||= Nokogiri::XML(body)
27
28
  end
28
29
 
29
30
  private
30
31
 
31
- def content_to_string(node)
32
+ def strip_content(node)
32
33
  case node
33
34
  when Array
34
- node.map { |el| content_to_string(el) }
35
+ node.map { |el| strip_content(el) }
35
36
  when Hash
36
37
  if node.keys.size == 1 && node["__content__"]
37
38
  node["__content__"]
38
39
  else
39
- node.inject({}) do |el, key_value|
40
- el.merge({ key_value.first => content_to_string(key_value.last) })
40
+ node.inject({}) do |coll, key_value|
41
+ coll.merge({ key_value.first => strip_content(key_value.last) })
41
42
  end
42
43
  end
43
44
  else
@@ -34,5 +34,5 @@ response = worker.get
34
34
  Benchmark.bm(100) do |x|
35
35
  x.report("Crack") { Crack::XML.parse(response.body) }
36
36
  x.report("SimpleXml") { XmlSimple.xml_in(response.body, { "ForceArray" => false }) }
37
- x.report("AS + Nokogiri") { response.to_h }
37
+ x.report("AS + Nokogiri") { response.to_hash }
38
38
  end
@@ -25,13 +25,13 @@ module Sucker
25
25
  end
26
26
 
27
27
  it "returns two errors" do
28
- errors = @response.to_hash("Error")
28
+ errors = @response.node("Error")
29
29
  errors.size.should eql 2
30
30
  errors.first["Message"].should include "not a valid value"
31
31
  end
32
32
 
33
33
  it "returns one item" do
34
- items = @response.to_hash("ItemAttributes")
34
+ items = @response.node("ItemAttributes")
35
35
  items.size.should eql 1
36
36
  end
37
37
  end
@@ -24,7 +24,7 @@ module Sucker
24
24
  context "single item" do
25
25
  before do
26
26
  @worker << { "ItemId" => "2070119874" }
27
- @item = @worker.get.to_h("Item").first
27
+ @item = @worker.get.node("Item").first
28
28
  end
29
29
 
30
30
  it "returns an item" do
@@ -40,7 +40,7 @@ module Sucker
40
40
  context "multiple items" do
41
41
  before do
42
42
  @worker << { "ItemId" => ["0816614024", "0143105825"] }
43
- @items = @worker.get.to_h("Item")
43
+ @items = @worker.get.node("Item")
44
44
  end
45
45
 
46
46
  it "returns two items" do
@@ -0,0 +1,35 @@
1
+ require "spec_helper"
2
+
3
+ module Sucker
4
+ describe "Images response group" do
5
+ before do
6
+ @worker = Sucker.new(
7
+ :locale => "us",
8
+ :key => amazon["key"],
9
+ :secret => amazon["secret"])
10
+
11
+ @worker << {
12
+ "Operation" => "ItemLookup",
13
+ "IdType" => "ASIN",
14
+ "ResponseGroup" => "Images" }
15
+
16
+ Sucker.stub(@worker)
17
+
18
+ @worker << { "ItemId" => "0816614024" }
19
+ @response = @worker.get
20
+ @item = @response.node("Item").first
21
+ end
22
+
23
+ it "has an ASIN" do
24
+ @item["ASIN"].should eql "0816614024"
25
+ end
26
+
27
+ it "has a large image URL" do
28
+ @item["LargeImage"]["URL"].should match /^http.*jpg$/
29
+ end
30
+
31
+ it "has an image set" do
32
+ @item["ImageSets"]["ImageSet"].should be_an_instance_of Hash
33
+ end
34
+ end
35
+ end
@@ -24,7 +24,7 @@ module Sucker
24
24
  before do
25
25
  @worker << { "ItemId" => "0816614024" }
26
26
  @response = @worker.get
27
- @item = @response.to_h("Item").first
27
+ @item = @response.node("Item").first
28
28
  end
29
29
 
30
30
  it "returns an item" do
@@ -41,14 +41,15 @@ module Sucker
41
41
  end
42
42
 
43
43
  it "returns no errors" do
44
- @response.to_h("Error").should be_empty
44
+ @response.node("Error").should be_empty
45
+ @response.node("Error").should be_an_instance_of Array
45
46
  end
46
47
  end
47
48
 
48
49
  context "multiple items" do
49
50
  before do
50
51
  @worker << { "ItemId" => ["0816614024", "0143105825"] }
51
- @items = @worker.get.to_h("Item")
52
+ @items = @worker.get.node("Item")
52
53
  end
53
54
 
54
55
  it "returns two items" do
@@ -19,7 +19,7 @@ module Sucker
19
19
  context "single item" do
20
20
  before do
21
21
  @worker << { "ItemId" => "482224816X" }
22
- @item = @worker.get.to_h("Item").first
22
+ @item = @worker.get.node("Item").first
23
23
  end
24
24
 
25
25
  it "returns an array of items" do
@@ -16,7 +16,7 @@ module Sucker
16
16
 
17
17
  Sucker.stub(@worker)
18
18
 
19
- @listings = @worker.get.to_h("SellerListings").first
19
+ @listings = @worker.get.node("SellerListings").first
20
20
  end
21
21
 
22
22
  it "returns page count" do
@@ -28,7 +28,7 @@ module Sucker
28
28
 
29
29
  Sucker.stub(@worker)
30
30
 
31
- @items = @worker.get.to_hash("Item")
31
+ @items = @worker.get.node("Item")
32
32
  end
33
33
 
34
34
  it "returns 20 items" do
@@ -25,6 +25,13 @@ module Sucker
25
25
  end
26
26
  end
27
27
 
28
+ context "#associate_tag=" do
29
+ it "sets the associate tag in the parameters" do
30
+ @worker.associate_tag = "foo"
31
+ @worker.parameters["AssociateTag"].should eql "foo"
32
+ end
33
+ end
34
+
28
35
  context "#curl" do
29
36
  it "returns a cURL object" do
30
37
  @worker.curl.should be_an_instance_of Curl::Easy
@@ -37,38 +37,46 @@ module Sucker
37
37
  end
38
38
  end
39
39
 
40
- context "#to_h" do
40
+ context "#node" do
41
+ it "returns a collection of hashified nodes" do
42
+ response = @response.node("ItemAttributes")
43
+ response.map { |book| book["ISBN"] }.should eql @asins
44
+ end
45
+
46
+ it "returns an empty array if there are no matches" do
47
+ response = @response.node("Foo")
48
+ response.should eql []
49
+ end
50
+ end
51
+
52
+ context "#to_hash" do
41
53
  it "returns a hash" do
42
- @response.to_h.should be_an_instance_of Hash
54
+ @response.to_hash.should be_an_instance_of Hash
43
55
  end
44
56
 
45
57
  it "converts a content hash to string" do
46
58
  @response.body = "<book><title>A Thousand Plateaus</title></book>"
47
- @response.to_h["book"]["title"].should be_an_instance_of String
48
- end
49
-
50
- it "is aliased as to_hash" do
51
- @response.to_hash.should eql @response.to_h
59
+ @response.to_hash["book"]["title"].should be_an_instance_of String
52
60
  end
53
61
 
54
- it "parses document for a node name and returns a collection of hashified nodes" do
55
- response = @response.to_hash("ItemAttributes")
56
- response.map { |book| book["ISBN"] }.should eql @asins
62
+ it "is aliased as to_h" do
63
+ @response.should respond_to :to_h
64
+ @response.to_h.should eql @response.to_hash
57
65
  end
58
66
 
59
67
  it "renders French" do
60
68
  @response.body = "<Title>L'archéologie du savoir</Title>"
61
- @response.to_h["Title"].should eql "L'archéologie du savoir"
69
+ @response.to_hash["Title"].should eql "L'archéologie du savoir"
62
70
  end
63
71
 
64
72
  it "renders German" do
65
73
  @response.body = "<Title>Kafka: Für eine kleine Literatur</Title>"
66
- @response.to_h["Title"].should eql "Kafka: Für eine kleine Literatur"
74
+ @response.to_hash["Title"].should eql "Kafka: Für eine kleine Literatur"
67
75
  end
68
76
 
69
77
  it "renders Japanese" do
70
78
  @response.body = "<Title>スティーブ・ジョブズ 驚異のプレゼン―人々を惹きつける18の法則</Title>"
71
- @response.to_h["Title"].should eql "スティーブ・ジョブズ 驚異のプレゼン―人々を惹きつける18の法則"
79
+ @response.to_hash["Title"].should eql "スティーブ・ジョブズ 驚異のプレゼン―人々を惹きつける18の法則"
72
80
  end
73
81
  end
74
82
  end
metadata CHANGED
@@ -1,12 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sucker
3
3
  version: !ruby/object:Gem::Version
4
+ hash: 1
4
5
  prerelease: false
5
6
  segments:
6
7
  - 0
7
8
  - 7
8
- - 0
9
- version: 0.7.0
9
+ - 1
10
+ version: 0.7.1
10
11
  platform: ruby
11
12
  authors:
12
13
  - Hakan Ensari
@@ -15,57 +16,60 @@ autorequire:
15
16
  bindir: bin
16
17
  cert_chain: []
17
18
 
18
- date: 2010-08-06 00:00:00 +01:00
19
+ date: 2010-08-07 00:00:00 +01:00
19
20
  default_executable:
20
21
  dependencies:
21
22
  - !ruby/object:Gem::Dependency
23
+ prerelease: false
24
+ type: :runtime
22
25
  name: activesupport
23
- requirement: &id001 !ruby/object:Gem::Requirement
26
+ version_requirements: &id001 !ruby/object:Gem::Requirement
24
27
  none: false
25
28
  requirements:
26
29
  - - ">="
27
30
  - !ruby/object:Gem::Version
31
+ hash: 7712042
28
32
  segments:
29
33
  - 3
30
34
  - 0
31
35
  - 0
32
36
  - rc
33
37
  version: 3.0.0.rc
34
- type: :runtime
35
- prerelease: false
36
- version_requirements: *id001
38
+ requirement: *id001
37
39
  - !ruby/object:Gem::Dependency
40
+ prerelease: false
41
+ type: :runtime
38
42
  name: nokogiri
39
- requirement: &id002 !ruby/object:Gem::Requirement
43
+ version_requirements: &id002 !ruby/object:Gem::Requirement
40
44
  none: false
41
45
  requirements:
42
46
  - - ">="
43
47
  - !ruby/object:Gem::Version
48
+ hash: 113
44
49
  segments:
45
50
  - 1
46
51
  - 4
47
52
  - 3
48
53
  - 1
49
54
  version: 1.4.3.1
50
- type: :runtime
51
- prerelease: false
52
- version_requirements: *id002
55
+ requirement: *id002
53
56
  - !ruby/object:Gem::Dependency
57
+ prerelease: false
58
+ type: :runtime
54
59
  name: curb
55
- requirement: &id003 !ruby/object:Gem::Requirement
60
+ version_requirements: &id003 !ruby/object:Gem::Requirement
56
61
  none: false
57
62
  requirements:
58
63
  - - ">="
59
64
  - !ruby/object:Gem::Version
65
+ hash: 105
60
66
  segments:
61
67
  - 0
62
68
  - 7
63
69
  - 7
64
70
  - 1
65
71
  version: 0.7.7.1
66
- type: :runtime
67
- prerelease: false
68
- version_requirements: *id003
72
+ requirement: *id003
69
73
  description: A paper-thin Ruby wrapper to the Amazon Product Advertising API
70
74
  email: code@papercavalier.com
71
75
  executables: []
@@ -85,6 +89,7 @@ files:
85
89
  - spec/benchmark/to_hash_implementations.rb
86
90
  - spec/integration/errors_spec.rb
87
91
  - spec/integration/france_spec.rb
92
+ - spec/integration/images_spec.rb
88
93
  - spec/integration/item_lookup_spec.rb
89
94
  - spec/integration/japan_spec.rb
90
95
  - spec/integration/seller_listing_search_spec.rb
@@ -110,7 +115,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
110
115
  requirements:
111
116
  - - ">="
112
117
  - !ruby/object:Gem::Version
113
- hash: 4409148971650304022
118
+ hash: 3
114
119
  segments:
115
120
  - 0
116
121
  version: "0"
@@ -119,6 +124,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
119
124
  requirements:
120
125
  - - ">="
121
126
  - !ruby/object:Gem::Version
127
+ hash: 3
122
128
  segments:
123
129
  - 0
124
130
  version: "0"
@@ -133,6 +139,7 @@ test_files:
133
139
  - spec/benchmark/to_hash_implementations.rb
134
140
  - spec/integration/errors_spec.rb
135
141
  - spec/integration/france_spec.rb
142
+ - spec/integration/images_spec.rb
136
143
  - spec/integration/item_lookup_spec.rb
137
144
  - spec/integration/japan_spec.rb
138
145
  - spec/integration/seller_listing_search_spec.rb