emporium 0.0.1
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/.gitignore +6 -0
- data/.rspec +1 -0
- data/Gemfile +4 -0
- data/README.md +30 -0
- data/Rakefile +5 -0
- data/emporium.gemspec +25 -0
- data/lib/emporium/code.rb +38 -0
- data/lib/emporium/product.rb +86 -0
- data/lib/emporium/version.rb +3 -0
- data/lib/emporium.rb +11 -0
- data/spec/emporium/emporium_spec.rb +64 -0
- data/spec/spec_helper.rb +5 -0
- metadata +99 -0
data/.gitignore
ADDED
data/.rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--color
|
data/Gemfile
ADDED
data/README.md
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
# Emporium
|
2
|
+
|
3
|
+
Automatic identification and data capture library to read UPC/EAN and get as much information as it possibly can.
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add to your Gemfile and run the `bundle` command to install it.
|
8
|
+
|
9
|
+
```ruby
|
10
|
+
gem "emporium"
|
11
|
+
```
|
12
|
+
|
13
|
+
**Requires Ruby 1.9.2 or later.**
|
14
|
+
|
15
|
+
|
16
|
+
## Usage
|
17
|
+
|
18
|
+
Given a UPC returns a product object that gets populated calling fetch. The Code class takes UPC-A or EAN digits
|
19
|
+
|
20
|
+
```ruby
|
21
|
+
require 'emporium'
|
22
|
+
|
23
|
+
product = Emporium::Product.new "066661234567"
|
24
|
+
product.use :amazon
|
25
|
+
product.fetch!
|
26
|
+
```
|
27
|
+
|
28
|
+
## Development
|
29
|
+
|
30
|
+
This gem is created by Hugo Bastien and is under the MIT License.
|
data/Rakefile
ADDED
data/emporium.gemspec
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "emporium/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "emporium"
|
7
|
+
s.version = Emporium::VERSION
|
8
|
+
s.authors = ["Hugo Bastien"]
|
9
|
+
s.email = ["hugobast@gmail.com"]
|
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 }
|
13
|
+
|
14
|
+
s.rubyforge_project = "emporium"
|
15
|
+
|
16
|
+
s.files = `git ls-files`.split("\n")
|
17
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
18
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
19
|
+
s.require_paths = ["lib"]
|
20
|
+
|
21
|
+
s.add_dependency 'nokogiri'
|
22
|
+
s.add_dependency 'ruby-hmac'
|
23
|
+
|
24
|
+
s.add_development_dependency "rspec"
|
25
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module Emporium
|
2
|
+
class Code
|
3
|
+
attr_accessor :value
|
4
|
+
|
5
|
+
def initialize(value)
|
6
|
+
@value, @check_digit, @code = value, value[-1, 1].to_i, value.chop
|
7
|
+
attach_methods!
|
8
|
+
end
|
9
|
+
|
10
|
+
def valid?
|
11
|
+
return unless (@value =~ /^[0-9]+$/) != nil
|
12
|
+
compute(@code.odds, @code.evens) == @check_digit
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
def compute(odds, evens)
|
17
|
+
# source http://en.wikipedia.org/wiki/Universal_Product_Code#Check_digits
|
18
|
+
remainder = (odds.inject(:+) * 3 + evens.inject(:+)) % 10
|
19
|
+
remainder == 0 ? remainder : 10 - remainder
|
20
|
+
end
|
21
|
+
|
22
|
+
def attach_methods!
|
23
|
+
@code.instance_eval do
|
24
|
+
def odds
|
25
|
+
self.subset(/(.).?/)
|
26
|
+
end
|
27
|
+
|
28
|
+
def evens
|
29
|
+
self.subset(/.(.)?/)
|
30
|
+
end
|
31
|
+
|
32
|
+
def subset(filter)
|
33
|
+
self.scan(filter).flatten.map{ |s| s.to_i }
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,86 @@
|
|
1
|
+
module Emporium
|
2
|
+
class Product
|
3
|
+
attr_accessor :code
|
4
|
+
|
5
|
+
def initialize(code, options={})
|
6
|
+
@code = ::Code.new(code)
|
7
|
+
raise "invalid code" unless @code.valid?
|
8
|
+
@options = options.merge! code: @code.value
|
9
|
+
end
|
10
|
+
|
11
|
+
def fetch!
|
12
|
+
if @@service == :amazon
|
13
|
+
create ::Nokogiri::XML(open("#{@@service_url}?#{signed_query}"))
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.class_option(*symbols)
|
18
|
+
symbols.each do |symbol|
|
19
|
+
class_eval(<<-EOS)
|
20
|
+
def self.#{symbol}
|
21
|
+
@@#{symbol}
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.#{symbol}=(value)
|
25
|
+
@@#{symbol} = value
|
26
|
+
end
|
27
|
+
EOS
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
class_option :access_key, :secret, :associate_tag
|
32
|
+
class_option :service, :service_url
|
33
|
+
|
34
|
+
def method_missing(name, *args)
|
35
|
+
if self.instance_variables.include? :"@#{name}"
|
36
|
+
self.instance_variable_get("@#{name}")
|
37
|
+
else
|
38
|
+
super
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
private
|
43
|
+
|
44
|
+
def create(result)
|
45
|
+
if @@service == :amazon
|
46
|
+
result.search("ItemAttributes").children.each do |value|
|
47
|
+
self.instance_variable_set("@#{value.name.downcase}", value.content)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def params
|
53
|
+
{
|
54
|
+
"Service" => "AWSECommerceService",
|
55
|
+
"Operation" => "ItemLookup",
|
56
|
+
"IdType" => "UPC",
|
57
|
+
"ItemId" => @code.value,
|
58
|
+
"SearchIndex" => @options[:search_index] || "All",
|
59
|
+
"ResponseGroup" => @options[:response_group] || "Medium",
|
60
|
+
"Version" => @options[:version] || "2011-08-01",
|
61
|
+
"AssociateTag" => @@associate_tag,
|
62
|
+
"Timestamp" => Time.now.iso8601,
|
63
|
+
"AWSAccessKeyId" => @@access_key
|
64
|
+
}
|
65
|
+
end
|
66
|
+
|
67
|
+
def to_query(hash)
|
68
|
+
hash.sort.collect { |k, v| [encode(k), encode(v.to_s)].join("=") }.join("&")
|
69
|
+
end
|
70
|
+
|
71
|
+
def signed_query
|
72
|
+
digest = HMAC::SHA256.digest(@@secret, request)
|
73
|
+
signature = Base64.encode64(digest).chomp
|
74
|
+
to_query(params.merge "Signature" => signature)
|
75
|
+
end
|
76
|
+
|
77
|
+
def encode(value)
|
78
|
+
CGI.escape(value).gsub("%7E", "~").gsub("+", "%20")
|
79
|
+
end
|
80
|
+
|
81
|
+
def request
|
82
|
+
"GET\nwebservices.amazon.com\n/onca/xml\n#{to_query(params)}"
|
83
|
+
end
|
84
|
+
|
85
|
+
end
|
86
|
+
end
|
data/lib/emporium.rb
ADDED
@@ -0,0 +1,64 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Product do
|
4
|
+
before(:each) do
|
5
|
+
Product.service = :amazon
|
6
|
+
Product.service_url = "http://webservices.amazon.com/onca/xml"
|
7
|
+
Product.access_key = CONFIG["access_key"]
|
8
|
+
Product.associate_tag = CONFIG["associate_tag"]
|
9
|
+
Product.secret = CONFIG["secret"]
|
10
|
+
end
|
11
|
+
|
12
|
+
it "uses the amazon service" do
|
13
|
+
Product.service.should be :amazon
|
14
|
+
end
|
15
|
+
|
16
|
+
describe "#new" do
|
17
|
+
it "creates an instance from a upc" do
|
18
|
+
product = Product.new("036000241457")
|
19
|
+
product.should be_an_instance_of Product
|
20
|
+
end
|
21
|
+
|
22
|
+
it "fails to create an instance if no upc is given" do
|
23
|
+
lambda { Product.new() }.should raise_error
|
24
|
+
end
|
25
|
+
|
26
|
+
it "fails to create an instance if invalid upc is given" do
|
27
|
+
lambda { Product.new("036000241452") }.should raise_error
|
28
|
+
end
|
29
|
+
|
30
|
+
it "has options in options if provided" do
|
31
|
+
product = Product.new("036000241457", secret: 'secret')
|
32
|
+
product.instance_eval { @options[:secret] }.should match 'secret'
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
describe "#fetch!" do
|
37
|
+
product = Product.new("610839331574")
|
38
|
+
|
39
|
+
it "should fetch product information" do
|
40
|
+
lambda { product.fetch! }.should_not raise_error
|
41
|
+
end
|
42
|
+
|
43
|
+
it "should create attributes for the product" do
|
44
|
+
product.fetch!
|
45
|
+
product.brand.should match 'Asus'
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
describe Code do
|
52
|
+
describe "#valid?" do
|
53
|
+
it "returns true for a valid UPC" do
|
54
|
+
code = Code.new("036000241457")
|
55
|
+
code.valid?.should be true
|
56
|
+
end
|
57
|
+
|
58
|
+
it "returns false for an invalid UPC" do
|
59
|
+
code = Code.new("036000241452")
|
60
|
+
code.valid?.should_not be true
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
data/spec/spec_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,99 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: emporium
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease:
|
5
|
+
version: 0.0.1
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Hugo Bastien
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
|
13
|
+
date: 2011-12-04 00:00:00 Z
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: nokogiri
|
17
|
+
prerelease: false
|
18
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
19
|
+
none: false
|
20
|
+
requirements:
|
21
|
+
- - ">="
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: "0"
|
24
|
+
type: :runtime
|
25
|
+
version_requirements: *id001
|
26
|
+
- !ruby/object:Gem::Dependency
|
27
|
+
name: ruby-hmac
|
28
|
+
prerelease: false
|
29
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
30
|
+
none: false
|
31
|
+
requirements:
|
32
|
+
- - ">="
|
33
|
+
- !ruby/object:Gem::Version
|
34
|
+
version: "0"
|
35
|
+
type: :runtime
|
36
|
+
version_requirements: *id002
|
37
|
+
- !ruby/object:Gem::Dependency
|
38
|
+
name: rspec
|
39
|
+
prerelease: false
|
40
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ">="
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: "0"
|
46
|
+
type: :development
|
47
|
+
version_requirements: *id003
|
48
|
+
description: "Early release, only uses amazon product advertising API "
|
49
|
+
email:
|
50
|
+
- hugobast@gmail.com
|
51
|
+
executables: []
|
52
|
+
|
53
|
+
extensions: []
|
54
|
+
|
55
|
+
extra_rdoc_files: []
|
56
|
+
|
57
|
+
files:
|
58
|
+
- .gitignore
|
59
|
+
- .rspec
|
60
|
+
- Gemfile
|
61
|
+
- README.md
|
62
|
+
- Rakefile
|
63
|
+
- emporium.gemspec
|
64
|
+
- lib/emporium.rb
|
65
|
+
- lib/emporium/code.rb
|
66
|
+
- lib/emporium/product.rb
|
67
|
+
- lib/emporium/version.rb
|
68
|
+
- spec/emporium/emporium_spec.rb
|
69
|
+
- spec/spec_helper.rb
|
70
|
+
homepage: https://github.com/hugobast/emporium
|
71
|
+
licenses: []
|
72
|
+
|
73
|
+
post_install_message:
|
74
|
+
rdoc_options: []
|
75
|
+
|
76
|
+
require_paths:
|
77
|
+
- lib
|
78
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
79
|
+
none: false
|
80
|
+
requirements:
|
81
|
+
- - ">="
|
82
|
+
- !ruby/object:Gem::Version
|
83
|
+
version: "0"
|
84
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
85
|
+
none: false
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: "0"
|
90
|
+
requirements: []
|
91
|
+
|
92
|
+
rubyforge_project: emporium
|
93
|
+
rubygems_version: 1.8.11
|
94
|
+
signing_key:
|
95
|
+
specification_version: 3
|
96
|
+
summary: Emporium fetches information about a product from it's UPC
|
97
|
+
test_files:
|
98
|
+
- spec/emporium/emporium_spec.rb
|
99
|
+
- spec/spec_helper.rb
|