Skip to content

Commit

Permalink
add rails initializer configuration style
Browse files Browse the repository at this point in the history
  • Loading branch information
phoet committed Jan 27, 2011
1 parent 4d68a07 commit dfc17d2
Show file tree
Hide file tree
Showing 3 changed files with 78 additions and 20 deletions.
29 changes: 14 additions & 15 deletions lib/asin.rb
Expand Up @@ -6,6 +6,7 @@

require 'asin/item'
require 'asin/version'
require 'asin/configuration'

# ASIN (Amazon Simple INterface) is a gem for easy access of the Amazon E-Commerce-API.
# It is simple to configure and use. Since it's very small and flexible, it is easy to extend it to your needs.
Expand Down Expand Up @@ -73,13 +74,7 @@ module ASIN
# [logger] a different logger than logging to STDERR
#
def configure(options={})
@options = {
:secret => '',
:key => '',
:host => 'webservices.amazon.com',
:logger => Logger.new(STDERR),
} if @options.nil?
@options.merge! options
Configuration.configure(options)
end

# Performs an +ItemLookup+ REST call against the Amazon API.
Expand Down Expand Up @@ -124,14 +119,18 @@ def search(search_string, params={:SearchIndex => :Books})

private

def credentials_valid?
!Configuration.secret.nil? && !Configuration.key.nil?
end

def call(params)
raise "you have to configure ASIN: 'configure :secret => 'your-secret', :key => 'your-key''" if @options.nil?
raise "you have to configure ASIN: 'configure :secret => 'your-secret', :key => 'your-key''" unless credentials_valid?

log(:debug, "calling with params=#{params}")
signed = create_signed_query_string(params)

url = "http://#{@options[:host]}#{PATH}?#{signed}"
log(:info, "performing rest call to url='#{url}' with client='#{@options[:client]}'")
url = "http://#{Configuration.host}#{PATH}?#{signed}"
log(:info, "performing rest call to url='#{url}'")

response = HTTPI.get(url)
if response.code == 200
Expand All @@ -149,24 +148,24 @@ def call(params)
def create_signed_query_string(params)
# nice tutorial http://cloudcarpenters.com/blog/amazon_products_api_request_signing/
params[:Service] = :AWSECommerceService
params[:AWSAccessKeyId] = @options[:key]
params[:AWSAccessKeyId] = Configuration.key
# utc timestamp needed for signing
params[:Timestamp] = Time.now.utc.strftime('%Y-%m-%dT%H:%M:%SZ')

# signing needs to order the query alphabetically
query = params.map{|key, value| "#{key}=#{CGI.escape(value.to_s)}" }.sort.join('&').gsub('+','%20')

# yeah, you really need to sign the get-request not the query
request_to_sign = "GET\n#{@options[:host]}\n#{PATH}\n#{query}"
hmac = OpenSSL::HMAC.digest(DIGEST, @options[:secret], request_to_sign)
request_to_sign = "GET\n#{Configuration.host}\n#{PATH}\n#{query}"
hmac = OpenSSL::HMAC.digest(DIGEST, Configuration.secret, request_to_sign)

# don't forget to remove the newline from base64
signature = CGI.escape(Base64.encode64(hmac).chomp)
"#{query}&Signature=#{signature}"
end

def log(severity, message)
@options[:logger].send severity, message if @options[:logger]
Configuration.logger.send severity, message if Configuration.logger
end

end
end
48 changes: 48 additions & 0 deletions lib/asin/configuration.rb
@@ -0,0 +1,48 @@
module ASIN
class Configuration
class << self

attr_accessor :secret, :key, :host, :logger

# Rails initializer configuration.
#
# Expects at least +secret+ and +key+ for the API call:
#
# ASIN::Configuration.configure do |config|
# config.secret = 'your-secret'
# config.key = 'your-key'
# end
#
# ==== Options:
#
# [secret] the API secret key
# [key] the API access key
# [host] the host, which defaults to 'webservices.amazon.com'
# [logger] a different logger than logging to STDERR
#
def configure(options={})
init_config
if block_given?
yield self
else
options.each do |key, value|
send(:"#{key}=", value)
end
end
self
end

private

def init_config(force=false)
return if @init && !force
@init = true
@secret = ''
@key = ''
@host = 'webservices.amazon.com'
@logger = Logger.new(STDERR)
end
end
end
end

21 changes: 16 additions & 5 deletions spec/asin_spec.rb
Expand Up @@ -16,14 +16,25 @@
it "should fail without secret and key" do
lambda { @helper.lookup ANY_ASIN }.should raise_error(RuntimeError)
end

it "should fail with wrong configuration key" do
lambda { @helper.configure :wrong => 'key' }.should raise_error(NoMethodError)
end

it "should not override the configuration" do
config = @helper.configure :something => 'wont get overridden'
config[:something].should_not be_nil
config = @helper.configure :key => 'wont get overridden'
config.key.should_not be_nil

config = @helper.configure :secret => 'is also set'
config.key.should_not be_nil
config.secret.should_not be_nil
end

config = @helper.configure :different => 'is also set'
config[:something].should_not be_nil
config[:different].should_not be_nil
it "should work with a configuration block" do
config = ASIN::Configuration.configure do |config|
config.key = 'bla'
end
config.key.should eql('bla')
end
end

Expand Down

0 comments on commit dfc17d2

Please sign in to comment.