asin 0.0.8 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,2 @@
1
+ lib/*.rb
2
+ README.rdoc
@@ -0,0 +1,5 @@
1
+ html
2
+ pkg
3
+ *.gem
4
+ .DS_Store
5
+ .bundle
data/.rvmrc ADDED
@@ -0,0 +1,2 @@
1
+ rvm use 1.9.2@asin --create
2
+ rvm wrapper 1.9.2@asin textmate
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in asin.gemspec
4
+ gemspec
@@ -0,0 +1,31 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ asin (0.0.9)
5
+ crack (~> 0.1.8)
6
+ hashie (~> 0.4.0)
7
+ httpi (~> 0.7.6)
8
+
9
+ GEM
10
+ remote: http://rubygems.org/
11
+ specs:
12
+ crack (0.1.8)
13
+ hashie (0.4.0)
14
+ httpclient (2.1.5.2)
15
+ httpi (0.7.6)
16
+ rack
17
+ mocha (0.9.10)
18
+ rake
19
+ rack (1.2.1)
20
+ rake (0.8.7)
21
+
22
+ PLATFORMS
23
+ ruby
24
+
25
+ DEPENDENCIES
26
+ asin!
27
+ crack (~> 0.1.8)
28
+ hashie (~> 0.4.0)
29
+ httpclient (~> 2.1.5.2)
30
+ httpi (~> 0.7.6)
31
+ mocha (~> 0.9.10)
@@ -1,20 +1,7 @@
1
- = Introduction
2
-
3
- There is already a sophisticated amazon gem out there called ruby-aaws[http://raa.ruby-lang.org/project/ruby-aws/], but ASIN in comparison is _reaaaaaaaaaly_ easy to use!
4
-
5
- It currently just supports the _ItemLookup_ via REST but is easy to extend and understand!
6
-
7
- Have a look at the RDOC[http://rdoc.info/projects/phoet/asin] for this project, if you want further information.
8
-
9
- For more information on the REST calls, have a look at the whole Amazon E-Commerce-API[http://docs.amazonwebservices.com/AWSEcommerceService/4-0/].
10
-
11
- The code currently runs best on Ruby-1.9 due to encoding issues with the Amazon REST output (if *YOU* know how to backport this to 1.8.7, you are welcome!).
12
-
13
1
  == Installation
14
2
 
15
- The gem is tested against 1.9.1 (to be compatible with Heroku Bamboo Stack) and somewhat against 1.8.7.
3
+ The gem is tested against 1.9.2, 1.9.1 and 1.8.7 (compatibility with Heroku-Bamboo-Stack[http://docs.heroku.com/stack]) and runs smoothly with Rails 3.
16
4
 
17
- rvm use 1.9.1
18
5
  gem install asin
19
6
 
20
7
  == Usage
@@ -32,6 +19,26 @@ The gem is tested against 1.9.1 (to be compatible with Heroku Bamboo Stack) and
32
19
  item.title
33
20
  => Learn Objective-C on the Mac (Learn Series)
34
21
 
22
+ # search for any kind of stuff on amazon
23
+ items = search 'Learn Objective-C'
24
+ items.first.title
25
+ => "Learn Objective-C on the Mac (Learn Series)"
26
+
35
27
  # access the internal data representation (Hashie::Mash)
36
28
  item.raw.ItemAttributes.ListPrice.FormattedPrice
37
29
  => $39.99
30
+
31
+ == HTTPI
32
+
33
+ ASIN uses HTTPI[https://github.com/rubiii/httpi] as a HTTP-Client adapter.
34
+ You can configure the Client you like via configure:
35
+
36
+ configure :client => :curb
37
+
38
+ == Infos
39
+
40
+ Have a look at the RDOC[http://rdoc.info/projects/phoet/asin] for this project, if you want further information.
41
+
42
+ For more information on the REST calls, have a look at the whole Amazon E-Commerce-API[http://docs.amazonwebservices.com/AWSEcommerceService/4-0/].
43
+
44
+ The code currently runs best on Ruby-1.9 due to encoding issues with the Amazon REST output (if *YOU* know how to backport this to 1.8.7, you are welcome!).
@@ -0,0 +1,28 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "asin/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "asin"
7
+ s.version = Asin::VERSION
8
+ s.platform = Gem::Platform::RUBY
9
+ s.authors = ['Peter Schröder']
10
+ s.email = ['phoetmail@googlemail.com']
11
+ s.homepage = 'http://github.com/phoet/asin'
12
+ s.summary = 'Simple interface to Amazon Item lookup.'
13
+ s.description = 'Amazon Simple INterface or whatever you want to call this.'
14
+
15
+ s.rubyforge_project = "asin"
16
+
17
+ s.files = `git ls-files`.split("\n")
18
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
19
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
20
+ s.require_paths = ["lib"]
21
+
22
+ s.add_dependency('crack', '~> 0.1.8')
23
+ s.add_dependency('hashie', '~> 0.4.0')
24
+ s.add_dependency('httpi', '~> 0.7.6')
25
+
26
+ s.add_development_dependency('httpclient', '~> 2.1.5.2')
27
+ s.add_development_dependency('mocha', '~> 0.9.10')
28
+ end
@@ -1,10 +1,12 @@
1
- require 'hashie'
2
- require 'httpclient'
1
+ require 'httpi'
3
2
  require 'crack/xml'
4
3
  require 'cgi'
5
4
  require 'base64'
6
5
  require 'logger'
7
6
 
7
+ require 'asin/item'
8
+ require 'asin/version'
9
+
8
10
  # ASIN (Amazon Simple INterface) is a gem for easy access of the Amazon E-Commerce-API.
9
11
  # It is simple to configure and use. Since it's very small and flexible, it is easy to extend it to your needs.
10
12
  #
@@ -25,11 +27,18 @@ require 'logger'
25
27
  #
26
28
  # configure :secret => 'your-secret', :key => 'your-key'
27
29
  #
28
- # After configuring your environment you can call the +lookup+ method to retrieve an +Item+ via the Amazon Standard Identification Number (ASIN):
30
+ # After configuring your environment you can call the +lookup+ method to retrieve an +Item+ via the
31
+ # Amazon Standard Identification Number (ASIN):
29
32
  #
30
33
  # item = lookup '1430218150'
31
34
  # item.title
32
35
  # => "Learn Objective-C on the Mac (Learn Series)"
36
+ #
37
+ # OR search with fulltext/ASIN/ISBN
38
+ #
39
+ # items = search 'Learn Objective-C'
40
+ # items.first.title
41
+ # => "Learn Objective-C on the Mac (Learn Series)"
33
42
  #
34
43
  # The +Item+ uses a Hashie::Mash as its internal data representation and you can get fetched data from it:
35
44
  #
@@ -38,7 +47,8 @@ require 'logger'
38
47
  #
39
48
  # ==Further Configuration
40
49
  #
41
- # If you need more controll over the request that is sent to the Amazon API (http://docs.amazonwebservices.com/AWSEcommerceService/4-0/),
50
+ # If you need more controll over the request that is sent to the
51
+ # Amazon API (http://docs.amazonwebservices.com/AWSEcommerceService/4-0/),
42
52
  # you can override some defaults or add additional query-parameters to the REST calls:
43
53
  #
44
54
  # configure :host => 'webservices.amazon.de'
@@ -46,26 +56,6 @@ require 'logger'
46
56
  #
47
57
  module ASIN
48
58
 
49
- # =Item
50
- #
51
- # The +Item+ class is a wrapper for the Amazon XML-REST-Response.
52
- #
53
- # A Hashie::Mash is used for the internal data representation and can be accessed over the +raw+ attribute.
54
- #
55
- class Item
56
-
57
- attr_reader :raw
58
-
59
- def initialize(hash)
60
- @raw = Hashie::Mash.new(hash).ItemLookupResponse.Items.Item
61
- end
62
-
63
- def title
64
- @raw.ItemAttributes.Title
65
- end
66
-
67
- end
68
-
69
59
  # Configures the basic request parameters for ASIN.
70
60
  #
71
61
  # Expects at least +secret+ and +key+ for the API call:
@@ -77,6 +67,7 @@ module ASIN
77
67
  # [secret] the API secret key
78
68
  # [key] the API access key
79
69
  # [host] the host, which defaults to 'webservices.amazon.com'
70
+ # [client] the client library for http (:httpclient, :curb, :net_http) see HTTPI for more information
80
71
  # [logger] a different logger than logging to STDERR
81
72
  #
82
73
  def configure(options={})
@@ -84,6 +75,7 @@ module ASIN
84
75
  :host => 'webservices.amazon.com',
85
76
  :path => '/onca/xml',
86
77
  :digest => OpenSSL::Digest::Digest.new('sha256'),
78
+ :client => :httpclient,
87
79
  :logger => Logger.new(STDERR),
88
80
  :key => '',
89
81
  :secret => '',
@@ -106,22 +98,57 @@ module ASIN
106
98
  # lookup(asin, :ResponseGroup => :Medium)
107
99
  #
108
100
  def lookup(asin, params={})
109
- Item.new(call(params.merge(:Operation => :ItemLookup, :ItemId => asin)))
101
+ response = call(params.merge(:Operation => :ItemLookup, :ItemId => asin))
102
+ Item.new(response['ItemLookupResponse']['Items']['Item'])
103
+ end
104
+
105
+ # Performs an +ItemSearch+ REST call against the Amazon API.
106
+ #
107
+ # Expects a search-string which can be an ASIN (Amazon Standard Identification Number) and returns a list of +Items+:
108
+ #
109
+ # items = search 'Learn Objective-C'
110
+ # items.first.title
111
+ # => "Learn Objective-C on the Mac (Learn Series)"
112
+ #
113
+ # ==== Options:
114
+ #
115
+ # Additional parameters for the API call like this:
116
+ #
117
+ # search(asin, :SearchIndex => :Music)
118
+ #
119
+ # Have a look at the different search index values on the Amazon-Documentation[http://docs.amazonwebservices.com/AWSEcommerceService/4-0/]
120
+ #
121
+ def search(search_string, params={:SearchIndex => :Books})
122
+ response = call(params.merge(:Operation => :ItemSearch, :Keywords => search_string))
123
+ response['ItemSearchResponse']['Items']['Item'].map {|item| Item.new(item)}
110
124
  end
111
125
 
112
126
  private
113
127
 
114
128
  def call(params)
115
129
  raise "you have to configure ASIN: 'configure :secret => 'your-secret', :key => 'your-key''" if @options.nil?
130
+
116
131
  log(:debug, "calling with params=#{params}")
117
132
  signed = create_signed_query_string(params)
133
+
118
134
  url = "http://#{@options[:host]}#{@options[:path]}?#{signed}"
119
- log(:info, "performing rest call to url='#{url}'")
120
- resp = HTTPClient.new.get_content(url)
121
- # force utf-8 chars, works only on 1.9 string
122
- resp = resp.force_encoding('UTF-8') if resp.respond_to? :force_encoding
123
- log(:debug, "got response='#{resp}'")
124
- Crack::XML.parse(resp)
135
+ log(:info, "performing rest call to url='#{url}' with client='#{@options[:client]}'")
136
+
137
+ HTTPI::Adapter.use = @options[:client]
138
+ HTTPI.logger = @options[:logger] if @options[:logger]
139
+ request = HTTPI::Request.new(url)
140
+ response = HTTPI.get(request)
141
+
142
+ if response.code == 200
143
+ # force utf-8 chars, works only on 1.9 string
144
+ resp = response.body
145
+ resp = resp.force_encoding('UTF-8') if resp.respond_to? :force_encoding
146
+ log(:debug, "got response='#{resp}'")
147
+ Crack::XML.parse(resp)
148
+ else
149
+ log(:error, "got response='#{response.body}'")
150
+ raise "request failed with response-code='#{response.code}'"
151
+ end
125
152
  end
126
153
 
127
154
  def create_signed_query_string(params)
@@ -130,12 +157,15 @@ module ASIN
130
157
  params[:AWSAccessKeyId] = @options[:key]
131
158
  # utc timestamp needed for signing
132
159
  params[:Timestamp] = Time.now.utc.strftime('%Y-%m-%dT%H:%M:%SZ')
133
-
134
- query = params.map{|key, value| "#{key}=#{CGI.escape(value.to_s)}" }.sort.join('&')
135
-
160
+
161
+ # signing needs to order the query alphabetically
162
+ query = params.map{|key, value| "#{key}=#{CGI.escape(value.to_s)}" }.sort.join('&').gsub('+','%20')
163
+
164
+ # yeah, you really need to sign the get-request not the query
136
165
  request_to_sign = "GET\n#{@options[:host]}\n#{@options[:path]}\n#{query}"
137
166
  hmac = OpenSSL::HMAC.digest(@options[:digest], @options[:secret], request_to_sign)
138
-
167
+
168
+ # don't forget to remove the newline from base64
139
169
  signature = CGI.escape(Base64.encode64(hmac).chomp)
140
170
  "#{query}&Signature=#{signature}"
141
171
  end
@@ -0,0 +1,24 @@
1
+ require 'hashie'
2
+
3
+ module ASIN
4
+
5
+ # =Item
6
+ #
7
+ # The +Item+ class is a wrapper for the Amazon XML-REST-Response.
8
+ #
9
+ # A Hashie::Mash is used for the internal data representation and can be accessed over the +raw+ attribute.
10
+ #
11
+ class Item
12
+
13
+ attr_reader :raw
14
+
15
+ def initialize(hash)
16
+ @raw = Hashie::Mash.new(hash)
17
+ end
18
+
19
+ def title
20
+ @raw.ItemAttributes.Title
21
+ end
22
+ end
23
+
24
+ end
@@ -0,0 +1,3 @@
1
+ module Asin
2
+ VERSION = "0.1.0"
3
+ end
@@ -0,0 +1,29 @@
1
+ require "bundler"
2
+ require "rake/rdoctask"
3
+ require "rake/gempackagetask"
4
+
5
+ Bundler::GemHelper.install_tasks
6
+
7
+ spec = eval(File.new("asin.gemspec").readlines.join("\n"))
8
+
9
+ Rake::GemPackageTask.new(spec) do |pkg|
10
+ pkg.need_zip = true
11
+ pkg.need_tar = true
12
+ end
13
+
14
+ Rake::RDocTask.new(:rdoc_dev) do |rd|
15
+ rd.rdoc_files.include("lib/**/*.rb", "README.rdoc")
16
+ rd.options + ['-a', '--inline-source', '--charset=UTF-8']
17
+ end
18
+
19
+ desc "the test task"
20
+ task :test do
21
+ require 'rake/testtask'
22
+ Rake::TestTask.new do |t|
23
+ t.libs << "test"
24
+ t.ruby_opts << "-rubygems"
25
+ t.test_files = FileList['test/test_*.rb']
26
+ t.verbose = true
27
+ end
28
+ end
29
+ task :default=>:test
@@ -1,9 +1,11 @@
1
1
  require 'test_helper'
