emporium 0.0.3.alpha → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -2,6 +2,7 @@
2
2
 
3
3
  Automatic identification and data capture library to read UPC/EAN and get as much information as it possibly can.
4
4
 
5
+
5
6
  ## Installation
6
7
 
7
8
  Add to your Gemfile and run the `bundle` command to install it.
@@ -12,8 +13,11 @@ Add to your Gemfile and run the `bundle` command to install it.
12
13
 
13
14
  **Requires Ruby 1.9.2 or later.**
14
15
 
16
+
15
17
  ## Configuration
16
18
 
19
+ ### Amazon
20
+
17
21
  ```ruby
18
22
  service = Emporium::Services::Amazon.configuration do |config|
19
23
  config.access_key = "access_key"
@@ -22,6 +26,15 @@ Add to your Gemfile and run the `bundle` command to install it.
22
26
  end
23
27
  ```
24
28
 
29
+ ### Google
30
+
31
+ ```ruby
32
+ service = Emporium::Services::Google.configuration do |config|
33
+ config.access_key = "access_key"
34
+ config.cme = "cse" # custom search engine
35
+ end
36
+ ```
37
+
25
38
 
26
39
  ## Usage
27
40
 
@@ -36,7 +49,29 @@ Give it a UPC to fetch a product object. The Code only takes UPC-A digits
36
49
  ```
37
50
 
38
51
 
39
-
40
52
  ## Development
41
53
 
42
- This gem is under the MIT License.
54
+ Questions or problems? Please post them on the [issue tracker](https://github.com/hugobast/emporium/issues).
55
+
56
+ You can contribute changes by forking the project and submitting a pull request. You can ensure the tests passing by running `bundle` and `rake`. Create a yml file under the spec folder that looks like this first:
57
+
58
+ ```yaml
59
+ amazon:
60
+ secret: <secret>
61
+ access_key: <access_key>
62
+ associate_tag: <associate_tag>
63
+
64
+ google:
65
+ access_key: <access_key>
66
+ cse: <custom_search_engine>
67
+ ```
68
+
69
+ ## Licence
70
+
71
+ Copyright (c) 2011 Hugo Bastien
72
+
73
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
74
+
75
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
76
+
77
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/emporium.gemspec CHANGED
@@ -8,8 +8,8 @@ Gem::Specification.new do |s|
8
8
  s.authors = ["Hugo Bastien"]
9
9
  s.email = ["hugobast@gmail.com"]
10
10
  s.homepage = "https://github.com/hugobast/emporium"
11
- s.summary = %q{Emporium fetches information about a product from it's UPC}
12
- s.description = %q{Early release, only uses amazon product advertising API }
11
+ s.summary = %q{Emporium fetches information about a product from it's UPC (GTIN-12)}
12
+ s.description = %q{Uses Amazon's product advertising API or Google's Shopping Search API}
13
13
 
14
14
  s.rubyforge_project = "emporium"
15
15
 
@@ -20,6 +20,7 @@ Gem::Specification.new do |s|
20
20
 
21
21
  s.add_dependency 'nokogiri'
22
22
  s.add_dependency 'ruby-hmac'
23
+ s.add_dependency 'json'
23
24
 
24
25
  s.add_development_dependency "rspec"
25
26
  end
@@ -9,13 +9,22 @@ module Emporium
9
9
  end
10
10
 
11
11
  def fetch!
12
+ @service.response
12
13
  create @service.response
13
14
  end
14
15
 
15
- def use(service)
16
- @service = service.new(code: @code.value)
16
+ def use(service, options={})
17
+ options.merge!(code: @code.value)
18
+ @service = service.new(options)
17
19
  end
18
-
20
+
21
+ private
22
+ def create(hash)
23
+ hash.each do |key, value|
24
+ self.instance_variable_set("@#{key.to_s}", value)
25
+ end
26
+ end
27
+
19
28
  def method_missing(name, *args)
20
29
  if self.instance_variables.include? :"@#{name}"
21
30
  self.instance_variable_get("@#{name}")
@@ -23,12 +32,5 @@ module Emporium
23
32
  super
24
33
  end
25
34
  end
26
-
27
- private
28
- def create(response)
29
- response.search("ItemAttributes").children.each do |value|
30
- self.instance_variable_set("@#{value.name.downcase}", value.content)
31
- end
32
- end
33
35
  end
34
36
  end
@@ -1,72 +1,57 @@
1
+ require 'hmac'
2
+ require 'hmac-sha2'
3
+ require 'base64'
4
+ require 'nokogiri'
5
+
1
6
  module Emporium
2
7
  module Services
3
8
  class Amazon
9
+ include Emporium::Services::Options
10
+
11
+ service_attr_accessor :access_key, :secret, :associate_tag
12
+
4
13
  def initialize(options={})
5
14
  @options = options
6
15
  end
7
16
 
8
17
  def response
9
- res = ::Nokogiri::XML(open("http://webservices.amazon.com/onca/xml?#{signed_query}"))
10
- message = res.search('Message')
11
- raise message.children.first.content unless message.empty?
12
- res
18
+ attributes
13
19
  end
14
20
 
15
21
  private
16
- def params
17
- {
18
- "Service" => "AWSECommerceService",
19
- "Operation" => "ItemLookup",
20
- "IdType" => @options[:type] || "UPC",
21
- "ItemId" => @options[:code],
22
- "SearchIndex" => @options[:search_index] || "All",
23
- "ResponseGroup" => @options[:response_group] || "Medium",
24
- "Version" => @options[:version] || "2011-08-01",
25
- "AssociateTag" => @@associate_tag,
26
- "Timestamp" => Time.now.iso8601,
27
- "AWSAccessKeyId" => @@access_key
28
- }
29
- end
22
+ include Emporium::Services::Utilities
30
23
 
31
- def to_query(hash)
32
- hash.sort.collect { |k, v| [encode(k), encode(v.to_s)].join("=") }.join("&")
24
+ def attributes
25
+ response = ::Nokogiri::XML(open("http://webservices.amazon.com/onca/xml?#{signed_query}"))
26
+ message = response.search('Message')
27
+ raise message.children.first.content unless message.empty?
28
+ hash_from_xml response.search('ItemAttributes')
33
29
  end
34
30
 
35
31
  def signed_query
36
32
  digest = HMAC::SHA256.digest(@@secret, request)
37
33
  signature = Base64.encode64(digest).chomp
38
- to_query(params.merge "Signature" => signature)
39
- end
40
-
41
- def encode(value)
42
- CGI.escape(value).gsub("%7E", "~").gsub("+", "%20")
34
+ query(params.merge "Signature" => signature)
43
35
  end
44
36
 
45
37
  def request
46
- "GET\nwebservices.amazon.com\n/onca/xml\n#{to_query(params)}"
38
+ "GET\nwebservices.amazon.com\n/onca/xml\n#{query(params)}"
47
39
  end
48
- class << self
49
-
50
- def configuration
51
- yield self
52
- end
53
-
54
- def class_option(*symbols)
55
- symbols.each do |symbol|
56
- class_eval(<<-EOS)
57
- def self.#{symbol}
58
- @@#{symbol}
59
- end
60
40
 
61
- def self.#{symbol}=(value)
62
- @@#{symbol} = value
63
- end
64
- EOS
65
- end
66
- end
41
+ def params
42
+ {
43
+ 'Service' => 'AWSECommerceService',
44
+ 'Operation' => 'ItemLookup',
45
+ 'IdType' => @options[:type] || 'UPC',
46
+ 'ItemId' => @options[:code],
47
+ 'SearchIndex' => @options[:search_index] || 'All',
48
+ 'ResponseGroup' => @options[:response_group] || 'Medium',
49
+ 'Version' => @options[:version] || '2011-08-01',
50
+ 'AssociateTag' => @@associate_tag,
51
+ 'Timestamp' => Time.now.iso8601,
52
+ 'AWSAccessKeyId' => @@access_key
53
+ }
67
54
  end
68
-
69
- class_option :access_key, :secret, :associate_tag
70
55
  end
71
56
  end
72
57
  end
@@ -0,0 +1,45 @@
1
+ require 'json'
2
+
3
+ module Emporium
4
+ module Services
5
+ class Google
6
+ include Emporium::Services::Options
7
+ service_attr_accessor :access_key, :cse
8
+
9
+ def initialize(options={})
10
+ @options = options
11
+ end
12
+
13
+ def response
14
+ attributes
15
+ end
16
+
17
+ private
18
+ include Emporium::Services::Utilities
19
+
20
+ def attributes
21
+ response = open(request)
22
+ hash = hash_from_json(response.read)
23
+ raise message unless hash["totalItems"] > 0
24
+ hash["items"][0]["product"]
25
+ end
26
+
27
+ def message
28
+ "q=#{@options[:code]} generated no results"
29
+ end
30
+
31
+ def request
32
+ "https://www.googleapis.com/shopping/search/v1/public/products?#{query(params)}"
33
+ end
34
+
35
+ def params
36
+ {
37
+ 'q' => @options[:code],
38
+ 'alt' => @options[:alt] || 'json',
39
+ 'country' => @options[:country] || 'US',
40
+ 'key' => @@access_key
41
+ }
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,31 @@
1
+ module Emporium
2
+ module Services
3
+
4
+ module Options
5
+ def self.included(base)
6
+ base.extend ClassMethods
7
+ end
8
+
9
+ module ClassMethods
10
+ def configuration
11
+ yield self
12
+ end
13
+
14
+ def service_attr_accessor(*symbols)
15
+ symbols.each do |symbol|
16
+ class_eval(<<-EOS)
17
+ def self.#{symbol}
18
+ @@#{symbol}
19
+ end
20
+
21
+ def self.#{symbol}=(value)
22
+ @@#{symbol} = value
23
+ end
24
+ EOS
25
+ end
26
+ end
27
+ end
28
+ end
29
+
30
+ end
31
+ end
@@ -0,0 +1,29 @@
1
+ module Emporium
2
+ module Services
3
+ module Utilities
4
+ def hash_from_xml(xml)
5
+ # Only the first level elements for now
6
+
7
+ result_hash = {}
8
+ xml.children.each do |value|
9
+ result_hash[value.name.downcase.to_sym] = value.content
10
+ end
11
+ result_hash
12
+ end
13
+
14
+ def hash_from_json(json)
15
+ JSON.parse(json)
16
+ end
17
+
18
+ def query(hash)
19
+ hash.sort.collect {
20
+ |k, v| [encode(k), encode(v.to_s)].join("=")
21
+ }.join("&")
22
+ end
23
+
24
+ def encode(value)
25
+ CGI.escape(value)
26
+ end
27
+ end
28
+ end
29
+ end
@@ -1,9 +1,8 @@
1
+ require 'emporium/services/options'
2
+ require 'emporium/services/utilities'
1
3
  require 'emporium/services/amazon'
4
+ require 'emporium/services/google'
2
5
 
3
- require 'hmac'
4
- require 'hmac-sha2'
5
6
  require 'time'
6
7
  require 'cgi'
7
- require 'base64'
8
8
  require 'open-uri'
9
- require 'nokogiri'
@@ -1,3 +1,3 @@
1
1
  module Emporium
2
- VERSION = "0.0.3.alpha"
2
+ VERSION = "0.0.3"
3
3
  end
@@ -1,18 +1,18 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  Emporium::Services::Amazon.configuration do |config|
4
- config.access_key = CONFIG["access_key"]
5
- config.associate_tag = CONFIG["associate_tag"]
6
- config.secret = CONFIG["secret"]
4
+ config.access_key = AMAZON["access_key"]
5
+ config.associate_tag = AMAZON["associate_tag"]
6
+ config.secret = AMAZON["secret"]
7
+ end
8
+
9
+ Emporium::Services::Google.configuration do |config|
10
+ config.access_key = GOOGLE["access_key"]
11
+ config.cse = GOOGLE["cse"]
7
12
  end
8
13
 
9
14
  describe Emporium::Product do
10
15
  describe "#new" do
11
- it "creates an instance from a upc" do
12
- product = Emporium::Product.new("036000241457")
13
- product.should be_an_instance_of Emporium::Product
14
- end
15
-
16
16
  it "fails to create an instance if no upc is given" do
17
17
  lambda { Emporium::Product.new() }.should raise_error
18
18
  end
@@ -24,16 +24,33 @@ describe Emporium::Product do
24
24
 
25
25
  describe "#fetch!" do
26
26
  product = Emporium::Product.new("610839331574")
27
- product.use Emporium::Services::Amazon
28
27
 
29
- it "should fetch product information" do
30
- lambda { product.fetch! }.should_not raise_error
28
+ describe "using the amazon service" do
29
+ product.use Emporium::Services::Amazon
30
+
31
+ it "should fetch product information" do
32
+ lambda { product.fetch! }.should_not raise_error
33
+ end
34
+
35
+ it "should create attributes for the product" do
36
+ product.fetch!
37
+ product.brand.downcase.should match 'asus'
38
+ end
31
39
  end
32
40
 
33
- it "should create attributes for the product" do
34
- product.fetch!
35
- product.brand.should match 'Asus'
41
+ describe "using the google service" do
42
+ product.use Emporium::Services::Google
43
+
44
+ it "should fetch product information" do
45
+ lambda { product.fetch! }.should_not raise_error
46
+ end
47
+
48
+ it "should create attributes for the product" do
49
+ product.fetch!
50
+ product.brand.downcase.should match 'asus'
51
+ end
36
52
  end
53
+
37
54
  end
38
55
 
39
56
  describe "#use" do
@@ -48,20 +65,45 @@ end
48
65
  describe Emporium::Services::Amazon do
49
66
  describe "#new" do
50
67
  it "should initialize with options" do
51
- options = {some: "option"}
68
+ options = { some: "option" }
52
69
  service = Emporium::Services::Amazon.new(options)
53
70
  service.instance_variable_get('@options')[:some].should match "option"
54
71
  end
55
72
  end
56
73
 
57
74
  describe "#response" do
58
- it "should return an XML document" do
75
+ it "should return a Hash" do
59
76
  service = Emporium::Services::Amazon.new(code: "610839331574")
60
- service.response.should be_a_kind_of ::Nokogiri::XML::Document
77
+ service.response.should be_an_instance_of Hash
61
78
  end
62
79
 
63
80
  it "should raise an error if nothing is found" do
64
- lambda { Emporium::Services::Amazon.new(code: "036000241452").response }.should raise_error
81
+ lambda {
82
+ Emporium::Services::Amazon.new(code: "036000241452").response
83
+ }.should raise_error
84
+ end
85
+ end
86
+ end
87
+
88
+ describe Emporium::Services::Google do
89
+ describe "#new" do
90
+ it "should initialize with options" do
91
+ options = { some: "option" }
92
+ service = Emporium::Services::Amazon.new(options)
93
+ service.instance_variable_get('@options')[:some].should match "option"
94
+ end
95
+ end
96
+
97
+ describe "#response" do
98
+ it "should return a Hash" do
99
+ service = Emporium::Services::Google.new(code: "610839331574")
100
+ service.response.should be_an_instance_of Hash
101
+ end
102
+
103
+ it "should return an error if nothing is found" do
104
+ lambda {
105
+ service = Emporium::Services::Google.new(code: "ASjh@89a2$").response
106
+ }.should raise_error
65
107
  end
66
108
  end
67
109
  end
data/spec/spec_helper.rb CHANGED
@@ -2,3 +2,5 @@ require 'emporium'
2
2
  require 'yaml'
3
3
 
4
4
  CONFIG = YAML.load_file('./spec/config.yml')
5
+ AMAZON = CONFIG["amazon"]
6
+ GOOGLE = CONFIG["google"]
metadata CHANGED
@@ -1,8 +1,8 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: emporium
3
3
  version: !ruby/object:Gem::Version
4
- prerelease: 6
5
- version: 0.0.3.alpha
4
+ prerelease:
5
+ version: 0.0.3
6
6
  platform: ruby
7
7
  authors:
8
8
  - Hugo Bastien
@@ -10,7 +10,7 @@ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
12
 
13
- date: 2011-12-05 00:00:00 Z
13
+ date: 2011-12-08 00:00:00 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: nokogiri
@@ -35,7 +35,7 @@ dependencies:
35
35
  type: :runtime
36
36
  version_requirements: *id002
37
37
  - !ruby/object:Gem::Dependency
38
- name: rspec
38
+ name: json
39
39
  prerelease: false
40
40
  requirement: &id003 !ruby/object:Gem::Requirement
41
41
  none: false
@@ -43,9 +43,20 @@ dependencies:
43
43
  - - ">="
44
44
  - !ruby/object:Gem::Version
45
45
  version: "0"
46
- type: :development
46
+ type: :runtime
47
47
  version_requirements: *id003
48
- description: "Early release, only uses amazon product advertising API "
48
+ - !ruby/object:Gem::Dependency
49
+ name: rspec
50
+ prerelease: false
51
+ requirement: &id004 !ruby/object:Gem::Requirement
52
+ none: false
53
+ requirements:
54
+ - - ">="
55
+ - !ruby/object:Gem::Version
56
+ version: "0"
57
+ type: :development
58
+ version_requirements: *id004
59
+ description: Uses Amazon's product advertising API or Google's Shopping Search API
49
60
  email:
50
61
  - hugobast@gmail.com
51
62
  executables: []
@@ -66,6 +77,9 @@ files:
66
77
  - lib/emporium/product.rb
67
78
  - lib/emporium/services.rb
68
79
  - lib/emporium/services/amazon.rb
80
+ - lib/emporium/services/google.rb
81
+ - lib/emporium/services/options.rb
82
+ - lib/emporium/services/utilities.rb
69
83
  - lib/emporium/version.rb
70
84
  - spec/emporium/emporium_spec.rb
71
85
  - spec/spec_helper.rb
@@ -86,16 +100,16 @@ required_ruby_version: !ruby/object:Gem::Requirement
86
100
  required_rubygems_version: !ruby/object:Gem::Requirement
87
101
  none: false
88
102
  requirements:
89
- - - ">"
103
+ - - ">="
90
104
  - !ruby/object:Gem::Version
91
- version: 1.3.1
105
+ version: "0"
92
106
  requirements: []
93
107
 
94
108
  rubyforge_project: emporium
95
109
  rubygems_version: 1.8.11
96
110
  signing_key:
97
111
  specification_version: 3
98
- summary: Emporium fetches information about a product from it's UPC
112
+ summary: Emporium fetches information about a product from it's UPC (GTIN-12)
99
113
  test_files:
100
114
  - spec/emporium/emporium_spec.rb
101
115
  - spec/spec_helper.rb