asin 0.1.0 → 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/Gemfile.lock CHANGED
@@ -1,23 +1,35 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- asin (0.0.9)
4
+ asin (0.2.0)
5
5
  crack (~> 0.1.8)
6
- hashie (~> 0.4.0)
7
- httpi (~> 0.7.6)
6
+ hashie (~> 1.0.0)
7
+ httpi (~> 0.7.9)
8
8
 
9
9
  GEM
10
10
  remote: http://rubygems.org/
11
11
  specs:
12
12
  crack (0.1.8)
13
- hashie (0.4.0)
14
- httpclient (2.1.5.2)
15
- httpi (0.7.6)
13
+ diff-lcs (1.1.2)
14
+ fuubar (0.0.3)
15
+ rspec (~> 2.0)
16
+ rspec-instafail (~> 0.1.4)
17
+ ruby-progressbar (~> 0.0.9)
18
+ hashie (1.0.0)
19
+ httpclient (2.1.6.1)
20
+ httpi (0.7.9)
16
21
  rack
17
- mocha (0.9.10)
18
- rake
19
22
  rack (1.2.1)
20
- rake (0.8.7)
23
+ rspec (2.4.0)
24
+ rspec-core (~> 2.4.0)
25
+ rspec-expectations (~> 2.4.0)
26
+ rspec-mocks (~> 2.4.0)
27
+ rspec-core (2.4.0)
28
+ rspec-expectations (2.4.0)
29
+ diff-lcs (~> 1.1.2)
30
+ rspec-instafail (0.1.5)
31
+ rspec-mocks (2.4.0)
32
+ ruby-progressbar (0.0.9)
21
33
 
22
34
  PLATFORMS
23
35
  ruby
@@ -25,7 +37,8 @@ PLATFORMS
25
37
  DEPENDENCIES
26
38
  asin!
27
39
  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)
40
+ fuubar (~> 0.0.3)
41
+ hashie (~> 1.0.0)
42
+ httpclient (~> 2.1.6.1)
43
+ httpi (~> 0.7.9)
44
+ rspec (~> 2.4.0)
data/README.rdoc CHANGED
@@ -1,19 +1,37 @@
1
1
  == Installation
2
2
 
3
+ Status: http://stillmaintained.com/phoet/asin.png
4
+
3
5
  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.
4
6
 
5
7
  gem install asin
6
8
 
7
- == Usage
9
+ == Configuration
10
+
11
+ Since Version 0.2.0 ASIN provides a Rails-Style configuration.
12
+
13
+ You can put this in a initializer (config/initializers/asin.rb):
14
+
15
+ ASIN::Configuration.configure do |config|
16
+ config.secret = 'your-secret'
17
+ config.key = 'your-key'
18
+ end
19
+
20
+ The old configuration syntax is still valid:
8
21
 
9
22
  require 'asin'
10
23
  include ASIN
11
24
 
12
25
  # use the configure method to setup your api credentials
13
26
  configure :secret => 'your-secret', :key => 'your-key'
14
-
27
+
28
+ == Usage
29
+
30
+ # create an ASIN client
31
+ client = ASIN.client
32
+
15
33
  # lookup an item with the amazon standard identification number (asin)
16
- item = lookup '1430218150'
34
+ item = client.lookup '1430218150'
17
35
 
18
36
  # have a look at the title of the item
19
37
  item.title