2
2
 
3
- ANY_ASIN = '1430218150'
4
-
5
3
  class TestAsin < Test::Unit::TestCase
6
4
 
5
+
6
+ ANY_ASIN = '1430218150'
7
+ ANY_SEARCH = 'Learn Objective-C'
8
+
7
9
  def setup
8
10
  @helper = Object.new
9
11
  @helper.extend ASIN
@@ -13,12 +15,24 @@ class TestAsin < Test::Unit::TestCase
13
15
  secret = ENV['ASIN_SECRET']
14
16
  key = ENV['ASIN_KEY']
15
17
  puts "configure #{secret} and #{key} for this test"
16
-
18
+
19
+ @helper.configure :secret => secret, :key => key
20
+ item = @helper.lookup(ANY_ASIN)
21
+ assert_match(/Learn Objective/, item.title)
22
+ end
23
+
24
+ def test_search_with_configured_string
25
+ secret = ENV['ASIN_SECRET']
26
+ key = ENV['ASIN_KEY']
27
+ puts "configure #{secret} and #{key} for this test"
28
+
17
29
  @helper.configure :secret => secret, :key => key
18
- p item = @helper.lookup(ANY_ASIN)
30
+ items = @helper.search(ANY_SEARCH)
31
+ assert_equal(10, items.size)
32
+ item = items.first
19
33
  assert_match(/Learn Objective/, item.title)
