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 ADDED
@@ -0,0 +1,6 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
5
+
6
+ spec/config.yml
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --color
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in supermarket.gemspec
4
+ gemspec
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
@@ -0,0 +1,5 @@
1
+ require "bundler/gem_tasks"
2
+ require 'rspec/core/rake_task'
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+ task default: :spec
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
@@ -0,0 +1,3 @@
1
+ module Emporium
2
+ VERSION = "0.0.1"
3
+ end
data/lib/emporium.rb ADDED
@@ -0,0 +1,11 @@
1
+ require "emporium/version"
2
+ require "emporium/code"
3
+ require "emporium/product"
4
+
5
+ require 'hmac'
6
+ require 'hmac-sha2'
7
+ require 'time'
8
+ require 'cgi'
9
+ require 'base64'
10
+ require 'nokogiri'
11
+ require 'open-uri'
@@ -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
+
@@ -0,0 +1,5 @@
1
+ require 'emporium'
2
+ require 'yaml'
3
+
4
+ CONFIG = YAML.load_file('./spec/config.yml')
5
+ include Emporium
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