@@ -31,9 +49,10 @@ The gem is tested against 1.9.2, 1.9.1 and 1.8.7 (compatibility with Heroku-Bamb
31
49
  == HTTPI
32
50
 
33
51
  ASIN uses HTTPI[https://github.com/rubiii/httpi] as a HTTP-Client adapter.
34
- You can configure the Client you like via configure:
52
+ See the HTTPI documentation for how to configure different clients or the logger.
53
+ As a default HTTPI uses _httpclient_ so you should add that dependency to your project:
35
54
 
36
- configure :client => :curb
55
+ gem 'httpclient'
37
56
 
38
57
  == Infos
39
58
 
@@ -42,3 +61,4 @@ Have a look at the RDOC[http://rdoc.info/projects/phoet/asin] for this project,
42
61
  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
62
 
44
63
  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!).
64
+
data/asin.gemspec CHANGED
@@ -4,7 +4,7 @@ require "asin/version"
4
4
 
5
5
  Gem::Specification.new do |s|
6
6
  s.name = "asin"
7
- s.version = Asin::VERSION
7
+ s.version = ASIN::VERSION
8
8
  s.platform = Gem::Platform::RUBY
9
9
  s.authors = ['Peter Schröder']
10
10
  s.email = ['phoetmail@googlemail.com']
@@ -20,9 +20,10 @@ Gem::Specification.new do |s|
20
20
  s.require_paths = ["lib"]
21
21
 
22
22
  s.add_dependency('crack', '~> 0.1.8')
23
- s.add_dependency('hashie', '~> 0.4.0')
24
- s.add_dependency('httpi', '~> 0.7.6')
23
+ s.add_dependency('hashie', '~> 1.0.0')
24
+ s.add_dependency('httpi', '~> 0.7.9')
25
25
 
26
- s.add_development_dependency('httpclient', '~> 2.1.5.2')
27
- s.add_development_dependency('mocha', '~> 0.9.10')
26
+ s.add_development_dependency('httpclient', '~> 2.1.6.1')
27
+ s.add_development_dependency('rspec', '~> 2.4.0')
28
+ s.add_development_dependency('fuubar', '~> 0.0.3')
28
29
  end
data/lib/asin.rb CHANGED
@@ -6,6 +6,7 @@ require 'logger'
6
6
 
7
7
  require 'asin/item'
8
8
  require 'asin/version'
9
+ require 'asin/configuration'
9
10
 
10
11
  # ASIN (Amazon Simple INterface) is a gem for easy access of the Amazon E-Commerce-API.
11
12
  # It is simple to configure and use. Since it's very small and flexible, it is easy to extend it to your needs.
@@ -55,6 +56,19 @@ require 'asin/version'
55
56
  # lookup(asin, :ResponseGroup => :Medium)
56
57
  #
57
58
  module ASIN
59
+
60
+ DIGEST = OpenSSL::Digest::Digest.new('sha256')
61
+ PATH = '/onca/xml'
62
+
63
+ # Convenience method to create an ASIN client.
64
+ #
65
+ # A client is not necessary though, you can simply include the ASIN module otherwise.
66
+ #
67
+ def self.client
68
+ client = Object.new
69
+ client.extend ASIN
70
+ client
71
+ end
58
72
 
59
73
  # Configures the basic request parameters for ASIN.
60
74
  #
@@ -62,25 +76,10 @@ module ASIN
62
76
  #
63
77
  # configure :secret => 'your-secret', :key => 'your-key'
64
78
  #
65
- # ==== Options:
66
- #
67
- # [secret] the API secret key
68
- # [key] the API access key
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
71
- # [logger] a different logger than logging to STDERR
79
+ # See ASIN::Configuration for more infos.
72
80
  #
73
81
  def configure(options={})
74
- @options = {
75
- :host => 'webservices.amazon.com',
76
- :path => '/onca/xml',
77
- :digest => OpenSSL::Digest::Digest.new('sha256'),
78
- :client => :httpclient,
79
- :logger => Logger.new(STDERR),
80
- :key => '',
81
- :secret => '',
82
- } if @options.nil?
83
- @options.merge! options
82
+ Configuration.configure(options)
84
83
  end
85
84
 
86
85
  # Performs an +ItemLookup+ REST call against the Amazon API.
@@ -125,20 +124,20 @@ module ASIN
125
124
 
126
125
  private
127
126
 
127
+ def credentials_valid?
128
+ !Configuration.secret.nil? && !Configuration.key.nil?
129
+ end
130
+
128
131
  def call(params)
129
- raise "you have to configure ASIN: 'configure :secret => 'your-secret', :key => 'your-key''" if @options.nil?
132
+ raise "you have to configure ASIN: 'configure :secret => 'your-secret', :key => 'your-key''" unless credentials_valid?
130
133
 
131
134
  log(:debug, "calling with params=#{params}")
132
135
  signed = create_signed_query_string(params)
133
136
 
134
- url = "http://#{@options[:host]}#{@options[:path]}?#{signed}"
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
-
137
+ url = "http://#{Configuration.host}#{PATH}?#{signed}"
138
+ log(:info, "performing rest call to url='#{url}'")
139
+
140
+ response = HTTPI.get(url)
142
141
  if response.code == 200
143
142
  # force utf-8 chars, works only on 1.9 string
144
143
  resp = response.body
@@ -154,7 +153,7 @@ module ASIN
154
153
  def create_signed_query_string(params)
155
154
  # nice tutorial http://cloudcarpenters.com/blog/amazon_products_api_request_signing/
156
155
  params[:Service] = :AWSECommerceService
157
- params[:AWSAccessKeyId] = @options[:key]
156
+ params[:AWSAccessKeyId] = Configuration.key
158
157
  # utc timestamp needed for signing
159
158
  params[:Timestamp] = Time.now.utc.strftime('%Y-%m-%dT%H:%M:%SZ')
160
159
 
@@ -162,8 +161,8 @@ module ASIN
162
161
  query = params.map{|key, value| "#{key}=#{CGI.escape(value.to_s)}" }.sort.join('&').gsub('+','%20')
163
162
 
164
163
  # yeah, you really need to sign the get-request not the query
165
- request_to_sign = "GET\n#{@options[:host]}\n#{@options[:path]}\n#{query}"
166
- hmac = OpenSSL::HMAC.digest(@options[:digest], @options[:secret], request_to_sign)
164
+ request_to_sign = "GET\n#{Configuration.host}\n#{PATH}\n#{query}"
165
+ hmac = OpenSSL::HMAC.digest(DIGEST, Configuration.secret, request_to_sign)
167
166
 
168
167
  # don't forget to remove the newline from base64
169
168
  signature = CGI.escape(Base64.encode64(hmac).chomp)
@@ -171,7 +170,8 @@ module ASIN
171
170
  end
172
171
 
173
172
  def log(severity, message)
174
- @options[:logger].send severity, message if @options[:logger]
173
+ Configuration.logger.send severity, message if Configuration.logger
175
174
  end
176
175
 
177
- end
176
+ end
177
+
@@ -0,0 +1,52 @@
1
+ module ASIN
2
+ class Configuration
3
+ class << self
4
+
5
+ attr_accessor :secret, :key, :host, :logger
6
+
7
+ # Rails initializer configuration.
8
+ #
9
+ # Expects at least +secret+ and +key+ for the API call:
10
+ #
11
+ # ASIN::Configuration.configure do |config|
12
+ # config.secret = 'your-secret'
13
+ # config.key = 'your-key'
14
+ # end
15
+ #
16
+ # You may pass options as a hash as well:
17
+ #
18
+ # ASIN::Configuration.configure(:secret => 'your-secret', :key => 'your-key')
19
+ #
20
+ # ==== Options:
21
+ #
22
+ # [secret] the API secret key
23
+ # [key] the API access key
24
+ # [host] the host, which defaults to 'webservices.amazon.com'
25
+ # [logger] a different logger than logging to STDERR (nil for no logging)
26
+ #
27
+ def configure(options={})
28
+ init_config
29
+ if block_given?
30
+ yield self
31
+ else
32
+ options.each do |key, value|
33
+ send(:"#{key}=", value)
34
+ end
35
+ end
36
+ self
37
+ end
38
+
39
+ private
40
+
41
+ def init_config(force=false)
42
+ return if @init && !force
43
+ @init = true
44
+ @secret = ''
45
+ @key = ''
46
+ @host = 'webservices.amazon.com'
47
+ @logger = Logger.new(STDERR)
48
+ end
49
+ end
50
+ end
51
+ end
52
+
data/lib/asin/version.rb CHANGED
@@ -1,3 +1,3 @@
1
- module Asin
2
- VERSION = "0.1.0"
1
+ module ASIN
2
+ VERSION = "0.2.0"
3
3
  end
data/rakefile.rb CHANGED
@@ -1,6 +1,12 @@
1
1
  require "bundler"
2
2
  require "rake/rdoctask"
3
3
  require "rake/gempackagetask"
4
+ require 'rspec/core/rake_task'
5
+
6
+ RSpec::Core::RakeTask.new do |t|
7
+ t.rspec_opts = ["--format Fuubar", "--color", "-r ./spec/spec_helper.rb"]
8
+ t.pattern = 'spec/**/*_spec.rb'
9
+ end
4
10
 
5
11
  Bundler::GemHelper.install_tasks
6
12
 
data/spec/asin_spec.rb ADDED
@@ -0,0 +1,58 @@
1
+ ANY_ASIN = '1430218150'
2
+ ANY_SEARCH = 'Learn Objective-C'
3
+
4
+ describe ASIN do
5
+ before do
6
+ @helper = ASIN.client
7
+ @helper.configure :logger => nil
8
+
9
+ @secret = ENV['ASIN_SECRET']
10
+ @key = ENV['ASIN_KEY']
11
+ puts "configure #{@secret} and #{@key} for this test"
12
+ end
13
+
14
+ context "configuration" do
15
+ it "should fail without secret and key" do
16
+ lambda { @helper.lookup ANY_ASIN }.should raise_error(RuntimeError)
17
+ end
18
+
19
+ it "should fail with wrong configuration key" do
20
+ lambda { @helper.configure :wrong => 'key' }.should raise_error(NoMethodError)
21
+ end
22
+
23
+ it "should not override the configuration" do
24
+ config = @helper.configure :key => 'wont get overridden'
25
+ config.key.should_not be_nil
26
+
27
+ config = @helper.configure :secret => 'is also set'
28
+ config.key.should_not be_nil
29
+ config.secret.should_not be_nil
30
+ end
31
+
32
+ it "should work with a configuration block" do
33
+ config = ASIN::Configuration.configure do |config|
34
+ config.key = 'bla'
35
+ end
36
+ config.key.should eql('bla')
37
+ end
38
+ end
39
+
40
+ context "lookup and search" do
41
+ before do
42
+ @helper.configure :secret => @secret, :key => @key
43
+ end
44
+
45
+ it "should lookup a book" do
46
+ item = @helper.lookup(ANY_ASIN)
47
+ item.title.should =~ /Learn Objective/
48
+ end
49
+
50
+ it "should search a book with fulltext" do
51
+ items = @helper.search(ANY_SEARCH)
52
+ items.should have(10).things
53
+
54
+ items.first.title.should =~ /Learn Objective/
55
+ end
56
+ end
57
+ end
58
+
@@ -0,0 +1,7 @@
1
+ $:.unshift File.join(File.dirname(__FILE__),'..','..','lib')
2
+ require 'rspec'
3
+ require 'asin'
4
+
5
+ Rspec.configure do |c|
6
+ c.mock_with :rspec
7
+ end
metadata CHANGED
@@ -4,9 +4,9 @@ version: !ruby/object:Gem::Version
4
4
  prerelease: false
5
5
  segments:
6
6
  - 0
7
- - 1
7
+ - 2
8
8
  - 0
9
- version: 0.1.0
9
+ version: 0.2.0
10
10
  platform: ruby
11
11
  authors:
12
12
  - "Peter Schr\xC3\xB6der"
@@ -14,7 +14,7 @@ autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
16
 
17
- date: 2011-01-04 00:00:00 +01:00
17
+ date: 2011-01-30 00:00:00 +01:00
18
18
  default_executable:
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
@@ -41,10 +41,10 @@ dependencies:
41
41
  - - ~>
42
42
  - !ruby/object:Gem::Version
43
43
  segments:
44
+ - 1
44
45
  - 0
45
- - 4
46
46
  - 0
47
- version: 0.4.0
47
+ version: 1.0.0
48
48
  type: :runtime
49
49
  version_requirements: *id002
50
50
  - !ruby/object:Gem::Dependency
@@ -58,8 +58,8 @@ dependencies:
58
58
  segments:
59
59
  - 0
60
60
  - 7
61
- - 6
62
- version: 0.7.6
61
+ - 9
62
+ version: 0.7.9
63
63
  type: :runtime
64
64
  version_requirements: *id003
65
65
  - !ruby/object:Gem::Dependency
@@ -73,13 +73,13 @@ dependencies:
73
73
  segments:
74
74
  - 2
75
75
  - 1
76
- - 5
77
- - 2
78
- version: 2.1.5.2
76
+ - 6
77
+ - 1
78
+ version: 2.1.6.1
79
79
  type: :development
80
80
  version_requirements: *id004
81
81
  - !ruby/object:Gem::Dependency
82
- name: mocha
82
+ name: rspec
83
83
  prerelease: false
84
84
  requirement: &id005 !ruby/object:Gem::Requirement
85
85
  none: false
@@ -87,12 +87,27 @@ dependencies:
87
87
  - - ~>
88
88
  - !ruby/object:Gem::Version
89
89
  segments:
90
+ - 2
91
+ - 4
90
92
  - 0
91
- - 9
92
- - 10
93
- version: 0.9.10
93
+ version: 2.4.0
94
94
  type: :development
95
95
  version_requirements: *id005
96
+ - !ruby/object:Gem::Dependency
97
+ name: fuubar
98
+ prerelease: false
99
+ requirement: &id006 !ruby/object:Gem::Requirement
100
+ none: false
101
+ requirements:
102
+ - - ~>
103
+ - !ruby/object:Gem::Version
104
+ segments:
105
+ - 0
106
+ - 0
107
+ - 3
108
+ version: 0.0.3
109
+ type: :development
110
+ version_requirements: *id006
96
111
  description: Amazon Simple INterface or whatever you want to call this.
97
112
  email:
98
113
  - phoetmail@googlemail.com
@@ -111,11 +126,12 @@ files:
111
126
  - README.rdoc
112
127
  - asin.gemspec
113
128
  - lib/asin.rb
129
+ - lib/asin/configuration.rb
114
130
  - lib/asin/item.rb
115
131
  - lib/asin/version.rb
116
132
  - rakefile.rb
117
- - test/test_asin.rb
118
- - test/test_helper.rb
133
+ - spec/asin_spec.rb
134
+ - spec/spec_helper.rb
119
135
  has_rdoc: true
120
136
  homepage: http://github.com/phoet/asin
121
137
  licenses: []
@@ -149,5 +165,5 @@ signing_key:
149
165
  specification_version: 3
150
166
  summary: Simple interface to Amazon Item lookup.
151
167
  test_files:
152
- - test/test_asin.rb
153
- - test/test_helper.rb
168
+ - spec/asin_spec.rb
169
+ - spec/spec_helper.rb
data/test/test_asin.rb DELETED
@@ -1,49 +0,0 @@
1
- require 'test_helper'
2
-
3
- class TestAsin < Test::Unit::TestCase
4
-
5
-
6
- ANY_ASIN = '1430218150'
7
- ANY_SEARCH = 'Learn Objective-C'
8
-
9
- def setup
10
- @helper = Object.new
11
- @helper.extend ASIN
12
- end
13
-
14
- def test_lookup_with_configured_asin
15
- secret = ENV['ASIN_SECRET']
16
- key = ENV['ASIN_KEY']
17
- puts "configure #{secret} and #{key} for this test"
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
-
29
- @helper.configure :secret => secret, :key => key
30
- items = @helper.search(ANY_SEARCH)
31
- assert_equal(10, items.size)
32
- item = items.first
33
- assert_match(/Learn Objective/, item.title)
34
- end
35
-
36
- def test_configure_second_time_wont_get_overridden
37
- config = @helper.configure :something => 'wont get overridden'
38
- assert_not_nil(config[:something])
39
-
40
- config = @helper.configure :different => 'is also set'
41
- assert_not_nil(config[:something])
42
- assert_not_nil(config[:different])
43
- end
44
-
45
- def test_error_with_not_called_configure
46
- assert_raise(RuntimeError) { @helper.lookup ANY_ASIN }
47
- end
48
-
49
- end
data/test/test_helper.rb DELETED
@@ -1,5 +0,0 @@
1
- $:.unshift File.join(File.dirname(__FILE__),'..','..','lib')
2
-
3
- require 'test/unit'
4
- require 'mocha'
5
- require 'asin'