20
34
  end
21
-
35
+
22
36
  def test_configure_second_time_wont_get_overridden
23
37
  config = @helper.configure :something => 'wont get overridden'
24
38
  assert_not_nil(config[:something])
@@ -27,9 +41,9 @@ class TestAsin < Test::Unit::TestCase
27
41
  assert_not_nil(config[:something])
28
42
  assert_not_nil(config[:different])
29
43
  end
30
-
44
+
31
45
  def test_error_with_not_called_configure
32
46
  assert_raise(RuntimeError) { @helper.lookup ANY_ASIN }
33
47
  end
34
48
 
35
- end
49
+ end
metadata CHANGED
@@ -1,13 +1,12 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: asin
3
3
  version: !ruby/object:Gem::Version
4
- hash: 15
5
4
  prerelease: false
6
5
  segments:
7
6
  - 0
7
+ - 1
8
8
  - 0
9
- - 8
10
- version: 0.0.8
9
+ version: 0.1.0
11
10
  platform: ruby
12
11
  authors:
13
12
  - "Peter Schr\xC3\xB6der"
@@ -15,7 +14,7 @@ autorequire:
15
14
  bindir: bin
16
15
  cert_chain: []
17
16
 
18
- date: 2010-08-06 00:00:00 +02:00
17
+ date: 2011-01-04 00:00:00 +01:00
19
18
  default_executable:
20
19
  dependencies:
21
20
  - !ruby/object:Gem::Dependency
@@ -24,14 +23,13 @@ dependencies:
24
23
  requirement: &id001 !ruby/object:Gem::Requirement
25
24
  none: false
26
25
  requirements:
27
- - - ">="
26
+ - - ~>
28
27
  - !ruby/object:Gem::Version
29
- hash: 27
30
28
  segments:
31
29
  - 0
32
30
  - 1
33
- - 0
34
- version: 0.1.0
31
+ - 8
32
+ version: 0.1.8
35
33
  type: :runtime
36
34
  version_requirements: *id001
37
35
  - !ruby/object:Gem::Dependency
@@ -40,34 +38,64 @@ dependencies:
40
38
  requirement: &id002 !ruby/object:Gem::Requirement
41
39
  none: false
42
40
  requirements:
43
- - - ">="
41
+ - - ~>
44
42
  - !ruby/object:Gem::Version
45
- hash: 23
46
43
  segments:
47
44
  - 0
48
- - 2
45
+ - 4
49
46
  - 0
50
- version: 0.2.0
47
+ version: 0.4.0
51
48
  type: :runtime
52
49
  version_requirements: *id002
53
50
  - !ruby/object:Gem::Dependency
54
- name: httpclient
51
+ name: httpi
55
52
  prerelease: false
