briandunn-a2ws 0.1.9
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/.document +5 -0
- data/.gitignore +5 -0
- data/LICENSE +20 -0
- data/README.rdoc +12 -0
- data/Rakefile +50 -0
- data/VERSION.yml +3 -0
- data/a2ws.gemspec +69 -0
- data/lib/a2ws/base.rb +48 -0
- data/lib/a2ws/image.rb +16 -0
- data/lib/a2ws/image_search.rb +21 -0
- data/lib/a2ws/item.rb +23 -0
- data/lib/a2ws/item_search.rb +24 -0
- data/lib/a2ws/methodize.rb +17 -0
- data/lib/a2ws/signature.rb +46 -0
- data/lib/a2ws.rb +13 -0
- data/spec/a2ws_live_spec.rb +28 -0
- data/spec/a2ws_spec.rb +21 -0
- data/spec/fixtures/empty_response.yml +73 -0
- data/spec/fixtures/single_item_response.yml +72 -0
- data/spec/spec_helper.rb +13 -0
- data/test/a2ws_test.rb +69 -0
- metadata +108 -0
data/.document
ADDED
data/LICENSE
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
Copyright (c) 2009 Andy Shen
|
|
2
|
+
|
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
|
4
|
+
a copy of this software and associated documentation files (the
|
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
|
9
|
+
the following conditions:
|
|
10
|
+
|
|
11
|
+
The above copyright notice and this permission notice shall be
|
|
12
|
+
included in all copies or substantial portions of the Software.
|
|
13
|
+
|
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
data/Rakefile
ADDED
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
require 'rubygems'
|
|
2
|
+
require 'rake'
|
|
3
|
+
|
|
4
|
+
begin
|
|
5
|
+
require 'jeweler'
|
|
6
|
+
Jeweler::Tasks.new do |gem|
|
|
7
|
+
gem.name = "a2ws"
|
|
8
|
+
gem.summary = %Q{Wrapper for Amazon Associates Web Service (A2WS).}
|
|
9
|
+
gem.email = "brianpatrickdunn@gmail.com"
|
|
10
|
+
gem.homepage = "http://github.com/handcrafted/a2ws"
|
|
11
|
+
gem.authors = ["Andy Shen", "Josh Owens"]
|
|
12
|
+
gem.add_dependency('httparty', '>= 0.4.3')
|
|
13
|
+
gem.add_dependency('activesupport', '>= 2.2.2')
|
|
14
|
+
gem.add_dependency('ruby-hmac')
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
rescue LoadError
|
|
18
|
+
puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
require 'spec/rake/spectask'
|
|
22
|
+
Spec::Rake::SpecTask.new(:spec) do |spec|
|
|
23
|
+
spec.libs << 'lib' << 'spec'
|
|
24
|
+
spec.spec_files = FileList['spec/**/*_spec.rb']
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
Spec::Rake::SpecTask.new(:rcov) do |spec|
|
|
28
|
+
spec.libs << 'lib' << 'spec'
|
|
29
|
+
spec.pattern = 'spec/**/*_spec.rb'
|
|
30
|
+
spec.rcov = true
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
task :default => :spec
|
|
35
|
+
|
|
36
|
+
require 'rake/rdoctask'
|
|
37
|
+
Rake::RDocTask.new do |rdoc|
|
|
38
|
+
if File.exist?('VERSION.yml')
|
|
39
|
+
config = YAML.load(File.read('VERSION.yml'))
|
|
40
|
+
version = "#{config[:major]}.#{config[:minor]}.#{config[:patch]}"
|
|
41
|
+
else
|
|
42
|
+
version = ""
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
rdoc.rdoc_dir = 'rdoc'
|
|
46
|
+
rdoc.title = "a2ws #{version}"
|
|
47
|
+
rdoc.rdoc_files.include('README*')
|
|
48
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
|
49
|
+
end
|
|
50
|
+
|
data/VERSION.yml
ADDED
data/a2ws.gemspec
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
|
2
|
+
|
|
3
|
+
Gem::Specification.new do |s|
|
|
4
|
+
s.name = %q{a2ws}
|
|
5
|
+
s.version = "0.1.9"
|
|
6
|
+
|
|
7
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
|
8
|
+
s.authors = ["Andy Shen", "Josh Owens"]
|
|
9
|
+
s.date = %q{2009-08-04}
|
|
10
|
+
s.email = %q{brianpatrickdunn@gmail.com}
|
|
11
|
+
s.extra_rdoc_files = [
|
|
12
|
+
"LICENSE",
|
|
13
|
+
"README.rdoc"
|
|
14
|
+
]
|
|
15
|
+
s.files = [
|
|
16
|
+
".document",
|
|
17
|
+
".gitignore",
|
|
18
|
+
"LICENSE",
|
|
19
|
+
"README.rdoc",
|
|
20
|
+
"Rakefile",
|
|
21
|
+
"VERSION.yml",
|
|
22
|
+
"a2ws.gemspec",
|
|
23
|
+
"lib/a2ws.rb",
|
|
24
|
+
"lib/a2ws/base.rb",
|
|
25
|
+
"lib/a2ws/image.rb",
|
|
26
|
+
"lib/a2ws/image_search.rb",
|
|
27
|
+
"lib/a2ws/item.rb",
|
|
28
|
+
"lib/a2ws/item_search.rb",
|
|
29
|
+
"lib/a2ws/methodize.rb",
|
|
30
|
+
"lib/a2ws/signature.rb",
|
|
31
|
+
"spec/a2ws_live_spec.rb",
|
|
32
|
+
"spec/a2ws_spec.rb",
|
|
33
|
+
"spec/fixtures/empty_response.yml",
|
|
34
|
+
"spec/fixtures/single_item_response.yml",
|
|
35
|
+
"spec/spec_helper.rb",
|
|
36
|
+
"test/a2ws_test.rb"
|
|
37
|
+
]
|
|
38
|
+
s.has_rdoc = true
|
|
39
|
+
s.homepage = %q{http://github.com/handcrafted/a2ws}
|
|
40
|
+
s.rdoc_options = ["--charset=UTF-8"]
|
|
41
|
+
s.require_paths = ["lib"]
|
|
42
|
+
s.rubygems_version = %q{1.3.1}
|
|
43
|
+
s.summary = %q{Wrapper for Amazon Associates Web Service (A2WS).}
|
|
44
|
+
s.test_files = [
|
|
45
|
+
"spec/a2ws_live_spec.rb",
|
|
46
|
+
"spec/a2ws_spec.rb",
|
|
47
|
+
"spec/spec_helper.rb",
|
|
48
|
+
"test/a2ws_test.rb"
|
|
49
|
+
]
|
|
50
|
+
|
|
51
|
+
if s.respond_to? :specification_version then
|
|
52
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
|
53
|
+
s.specification_version = 2
|
|
54
|
+
|
|
55
|
+
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
|
56
|
+
s.add_runtime_dependency(%q<httparty>, [">= 0.4.3"])
|
|
57
|
+
s.add_runtime_dependency(%q<activesupport>, [">= 2.2.2"])
|
|
58
|
+
s.add_runtime_dependency(%q<ruby-hmac>, [">= 0"])
|
|
59
|
+
else
|
|
60
|
+
s.add_dependency(%q<httparty>, [">= 0.4.3"])
|
|
61
|
+
s.add_dependency(%q<activesupport>, [">= 2.2.2"])
|
|
62
|
+
s.add_dependency(%q<ruby-hmac>, [">= 0"])
|
|
63
|
+
end
|
|
64
|
+
else
|
|
65
|
+
s.add_dependency(%q<httparty>, [">= 0.4.3"])
|
|
66
|
+
s.add_dependency(%q<activesupport>, [">= 2.2.2"])
|
|
67
|
+
s.add_dependency(%q<ruby-hmac>, [">= 0"])
|
|
68
|
+
end
|
|
69
|
+
end
|
data/lib/a2ws/base.rb
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
module A2WS
|
|
2
|
+
class Base
|
|
3
|
+
include HTTParty
|
|
4
|
+
extend Signature
|
|
5
|
+
base_uri 'http://ecs.amazonaws.com'
|
|
6
|
+
default_params :Service => 'AWSECommerceService', :Operation => 'ItemSearch'
|
|
7
|
+
@@secret_key = ''
|
|
8
|
+
|
|
9
|
+
def self.configure
|
|
10
|
+
yield self
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def self.api_key=(key)
|
|
14
|
+
default_params :AWSAccessKeyId => key
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def self.secret_key=(key)
|
|
18
|
+
@@secret_key = key
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def self.secret_key
|
|
22
|
+
@@secret_key
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def self.request_uri
|
|
26
|
+
'/onca/xml'
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
private
|
|
30
|
+
|
|
31
|
+
def self.downcase_keys(hash)
|
|
32
|
+
new_hash = {}
|
|
33
|
+
hash.keys.each do |key|
|
|
34
|
+
value = hash.delete(key)
|
|
35
|
+
new_hash[downcase_key(key)] = value
|
|
36
|
+
new_hash[downcase_key(key)] = downcase_keys(value) if value.is_a?(Hash)
|
|
37
|
+
new_hash[downcase_key(key)] = value.each{|p| downcase_keys(p) if p.is_a?(Hash)} if value.is_a?(Array)
|
|
38
|
+
end
|
|
39
|
+
new_hash
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def self.downcase_key(key)
|
|
43
|
+
key.titlecase.downcase.gsub(' ', '_')
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
end
|
data/lib/a2ws/image.rb
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
module A2WS
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class ImageSearch < Base
|
|
5
|
+
|
|
6
|
+
def self.find(item)
|
|
7
|
+
items = get(request_url, :query => {:ItemId => item, :Operation => "ItemLookup", :ResponseGroup => "Images"})
|
|
8
|
+
puts items.inspect
|
|
9
|
+
if items['ItemLookupResponse']["Items"]["Request"]['IsValid'] == 'True'
|
|
10
|
+
items["ItemLookupResponse"]["Items"]["Item"].delete("ImageSets")
|
|
11
|
+
items["ItemLookupResponse"]["Items"]["Item"].delete("ASIN")
|
|
12
|
+
downcase_keys(items["ItemLookupResponse"]["Items"]["Item"]).collect { |size, data| Image.new(size, data) }
|
|
13
|
+
else
|
|
14
|
+
raise items['Request']['Errors']['Error']['Message']
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
end
|
data/lib/a2ws/item.rb
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
module A2WS
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class Item
|
|
5
|
+
include Methodize
|
|
6
|
+
|
|
7
|
+
def item_attributes
|
|
8
|
+
ItemAttributes.new @data_hash["item_attributes"]
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
def images
|
|
12
|
+
ImageSearch.find(@data_hash["asin"])
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
class ItemAttributes
|
|
18
|
+
include Methodize
|
|
19
|
+
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
end
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
module A2WS
|
|
2
|
+
|
|
3
|
+
class ItemSearch < Base
|
|
4
|
+
|
|
5
|
+
def self.find(keywords, search_index = :All, options = {})
|
|
6
|
+
options.merge!({:Keywords => keywords, :SearchIndex => search_index})
|
|
7
|
+
query = sign_request(options)
|
|
8
|
+
puts query.inspect
|
|
9
|
+
result = get( request_uri, :query => query )
|
|
10
|
+
puts result.inspect
|
|
11
|
+
|
|
12
|
+
items = result["ItemSearchResponse"]["Items"]
|
|
13
|
+
if items['Request']['IsValid'] == 'True'
|
|
14
|
+
[ items['Item'] ].flatten.compact.collect do |i|
|
|
15
|
+
Item.new downcase_keys(i)
|
|
16
|
+
end
|
|
17
|
+
else
|
|
18
|
+
raise items['Request']['Errors']['Error']['Message']
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
module Methodize
|
|
2
|
+
|
|
3
|
+
attr_accessor :data_hash
|
|
4
|
+
|
|
5
|
+
def initialize(attributes)
|
|
6
|
+
@data_hash = attributes
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def method_missing(meth,*args)
|
|
10
|
+
if @data_hash.keys.include?(meth.to_s)
|
|
11
|
+
@data_hash[meth.to_s]
|
|
12
|
+
else
|
|
13
|
+
super
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
end
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
require "hmac"
|
|
2
|
+
require "hmac-sha2"
|
|
3
|
+
require 'cgi'
|
|
4
|
+
|
|
5
|
+
# reference:
|
|
6
|
+
# http://docs.amazonwebservices.com/AWSECommerceService/2009-07-01/DG/index.html?BasicAuthProcess.html
|
|
7
|
+
# http://docs.amazonwebservices.com/AWSECommerceService/2009-07-01/DG/index.html?Query_QueryAuth.html
|
|
8
|
+
module A2WS
|
|
9
|
+
module Signature
|
|
10
|
+
def sign_request(params)
|
|
11
|
+
params.reverse_merge!(:Timestamp => timestamp, :Version => "2009-07-01")
|
|
12
|
+
params.merge!(:Signature => build_signature(params, "GET"))
|
|
13
|
+
params
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
private
|
|
17
|
+
|
|
18
|
+
def timestamp
|
|
19
|
+
Time.now.gmtime.strftime("%Y-%m-%dT%H:%M:%SZ")
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def build_string_to_sign(params, http_verb)
|
|
23
|
+
returning [] do |string_to_sign|
|
|
24
|
+
string_to_sign << http_verb << self.base_uri.gsub(/^https?\:\/\//, "") << self.request_uri
|
|
25
|
+
canonicalized_params = params.sort_by {|k,v| k.to_s }.map do |( k,v )|
|
|
26
|
+
"#{aws_escape(k.to_s)}=#{aws_escape(v.to_s)}"
|
|
27
|
+
end.join("&")
|
|
28
|
+
string_to_sign << canonicalized_params
|
|
29
|
+
end.join("\n")
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def build_signature(params, http_verb)
|
|
33
|
+
params.merge!(self.default_params)
|
|
34
|
+
|
|
35
|
+
hmac = HMAC::SHA256.new(secret_key)
|
|
36
|
+
hmac.update(build_string_to_sign(params, http_verb))
|
|
37
|
+
|
|
38
|
+
Base64.encode64(hmac.digest).chomp
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def aws_escape(string)
|
|
42
|
+
CGI.escape(string).gsub("+", "%20").gsub("%7E", "~")
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
data/lib/a2ws.rb
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
require 'rubygems'
|
|
2
|
+
require 'httparty'
|
|
3
|
+
require 'activesupport'
|
|
4
|
+
require 'pp'
|
|
5
|
+
|
|
6
|
+
$:.unshift File.join(File.dirname(__FILE__),'..','lib')
|
|
7
|
+
require 'a2ws/signature'
|
|
8
|
+
require 'a2ws/base'
|
|
9
|
+
require 'a2ws/methodize'
|
|
10
|
+
require 'a2ws/item'
|
|
11
|
+
require 'a2ws/image'
|
|
12
|
+
require 'a2ws/item_search'
|
|
13
|
+
require 'a2ws/image_search'
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
|
2
|
+
|
|
3
|
+
include A2WS
|
|
4
|
+
begin
|
|
5
|
+
conf = YAML::load(open(ENV['HOME'] + '/.a2ws'))
|
|
6
|
+
A2WS::Base.configure do |config|
|
|
7
|
+
config.api_key = conf["access_key"]
|
|
8
|
+
config.secret_key = conf["secret_key"]
|
|
9
|
+
end
|
|
10
|
+
describe "A2WS Operations" do
|
|
11
|
+
|
|
12
|
+
describe ItemSearch do
|
|
13
|
+
|
|
14
|
+
it "should find some items" do
|
|
15
|
+
ItemSearch.find('Harry Potter', :Books).size.should_not == 0
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
describe "signing" do
|
|
21
|
+
ItemSearch.find('Harry Potter', :Books).size.should_not == 0
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
end
|
|
25
|
+
rescue
|
|
26
|
+
puts "couldn't run live specs. if you want to actually hit up the api, put your key in a yaml file in your home folder.#{$!}"
|
|
27
|
+
end
|
|
28
|
+
|
data/spec/a2ws_spec.rb
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
|
2
|
+
|
|
3
|
+
include A2WS
|
|
4
|
+
|
|
5
|
+
describe "A2WS Operations" do
|
|
6
|
+
|
|
7
|
+
describe ItemSearch do
|
|
8
|
+
|
|
9
|
+
it "should survive a search that returns a single result" do
|
|
10
|
+
ItemSearch.should_receive(:get).and_return(fixture :single_item_response)
|
|
11
|
+
ItemSearch.find('not used')
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
it "should return an empty array when there aint no results" do
|
|
15
|
+
ItemSearch.should_receive(:get).and_return(fixture :empty_response)
|
|
16
|
+
ItemSearch.find( "not used" ).should == []
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
end
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
---
|
|
2
|
+
ItemSearchResponse:
|
|
3
|
+
OperationRequest:
|
|
4
|
+
Arguments:
|
|
5
|
+
Argument:
|
|
6
|
+
- Name: Operation
|
|
7
|
+
Value: ItemSearch
|
|
8
|
+
- Name: Service
|
|
9
|
+
Value: AWSECommerceService
|
|
10
|
+
- Name: AWSAccessKeyId
|
|
11
|
+
Value: AKIAJJES5KN2IIXQSSOA
|
|
12
|
+
- Name: SearchIndex
|
|
13
|
+
Value: Books
|
|
14
|
+
- Name: Keywords
|
|
15
|
+
Value: assdflasdjfasldkfjasdl
|
|
16
|
+
RequestId: !str
|
|
17
|
+
str: 46ebabe5-abe2-44ff-a010-7b76cb0538c9
|
|
18
|
+
"@attributes": {}
|
|
19
|
+
|
|
20
|
+
RequestProcessingTime: !str
|
|
21
|
+
str: "0.0196700000000000"
|
|
22
|
+
"@attributes": {}
|
|
23
|
+
|
|
24
|
+
Items:
|
|
25
|
+
TotalPages: !str
|
|
26
|
+
str: "0"
|
|
27
|
+
"@attributes": {}
|
|
28
|
+
|
|
29
|
+
Request:
|
|
30
|
+
ItemSearchRequest:
|
|
31
|
+
DeliveryMethod: !str
|
|
32
|
+
str: Ship
|
|
33
|
+
"@attributes": {}
|
|
34
|
+
|
|
35
|
+
Keywords: !str
|
|
36
|
+
str: assdflasdjfasldkfjasdl
|
|
37
|
+
"@attributes": {}
|
|
38
|
+
|
|
39
|
+
MerchantId: !str
|
|
40
|
+
str: Amazon
|
|
41
|
+
"@attributes": {}
|
|
42
|
+
|
|
43
|
+
Condition: !str
|
|
44
|
+
str: New
|
|
45
|
+
"@attributes": {}
|
|
46
|
+
|
|
47
|
+
ResponseGroup: !str
|
|
48
|
+
str: Small
|
|
49
|
+
"@attributes": {}
|
|
50
|
+
|
|
51
|
+
SearchIndex: !str
|
|
52
|
+
str: Books
|
|
53
|
+
"@attributes": {}
|
|
54
|
+
|
|
55
|
+
Errors:
|
|
56
|
+
Error:
|
|
57
|
+
Message: !str
|
|
58
|
+
str: We did not find any matches for your request.
|
|
59
|
+
"@attributes": {}
|
|
60
|
+
|
|
61
|
+
Code: !str
|
|
62
|
+
str: AWS.ECommerceService.NoExactMatches
|
|
63
|
+
"@attributes": {}
|
|
64
|
+
|
|
65
|
+
IsValid: !str
|
|
66
|
+
str: "True"
|
|
67
|
+
"@attributes": {}
|
|
68
|
+
|
|
69
|
+
TotalResults: !str
|
|
70
|
+
str: "0"
|
|
71
|
+
"@attributes": {}
|
|
72
|
+
|
|
73
|
+
xmlns: http://webservices.amazon.com/AWSECommerceService/2005-10-05
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
---
|
|
2
|
+
ItemSearchResponse:
|
|
3
|
+
OperationRequest:
|
|
4
|
+
Arguments:
|
|
5
|
+
Argument:
|
|
6
|
+
- Name: Operation
|
|
7
|
+
Value: ItemSearch
|
|
8
|
+
- Name: Service
|
|
9
|
+
Value: AWSECommerceService
|
|
10
|
+
- Name: AWSAccessKeyId
|
|
11
|
+
Value: SECRET
|
|
12
|
+
- Name: SearchIndex
|
|
13
|
+
Value: Books
|
|
14
|
+
- Name: Keywords
|
|
15
|
+
Value: Something cool from canada
|
|
16
|
+
RequestId: !str
|
|
17
|
+
str: 53b485a7-6bb7-4b3f-9c6d-fa9f2f1293dc
|
|
18
|
+
"@attributes": {}
|
|
19
|
+
RequestProcessingTime: !str
|
|
20
|
+
str: "0.0551560000000000"
|
|
21
|
+
"@attributes": {}
|
|
22
|
+
Items:
|
|
23
|
+
TotalPages: !str
|
|
24
|
+
str: "1"
|
|
25
|
+
"@attributes": {}
|
|
26
|
+
Item:
|
|
27
|
+
ItemAttributes:
|
|
28
|
+
Author: !str
|
|
29
|
+
str: Christopher A. Sawyer
|
|
30
|
+
"@attributes": {}
|
|
31
|
+
Title: !str
|
|
32
|
+
str: "Something cool from Canada: powersport equipment design requires flowing, edgy forms, an understanding of the role of the rider, and a multi-disciplinary ... article from: Automotive Design & Production"
|
|
33
|
+
"@attributes": {}
|
|
34
|
+
ProductGroup: !str
|
|
35
|
+
str: Book
|
|
36
|
+
"@attributes": {}
|
|
37
|
+
Manufacturer: !str
|
|
38
|
+
str: Thomson Gale
|
|
39
|
+
"@attributes": {}
|
|
40
|
+
ASIN: !str
|
|
41
|
+
str: B000Y757NE
|
|
42
|
+
"@attributes": {}
|
|
43
|
+
DetailPageURL: !str
|
|
44
|
+
str: http://www.amazon.com/Something-cool-Canada-understanding-multi-disciplinary/dp/B000Y757NE%3FSubscriptionId%3DAKIAJJES5KN2IIXQSSOA%26tag%3Dws%26linkCode%3Dxm2%26camp%3D2025%26creative%3D165953%26creativeASIN%3DB000Y757NE
|
|
45
|
+
"@attributes": {}
|
|
46
|
+
Request:
|
|
47
|
+
ItemSearchRequest:
|
|
48
|
+
DeliveryMethod: !str
|
|
49
|
+
str: Ship
|
|
50
|
+
"@attributes": {}
|
|
51
|
+
Keywords: !str
|
|
52
|
+
str: Something cool from canada
|
|
53
|
+
"@attributes": {}
|
|
54
|
+
MerchantId: !str
|
|
55
|
+
str: Amazon
|
|
56
|
+
"@attributes": {}
|
|
57
|
+
Condition: !str
|
|
58
|
+
str: New
|
|
59
|
+
"@attributes": {}
|
|
60
|
+
ResponseGroup: !str
|
|
61
|
+
str: Small
|
|
62
|
+
"@attributes": {}
|
|
63
|
+
SearchIndex: !str
|
|
64
|
+
str: Books
|
|
65
|
+
"@attributes": {}
|
|
66
|
+
IsValid: !str
|
|
67
|
+
str: "True"
|
|
68
|
+
"@attributes": {}
|
|
69
|
+
TotalResults: !str
|
|
70
|
+
str: "1"
|
|
71
|
+
"@attributes": {}
|
|
72
|
+
xmlns: http://webservices.amazon.com/AWSECommerceService/2005-10-05
|
data/spec/spec_helper.rb
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
require 'spec'
|
|
2
|
+
require 'yaml'
|
|
3
|
+
require 'pp'
|
|
4
|
+
|
|
5
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
|
6
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
|
7
|
+
require 'a2ws'
|
|
8
|
+
|
|
9
|
+
Spec::Runner.configure do |config|
|
|
10
|
+
def fixture file_name
|
|
11
|
+
YAML.load(File.open(File.expand_path(File.dirname(__FILE__) + "/fixtures/#{file_name}.yml")))
|
|
12
|
+
end
|
|
13
|
+
end
|
data/test/a2ws_test.rb
ADDED
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
require 'rubygems'
|
|
2
|
+
gem 'thoughtbot-shoulda'
|
|
3
|
+
require 'shoulda'
|
|
4
|
+
require File.expand_path(File.dirname(__FILE__) + '/../lib/a2ws')
|
|
5
|
+
include A2WS
|
|
6
|
+
# black-box testing for generating signatures
|
|
7
|
+
# reference:
|
|
8
|
+
# http://docs.amazonwebservices.com/AWSECommerceService/2009-07-01/DG/index.html?rest-signature.html
|
|
9
|
+
class A2WSTest < Test::Unit::TestCase
|
|
10
|
+
context "Amazon Authentication" do
|
|
11
|
+
should "occur when finding items" do
|
|
12
|
+
AAWS.stubs(:timestamp).returns("2009-01-01T12:00:00Z")
|
|
13
|
+
AAWS.stubs(:build_signature).returns("SIGNATURE")
|
|
14
|
+
expected_params = has_entries(
|
|
15
|
+
:query => has_entries(
|
|
16
|
+
:Timestamp => "2009-01-01T12:00:00Z",
|
|
17
|
+
:Signature => "SIGNATURE",
|
|
18
|
+
:Version => "2009-07-01"
|
|
19
|
+
)
|
|
20
|
+
)
|
|
21
|
+
AAWS.expects(:get).with("/onca/xml", expected_params).returns(AAWSCannedResponse.asin_response)
|
|
22
|
+
AAWS.find("0316769177")
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
should "occur when searching items" do
|
|
26
|
+
AAWS.stubs(:timestamp).returns("2009-01-01T12:00:00Z")
|
|
27
|
+
AAWS.stubs(:build_signature).returns("SIGNATURE")
|
|
28
|
+
expected_params = has_entries(
|
|
29
|
+
:query => has_entries(
|
|
30
|
+
:Timestamp => "2009-01-01T12:00:00Z",
|
|
31
|
+
:Signature => "SIGNATURE",
|
|
32
|
+
:Version => "2009-07-01"
|
|
33
|
+
)
|
|
34
|
+
)
|
|
35
|
+
AAWS.expects(:get).with("/onca/xml", expected_params).returns(AAWSCannedResponse.search_response)
|
|
36
|
+
AAWS.search(:Title => "Ruby on Rails")
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
should "properly generate signatures" do
|
|
40
|
+
AAWS.stubs(:timestamp).returns("2009-01-01T12:00:00Z")
|
|
41
|
+
AAWS.stubs(:secret_key).returns("1234567890")
|
|
42
|
+
AAWS.stubs(:default_params).returns({ :Service => "AWSECommerceService",
|
|
43
|
+
:AWSAccessKeyId => "00000000000000000000",
|
|
44
|
+
:ResponseGroup => "ItemAttributes,Offers,Images,Reviews"})
|
|
45
|
+
|
|
46
|
+
assert_equal "Nace+U3Az4OhN7tISqgs1vdLBHBEijWcBeCqL5xN9xg=",
|
|
47
|
+
AAWS.sign_request({ :Operation => "ItemLookup",
|
|
48
|
+
:ItemId => "0679722769",
|
|
49
|
+
:Version => "2009-01-06"})[:Signature]
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
should "properly generate signatures with overrides" do
|
|
53
|
+
AAWS.stubs(:base_uri).returns("http://ecs.amazonaws.co.uk")
|
|
54
|
+
AAWS.stubs(:timestamp).returns("2009-01-01T12:00:00Z")
|
|
55
|
+
AAWS.stubs(:secret_key).returns("1234567890")
|
|
56
|
+
AAWS.stubs(:default_params).returns({ :Service => "AWSECommerceService",
|
|
57
|
+
:AWSAccessKeyId => "00000000000000000000",
|
|
58
|
+
:ResponseGroup => "ItemAttributes,Offers,Images,Reviews,Variations"})
|
|
59
|
+
|
|
60
|
+
assert_equal "TuM6E5L9u/uNqOX09ET03BXVmHLVFfJIna5cxXuHxiU=",
|
|
61
|
+
AAWS.sign_request({ :Operation => "ItemSearch",
|
|
62
|
+
:SearchIndex => "DVD",
|
|
63
|
+
:Sort => "salesrank",
|
|
64
|
+
:AssociateTag => "mytag-20",
|
|
65
|
+
:Actor => "Johnny Depp",
|
|
66
|
+
:Version => "2009-01-01"})[:Signature]
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: briandunn-a2ws
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.1.9
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Andy Shen
|
|
8
|
+
- Josh Owens
|
|
9
|
+
autorequire:
|
|
10
|
+
bindir: bin
|
|
11
|
+
cert_chain: []
|
|
12
|
+
|
|
13
|
+
date: 2009-08-04 00:00:00 -07:00
|
|
14
|
+
default_executable:
|
|
15
|
+
dependencies:
|
|
16
|
+
- !ruby/object:Gem::Dependency
|
|
17
|
+
name: httparty
|
|
18
|
+
type: :runtime
|
|
19
|
+
version_requirement:
|
|
20
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
21
|
+
requirements:
|
|
22
|
+
- - ">="
|
|
23
|
+
- !ruby/object:Gem::Version
|
|
24
|
+
version: 0.4.3
|
|
25
|
+
version:
|
|
26
|
+
- !ruby/object:Gem::Dependency
|
|
27
|
+
name: activesupport
|
|
28
|
+
type: :runtime
|
|
29
|
+
version_requirement:
|
|
30
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
31
|
+
requirements:
|
|
32
|
+
- - ">="
|
|
33
|
+
- !ruby/object:Gem::Version
|
|
34
|
+
version: 2.2.2
|
|
35
|
+
version:
|
|
36
|
+
- !ruby/object:Gem::Dependency
|
|
37
|
+
name: ruby-hmac
|
|
38
|
+
type: :runtime
|
|
39
|
+
version_requirement:
|
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
41
|
+
requirements:
|
|
42
|
+
- - ">="
|
|
43
|
+
- !ruby/object:Gem::Version
|
|
44
|
+
version: "0"
|
|
45
|
+
version:
|
|
46
|
+
description:
|
|
47
|
+
email: brianpatrickdunn@gmail.com
|
|
48
|
+
executables: []
|
|
49
|
+
|
|
50
|
+
extensions: []
|
|
51
|
+
|
|
52
|
+
extra_rdoc_files:
|
|
53
|
+
- LICENSE
|
|
54
|
+
- README.rdoc
|
|
55
|
+
files:
|
|
56
|
+
- .document
|
|
57
|
+
- .gitignore
|
|
58
|
+
- LICENSE
|
|
59
|
+
- README.rdoc
|
|
60
|
+
- Rakefile
|
|
61
|
+
- VERSION.yml
|
|
62
|
+
- a2ws.gemspec
|
|
63
|
+
- lib/a2ws.rb
|
|
64
|
+
- lib/a2ws/base.rb
|
|
65
|
+
- lib/a2ws/image.rb
|
|
66
|
+
- lib/a2ws/image_search.rb
|
|
67
|
+
- lib/a2ws/item.rb
|
|
68
|
+
- lib/a2ws/item_search.rb
|
|
69
|
+
- lib/a2ws/methodize.rb
|
|
70
|
+
- lib/a2ws/signature.rb
|
|
71
|
+
- spec/a2ws_live_spec.rb
|
|
72
|
+
- spec/a2ws_spec.rb
|
|
73
|
+
- spec/fixtures/empty_response.yml
|
|
74
|
+
- spec/fixtures/single_item_response.yml
|
|
75
|
+
- spec/spec_helper.rb
|
|
76
|
+
- test/a2ws_test.rb
|
|
77
|
+
has_rdoc: true
|
|
78
|
+
homepage: http://github.com/handcrafted/a2ws
|
|
79
|
+
licenses:
|
|
80
|
+
post_install_message:
|
|
81
|
+
rdoc_options:
|
|
82
|
+
- --charset=UTF-8
|
|
83
|
+
require_paths:
|
|
84
|
+
- lib
|
|
85
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
86
|
+
requirements:
|
|
87
|
+
- - ">="
|
|
88
|
+
- !ruby/object:Gem::Version
|
|
89
|
+
version: "0"
|
|
90
|
+
version:
|
|
91
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
92
|
+
requirements:
|
|
93
|
+
- - ">="
|
|
94
|
+
- !ruby/object:Gem::Version
|
|
95
|
+
version: "0"
|
|
96
|
+
version:
|
|
97
|
+
requirements: []
|
|
98
|
+
|
|
99
|
+
rubyforge_project:
|
|
100
|
+
rubygems_version: 1.3.5
|
|
101
|
+
signing_key:
|
|
102
|
+
specification_version: 2
|
|
103
|
+
summary: Wrapper for Amazon Associates Web Service (A2WS).
|
|
104
|
+
test_files:
|
|
105
|
+
- spec/a2ws_live_spec.rb
|
|
106
|
+
- spec/a2ws_spec.rb
|
|
107
|
+
- spec/spec_helper.rb
|
|
108
|
+
- test/a2ws_test.rb
|