56
53
  requirement: &id003 !ruby/object:Gem::Requirement
57
54
  none: false
58
55
  requirements:
59
- - - ">="
56
+ - - ~>
60
57
  - !ruby/object:Gem::Version
61
- hash: 11
62
58
  segments:
63
- - 2
64
- - 1
65
59
  - 0
66
- version: 2.1.0
60
+ - 7
61
+ - 6
62
+ version: 0.7.6
67
63
  type: :runtime
68
64
  version_requirements: *id003
65
+ - !ruby/object:Gem::Dependency
66
+ name: httpclient
67
+ prerelease: false
68
+ requirement: &id004 !ruby/object:Gem::Requirement
69
+ none: false
70
+ requirements:
71
+ - - ~>
72
+ - !ruby/object:Gem::Version
73
+ segments:
74
+ - 2
75
+ - 1
76
+ - 5
77
+ - 2
78
+ version: 2.1.5.2
79
+ type: :development
80
+ version_requirements: *id004
81
+ - !ruby/object:Gem::Dependency
82
+ name: mocha
83
+ prerelease: false
84
+ requirement: &id005 !ruby/object:Gem::Requirement
85
+ none: false
86
+ requirements:
87
+ - - ~>
88
+ - !ruby/object:Gem::Version
89
+ segments:
90
+ - 0
91
+ - 9
92
+ - 10
93
+ version: 0.9.10
94
+ type: :development
95
+ version_requirements: *id005
69
96
  description: Amazon Simple INterface or whatever you want to call this.
70
- email: phoetmail@googlemail.com
97
+ email:
98
+ - phoetmail@googlemail.com
71
99
  executables: []
72
100
 
73
101
  extensions: []
@@ -75,8 +103,17 @@ extensions: []
75
103
  extra_rdoc_files: []
76
104
 
77
105
  files:
78
- - lib/asin.rb
106
+ - .document
107
+ - .gitignore
108
+ - .rvmrc
109
+ - Gemfile
110
+ - Gemfile.lock
79
111
  - README.rdoc
112
+ - asin.gemspec
113
+ - lib/asin.rb
114
+ - lib/asin/item.rb
115
+ - lib/asin/version.rb
116
+ - rakefile.rb
80
117
  - test/test_asin.rb
81
118
  - test/test_helper.rb
82
119
  has_rdoc: true
@@ -84,10 +121,8 @@ homepage: http://github.com/phoet/asin
84
121
  licenses: []
85
122
 
86
123
  post_install_message:
87
- rdoc_options:
88
- - -a
89
- - --inline-source
90
- - --charset=UTF-8
124
+ rdoc_options: []
125
+
91
126
  require_paths:
92
127
  - lib
93
128
  required_ruby_version: !ruby/object:Gem::Requirement
@@ -95,7 +130,6 @@ required_ruby_version: !ruby/object:Gem::Requirement
95
130
  requirements:
96
131
  - - ">="
97
132
  - !ruby/object:Gem::Version
98
- hash: 3
99
133
  segments:
100
134
  - 0
101
135
  version: "0"
@@ -104,13 +138,12 @@ required_rubygems_version: !ruby/object:Gem::Requirement
104
138
  requirements:
105
139
  - - ">="
106
140
  - !ruby/object:Gem::Version
107
- hash: 3
108
141
  segments:
109
142
  - 0
110
143
  version: "0"
111
144
  requirements: []
112
145
 
113
- rubyforge_project:
146
+ rubyforge_project: asin
114
147
  rubygems_version: 1.3.7
115
148
  signing_key:
116
149
  specification_version: 3