indix 1.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.
- checksums.yaml +7 -0
- data/README.md +48 -0
- data/lib/indix.rb +38 -0
- data/lib/indix/brands.rb +13 -0
- data/lib/indix/categories.rb +12 -0
- data/lib/indix/config.rb +55 -0
- data/lib/indix/offers.rb +15 -0
- data/lib/indix/prices.rb +15 -0
- data/lib/indix/products.rb +65 -0
- data/lib/indix/resource.rb +64 -0
- data/lib/indix/stores.rb +13 -0
- data/lib/indix/version.rb +3 -0
- data/spec/lib/indix/brands_spec.rb +16 -0
- data/spec/lib/indix/categories_spec.rb +21 -0
- data/spec/lib/indix/config_spec.rb +21 -0
- data/spec/lib/indix/offers_spec.rb +45 -0
- data/spec/lib/indix/prices_spec.rb +21 -0
- data/spec/lib/indix/products_spec.rb +150 -0
- data/spec/lib/indix/resource_spec.rb +31 -0
- data/spec/lib/indix/stores_spec.rb +17 -0
- data/spec/spec_helper.rb +32 -0
- metadata +143 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: c30a8ec0c8134ae18fe904a480b1ff2d33dcbc9a
|
4
|
+
data.tar.gz: 844fb6b2e8a2c29fbb82ca40971c239f8f6a060a
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 6d2f71b18a055c4f60d2d34bbfc44752d332b91beef580288e1beac3fca347dfadaa52b10acbca4bf4d918c969b6f244560bf94862532ee0267ed68194452bdb
|
7
|
+
data.tar.gz: 22bbb43dc66ec2fc96a9974c72869629e80ca237132079db5bb966dba7d4cf37a81a2c5a33d485c3333df51aea2b25967b36549c61613599a3912fb840922173
|
data/README.md
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
# Indix
|
2
|
+
|
3
|
+
Offical Ruby Wrapper for Indix API
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
gem 'indix'
|
10
|
+
|
11
|
+
And then execute:
|
12
|
+
|
13
|
+
$ bundle
|
14
|
+
|
15
|
+
Or install it yourself as:
|
16
|
+
|
17
|
+
$ gem install indix
|
18
|
+
|
19
|
+
## Usage
|
20
|
+
|
21
|
+
Require the Gem:
|
22
|
+
|
23
|
+
require 'indix'
|
24
|
+
|
25
|
+
Configure Indix client with the app_id and app_key provided to you
|
26
|
+
|
27
|
+
Indix::Config.setup({:app_id => '12345', :app_key => '12345abcde'})
|
28
|
+
|
29
|
+
or
|
30
|
+
|
31
|
+
Indix::Config.app_id = '12345'
|
32
|
+
Indix::Config.app_key = '12345abcde'
|
33
|
+
|
34
|
+
Call the API endpoints
|
35
|
+
|
36
|
+
Indix::Stores.search('amazon')
|
37
|
+
Indix::Products.search(query: 'nike', store_id: 1234)
|
38
|
+
|
39
|
+
Use the response
|
40
|
+
|
41
|
+
products_response = Indix::Products.search(query: 'nike')
|
42
|
+
puts products_response.count
|
43
|
+
puts products_response.products[0].id
|
44
|
+
puts products_response.products[0].offers_count
|
45
|
+
|
46
|
+
|
47
|
+
|
48
|
+
|
data/lib/indix.rb
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'httpclient'
|
2
|
+
require 'cgi'
|
3
|
+
require 'json'
|
4
|
+
require 'hashie'
|
5
|
+
|
6
|
+
require 'indix/resource'
|
7
|
+
Dir[File.join(File.dirname(__FILE__), 'indix', '*.rb')].each { |lib| require lib }
|
8
|
+
|
9
|
+
class String
|
10
|
+
|
11
|
+
# borrowed from ActiveSupport
|
12
|
+
def underscore
|
13
|
+
word = self.dup
|
14
|
+
word.gsub!(/::/, '/')
|
15
|
+
word.gsub!(/([A-Z]+)([A-Z][a-z])/,'\1_\2')
|
16
|
+
word.gsub!(/([a-z\d])([A-Z])/,'\1_\2')
|
17
|
+
word.tr!("-", "_")
|
18
|
+
word.downcase!
|
19
|
+
word
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
class Mash < ::Hashie::Mash
|
24
|
+
|
25
|
+
# rubify keys
|
26
|
+
def convert_key(key)
|
27
|
+
key.to_s.underscore
|
28
|
+
end
|
29
|
+
|
30
|
+
def count
|
31
|
+
if self['count']
|
32
|
+
self['count']
|
33
|
+
else
|
34
|
+
super
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
data/lib/indix/brands.rb
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
module Indix
|
2
|
+
class Brands
|
3
|
+
extend Indix::Resource
|
4
|
+
|
5
|
+
# Get the brands matching the query text
|
6
|
+
#
|
7
|
+
# @param query [String]
|
8
|
+
# @return [Mash] an array containing each matching brand's Id and name
|
9
|
+
def self.search(query)
|
10
|
+
get('/brands', {:query => query})
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
data/lib/indix/config.rb
ADDED
@@ -0,0 +1,55 @@
|
|
1
|
+
module Indix
|
2
|
+
|
3
|
+
#Thrown when app_id or app_key missing
|
4
|
+
ConfigurationError = Class.new StandardError
|
5
|
+
|
6
|
+
#Thrown when the arguments passed do not confirm to pre-conditions
|
7
|
+
ArgumentError = Class.new StandardError
|
8
|
+
|
9
|
+
#Thrown when the API has received too many requests from this client in a given amount of time
|
10
|
+
LimitExceededError = Class.new StandardError
|
11
|
+
|
12
|
+
#Thrown when app_id or app_key passed are invalid
|
13
|
+
AuthenticationError = Class.new StandardError
|
14
|
+
|
15
|
+
#Thrown when the app_id/app_key is not authorized to access a resource
|
16
|
+
UnauthorizedAccessError = Class.new StandardError
|
17
|
+
|
18
|
+
module Config
|
19
|
+
|
20
|
+
module_function
|
21
|
+
|
22
|
+
# Sets the app_id
|
23
|
+
def app_id=(app_id)
|
24
|
+
@app_id = app_id
|
25
|
+
end
|
26
|
+
|
27
|
+
# Sets the app_key
|
28
|
+
def app_key=(app_key)
|
29
|
+
@app_key = app_key
|
30
|
+
end
|
31
|
+
|
32
|
+
def app_id
|
33
|
+
if @app_id
|
34
|
+
@app_id
|
35
|
+
else
|
36
|
+
raise ConfigurationError.new "Cannot complete request. Please provide app_id first"
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def app_key
|
41
|
+
if @app_key
|
42
|
+
@app_key
|
43
|
+
else
|
44
|
+
raise ConfigurationError.new "Cannot complete request. Please provide app_key first"
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
# Set app_id and app_key
|
49
|
+
def setup(options={})
|
50
|
+
options.map do |k,v|
|
51
|
+
send("#{k}=", v)
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
data/lib/indix/offers.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
module Indix
|
2
|
+
class Offers
|
3
|
+
extend Indix::Resource
|
4
|
+
|
5
|
+
# Get the offers for a product at a store
|
6
|
+
#
|
7
|
+
# @param product_id [String]
|
8
|
+
# @param store_id [Fixnum]
|
9
|
+
# @return [Mash] an object containing the count and offers array
|
10
|
+
def self.find(product_id, store_id)
|
11
|
+
request_params = {:storeId => store_id}
|
12
|
+
get("/products/#{product_id}/offers", request_params)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
data/lib/indix/prices.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
module Indix
|
2
|
+
class Prices
|
3
|
+
extend Indix::Resource
|
4
|
+
|
5
|
+
# Get the prices for a product at a store
|
6
|
+
#
|
7
|
+
# @param product_id [String]
|
8
|
+
# @param store_id [Fixnum]
|
9
|
+
# @return [Mash] an object containing a few product details like the store, brand etc and an array of prices and recorded time
|
10
|
+
def self.find(product_id, store_id)
|
11
|
+
request_params = {:storeId => store_id}
|
12
|
+
get("/products/#{product_id}/prices", request_params)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
module Indix
|
2
|
+
class Products
|
3
|
+
extend Indix::Resource
|
4
|
+
|
5
|
+
# Get the products that match the search criteria
|
6
|
+
#
|
7
|
+
# @param query [String]
|
8
|
+
# @param upc [String]
|
9
|
+
# @param mpn [String]
|
10
|
+
# @param sku [String]
|
11
|
+
# @param url [String] product URL
|
12
|
+
# @param stores [String] (Comma seperated list of store Ids)
|
13
|
+
# @param brands [String](Comma seperated list of brand Ids)
|
14
|
+
# @param category_id [Fixnum]
|
15
|
+
# @param start_price [BigDecimal]
|
16
|
+
# @param end_price [BigDecimal]
|
17
|
+
# @param availability [String] Possible values: 'IN_STOCK', 'OUT_OF_STOCK'
|
18
|
+
# @param price_history_available [Boolean]
|
19
|
+
# @param offers_count [Fixnum] Minimum number of offers the matched product should have
|
20
|
+
# @param price_change [String] Possible values: 'PRICE_INCREASED', 'PRICE_DECREASED'
|
21
|
+
# @param sort_by [String] Possible values: 'PRICE_LOW_TO_HIGH', 'PRICE_HIGH_TO_LOW', 'MOST_RECENT'
|
22
|
+
# @param page_number [Fixnum]
|
23
|
+
|
24
|
+
# @return [Mash] an object containing the count, products array and page_number
|
25
|
+
def self.search(query: nil, upc: nil, mpn: nil, sku: nil, url: nil, stores: nil, brands: nil, category_id: nil,
|
26
|
+
start_price: nil, end_price: nil, availability: nil, price_history_available: nil, offers_count: nil, price_change: nil, sort_by: nil, page_number: 1)
|
27
|
+
request_params = {}
|
28
|
+
request_params[:query] = query unless query.nil?
|
29
|
+
request_params[:upc] = upc unless upc.nil?
|
30
|
+
request_params[:mpn] = mpn unless mpn.nil?
|
31
|
+
request_params[:sku] = sku unless sku.nil?
|
32
|
+
request_params[:url] = url unless url.nil?
|
33
|
+
request_params[:storeId] = stores unless stores.nil?
|
34
|
+
request_params[:brandId] = brands unless brands.nil?
|
35
|
+
request_params[:categoryId] = category_id unless category_id.nil?
|
36
|
+
|
37
|
+
raise Indix::ArgumentError.new('Atleast one required parameter should be passed') if request_params.empty?
|
38
|
+
|
39
|
+
request_params[:startPrice] = start_price unless start_price.nil?
|
40
|
+
request_params[:endPrice] = end_price unless end_price.nil?
|
41
|
+
request_params[:availability] = availability unless availability.nil?
|
42
|
+
request_params[:priceHistoryAvailable] = price_history_available unless price_history_available.nil?
|
43
|
+
request_params[:offersCount] = offers_count unless offers_count.nil?
|
44
|
+
request_params[:priceChange] = price_change unless price_change.nil?
|
45
|
+
request_params[:sortBy] = sort_by unless sort_by.nil?
|
46
|
+
request_params[:pageNumber] = page_number
|
47
|
+
|
48
|
+
get("/products", request_params)
|
49
|
+
end
|
50
|
+
|
51
|
+
# Get the details of a product
|
52
|
+
#
|
53
|
+
# @param product_id [String]
|
54
|
+
# @param view [Fixnum] (Optional) Possible values: 'offers', 'offers_catalog' and 'catalog'
|
55
|
+
# @params page_number [Fixnum] Use to paginate through the offers array
|
56
|
+
#
|
57
|
+
# @return [Mash] an object containing the product details like the store, brand etc and an array of offers (presence depends on the view type) and page_number
|
58
|
+
def self.find(id, view: nil, page_number: 1)
|
59
|
+
request_params = {}
|
60
|
+
request_params[:view] = view unless view.nil?
|
61
|
+
request_params[:pageNumber] = page_number
|
62
|
+
get("/products/#{id}", request_params)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
require 'httpclient'
|
2
|
+
require 'json'
|
3
|
+
require 'cgi'
|
4
|
+
|
5
|
+
module Indix
|
6
|
+
module Resource
|
7
|
+
|
8
|
+
def base_uri
|
9
|
+
@base_uri ||= 'https://api.indix.com/v1'
|
10
|
+
end
|
11
|
+
|
12
|
+
def client
|
13
|
+
@client ||= HTTPClient.new
|
14
|
+
end
|
15
|
+
|
16
|
+
def get(path, params = {})
|
17
|
+
params[:app_id] = Indix::Config.app_id
|
18
|
+
params[:app_key] = Indix::Config.app_key
|
19
|
+
|
20
|
+
# no need to escape params as httpclient does it anyways
|
21
|
+
target = base_uri + path
|
22
|
+
client.ssl_config.verify_mode = OpenSSL::SSL::VERIFY_NONE
|
23
|
+
response = client.get(target, :query => params)
|
24
|
+
if response.status == 200
|
25
|
+
content = JSON.parse(response.content)
|
26
|
+
data = content["response"]
|
27
|
+
data = to_hashie(data)
|
28
|
+
elsif response.status == 401
|
29
|
+
raise AuthenticationError.new('Cannot complete request. Authentication failed. Please provide a valid app_id and app_key')
|
30
|
+
elsif response.status == 402
|
31
|
+
raise UnauthorizedAccessError.new('Cannot complete request. Not authorized to access this resource')
|
32
|
+
elsif response.status == 429
|
33
|
+
raise LimitExceededError.new('Too many requests')
|
34
|
+
else
|
35
|
+
raise StandardError.new('Cannot complete request. Response Code: ' + response.status.to_s + ' Response Body: ' + response.content)
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
|
40
|
+
private
|
41
|
+
|
42
|
+
def to_hashie(json)
|
43
|
+
if json.is_a? Array
|
44
|
+
json.collect! { |x| x.is_a?(Hash) ? Mash.new(x) : x }
|
45
|
+
else
|
46
|
+
Mash.new(json)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def can_escape(value)
|
51
|
+
case value
|
52
|
+
when Fixnum
|
53
|
+
return false
|
54
|
+
when TrueClass
|
55
|
+
return false
|
56
|
+
when FalseClass
|
57
|
+
return false
|
58
|
+
end
|
59
|
+
true
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
|
data/lib/indix/stores.rb
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
module Indix
|
2
|
+
class Stores
|
3
|
+
extend Indix::Resource
|
4
|
+
|
5
|
+
# Get the stores matching the query text
|
6
|
+
#
|
7
|
+
# @param query [String]
|
8
|
+
# @return [Mash] an array containing each matching store's Id and name
|
9
|
+
def self.search(query)
|
10
|
+
get('/stores', {:query => query})
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Indix::Brands do
|
4
|
+
|
5
|
+
describe "Brands Search API" do
|
6
|
+
it "must succeed when valid parameters are passed" do
|
7
|
+
HTTPClient.any_instance.stubs(:get).with('https://api.indix.com/v1/brands', {:query => {:app_id=>'12345', :app_key=>'12345abcde', :query => 'wal'}}).returns(mock_response('brands'))
|
8
|
+
Indix::Config.setup({:app_id => '12345', :app_key => '12345abcde'})
|
9
|
+
brands = Indix::Brands.search('wal')
|
10
|
+
brands.length.must_equal 10
|
11
|
+
brands[0].id.must_equal "6715"
|
12
|
+
brands[0].name.must_equal "Walgreens"
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Indix::Categories do
|
4
|
+
|
5
|
+
describe "Categories export API" do
|
6
|
+
it "must succeed when valid parameters are passed" do
|
7
|
+
HTTPClient.any_instance.stubs(:get).with('https://api.indix.com/v1/categories', {:query => {:app_id=>'12345', :app_key=>'12345abcde'}}).returns(mock_response('categories'))
|
8
|
+
|
9
|
+
Indix::Config.setup({:app_id => '12345', :app_key => '12345abcde'})
|
10
|
+
categories = Indix::Categories.all
|
11
|
+
categories.length.must_equal 9
|
12
|
+
categories[0].id.must_equal 10001
|
13
|
+
categories[0].name.must_equal "Apparel"
|
14
|
+
categories[6].id.must_equal 10019
|
15
|
+
categories[6].name.must_equal "Home Care"
|
16
|
+
categories[6].name_path.must_equal "Grocery, Health & Personal Care > Home Care"
|
17
|
+
categories[6].id_path.must_equal "10018 > 10019"
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Indix::Config do
|
4
|
+
|
5
|
+
describe "Request to Indix API" do
|
6
|
+
it "must fail when no app_id or app_key is configured" do
|
7
|
+
Indix::Config.app_id = nil
|
8
|
+
Indix::Config.app_key = nil
|
9
|
+
lambda {Indix::Brands.search('wal')}.must_raise Indix::ConfigurationError
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
describe "Indix API configuration" do
|
14
|
+
it "must be properly setup" do
|
15
|
+
Indix::Config.setup({:app_id => 'abc12345', :app_key => 'abcd1234567890'})
|
16
|
+
Indix::Config.app_id.must_equal 'abc12345'
|
17
|
+
Indix::Config.app_key.must_equal 'abcd1234567890'
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Indix::Offers do
|
4
|
+
describe "Store Offers API" do
|
5
|
+
it "must return proper response when a valid product_id and store_id are passed" do
|
6
|
+
HTTPClient.any_instance.stubs(:get).with('https://api.indix.com/v1/products/01aec3dc861c642805cb4be5784e2521/offers', {:query => {:app_id=>'12345', :app_key=>'12345abcde', :storeId => 57}}).returns(mock_response('offers'))
|
7
|
+
|
8
|
+
Indix::Config.setup({:app_id => '12345', :app_key => '12345abcde'})
|
9
|
+
store_offer_response = Indix::Offers.find('01aec3dc861c642805cb4be5784e2521', 57)
|
10
|
+
store_offer_response.count.must_equal 1
|
11
|
+
store_offer_response.offers.count.must_equal 1
|
12
|
+
store_offer_response.offers[0].id.must_equal '01aec3dc861c642805cb4be5784e2521'
|
13
|
+
store_offer_response.offers[0].title.must_equal 'Nike Revolution 2 Wolf Grey/Cool Grey/Volt/Black'
|
14
|
+
store_offer_response.offers[0].store_id.must_equal 57
|
15
|
+
store_offer_response.offers[0].store_name.must_equal 'Zappos.com'
|
16
|
+
store_offer_response.offers[0].brand_id.must_equal 5572
|
17
|
+
store_offer_response.offers[0].brand_name.must_equal 'Nike'
|
18
|
+
store_offer_response.offers[0].product_url.must_equal 'http://www.zappos.com/nike-revolution-2-dark-grey-cool-grey-total-crimson-hyper-blue'
|
19
|
+
store_offer_response.offers[0].image_url.must_equal 'http://www.zappos.com/images/z/2/0/8/4/1/6/2084160-p-DETAILED.jpg'
|
20
|
+
store_offer_response.offers[0].category_id_path.must_equal '10003 > 11200 > 11211'
|
21
|
+
store_offer_response.offers[0].category_name_path.must_equal 'Shoes & Accessories > Shoes > Men\'s Shoes'
|
22
|
+
store_offer_response.offers[0].upc.must_equal 'NA'
|
23
|
+
store_offer_response.offers[0].sku.must_equal '8064765'
|
24
|
+
store_offer_response.offers[0].mpn.must_equal 'NA'
|
25
|
+
store_offer_response.offers[0].price.list_price.must_equal 55
|
26
|
+
store_offer_response.offers[0].price.sale_price.must_equal 55
|
27
|
+
store_offer_response.offers[0].cart_price.must_equal false
|
28
|
+
store_offer_response.offers[0].last_recorded_at.must_equal 1399287717330
|
29
|
+
store_offer_response.offers[0].price_history_available.must_equal true
|
30
|
+
store_offer_response.offers[0].availability.must_equal 'In Stock'
|
31
|
+
store_offer_response.offers[0].buy_box_winner.must_equal false
|
32
|
+
store_offer_response.offers[0].add_on_item.must_equal false
|
33
|
+
store_offer_response.offers[0].new_offers.must_equal 0
|
34
|
+
store_offer_response.offers[0].used_offers.must_equal 0
|
35
|
+
store_offer_response.offers[0].refurbished_offers.must_equal 0
|
36
|
+
store_offer_response.offers[0].user_ratings.must_equal 0
|
37
|
+
store_offer_response.offers[0].average_rating.must_equal 0
|
38
|
+
store_offer_response.offers[0].max_rating.must_equal 0
|
39
|
+
store_offer_response.offers[0].sales_rank.must_equal 0
|
40
|
+
store_offer_response.offers[0].tags.count.must_equal 15
|
41
|
+
store_offer_response.offers[0].tags[0].must_equal 'nike'
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Indix::Prices do
|
4
|
+
describe "Price History API" do
|
5
|
+
it "must return proper response when a valid product_id and store_id are passed" do
|
6
|
+
HTTPClient.any_instance.stubs(:get).with('https://api.indix.com/v1/products/01aec3dc861c642805cb4be5784e2521/prices', {:query => {:app_id=>'12345', :app_key=>'12345abcde', :storeId => 57}}).returns(mock_response('prices'))
|
7
|
+
|
8
|
+
Indix::Config.setup({:app_id => '12345', :app_key => '12345abcde'})
|
9
|
+
price_history_response = Indix::Prices.find('01aec3dc861c642805cb4be5784e2521', 57)
|
10
|
+
price_history_response.id.must_equal '01aec3dc861c642805cb4be5784e2521'
|
11
|
+
price_history_response.store_id.must_equal 57
|
12
|
+
price_history_response.brand_id.must_equal 5572
|
13
|
+
price_history_response.category_id.must_equal 11211
|
14
|
+
price_history_response.price_history.count.must_equal 8
|
15
|
+
price_history_response.price_history[0].sale_price.must_equal 55
|
16
|
+
price_history_response.price_history[0].list_price.must_equal 55
|
17
|
+
price_history_response.price_history[0].recorded_at.must_equal 1398729599999
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
@@ -0,0 +1,150 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Indix::Products do
|
4
|
+
|
5
|
+
describe "Products Search API" do
|
6
|
+
it "must fail when no required parameters are passed" do
|
7
|
+
lambda {Indix::Products.search()}.must_raise Indix::ArgumentError
|
8
|
+
end
|
9
|
+
|
10
|
+
it "must return proper response when a valid query is passed" do
|
11
|
+
HTTPClient.any_instance.stubs(:get).with('https://api.indix.com/v1/products', {:query => {:app_id=>'12345', :app_key=>'12345abcde', :query => 'nike', :pageNumber => 1}}).returns(mock_response('products'))
|
12
|
+
|
13
|
+
Indix::Config.setup({:app_id => '12345', :app_key => '12345abcde'})
|
14
|
+
products_response = Indix::Products.search(query: 'nike')
|
15
|
+
products_response.count.must_equal 2010
|
16
|
+
products_response.products.length.must_equal 10
|
17
|
+
products_response.products[0].id.must_equal '01aec3dc861c642805cb4be5784e2521'
|
18
|
+
products_response.products[0].title.must_equal 'Nike Revolution 2 Wolf Grey/Cool Grey/Volt/Black'
|
19
|
+
products_response.products[0].brand_id.must_equal 5572
|
20
|
+
products_response.products[0].brand_name.must_equal 'Nike'
|
21
|
+
products_response.products[0].image_url.must_equal 'http://www.zappos.com/images/z/2/0/8/4/1/6/2084160-p-DETAILED.jpg'
|
22
|
+
products_response.products[0].category_id_path.must_equal '10003 > 11200 > 11211'
|
23
|
+
products_response.products[0].category_name_path.must_equal 'Shoes & Accessories > Shoes > Men\'s Shoes'
|
24
|
+
products_response.products[0].upc.must_equal 'NA'
|
25
|
+
products_response.products[0].mpn.must_equal 'NA'
|
26
|
+
products_response.products[0].store_count.must_equal 1
|
27
|
+
products_response.products[0].offers_count.must_equal 1
|
28
|
+
products_response.products[0].offers_price_range.must_equal '55.0-55.0'
|
29
|
+
end
|
30
|
+
|
31
|
+
it "must return proper response when a valid upc is passed" do
|
32
|
+
HTTPClient.any_instance.stubs(:get).with('https://api.indix.com/v1/products', {:query => {:app_id=>'12345', :app_key=>'12345abcde', :upc => 81732301143, :pageNumber => 1}}).returns(mock_response('products'))
|
33
|
+
|
34
|
+
Indix::Config.setup({:app_id => '12345', :app_key => '12345abcde'})
|
35
|
+
products_response = Indix::Products.search(upc: 81732301143)
|
36
|
+
products_response.count.must_equal 2010
|
37
|
+
products_response.products.length.must_equal 10
|
38
|
+
end
|
39
|
+
|
40
|
+
it "must return proper response when a valid sku is passed" do
|
41
|
+
HTTPClient.any_instance.stubs(:get).with('https://api.indix.com/v1/products', {:query => {:app_id=>'12345', :app_key=>'12345abcde', :sku => 486053, :pageNumber => 1}}).returns(mock_response('products'))
|
42
|
+
|
43
|
+
Indix::Config.setup({:app_id => '12345', :app_key => '12345abcde'})
|
44
|
+
products_response = Indix::Products.search(sku: 486053)
|
45
|
+
products_response.count.must_equal 2010
|
46
|
+
products_response.products.length.must_equal 10
|
47
|
+
end
|
48
|
+
|
49
|
+
it "must return proper response when a valid mpn is passed" do
|
50
|
+
HTTPClient.any_instance.stubs(:get).with('https://api.indix.com/v1/products', {:query => {:app_id=>'12345', :app_key=>'12345abcde', :mpn => '5217TZG', :pageNumber => 1}}).returns(mock_response('products'))
|
51
|
+
|
52
|
+
Indix::Config.setup({:app_id => '12345', :app_key => '12345abcde'})
|
53
|
+
products_response = Indix::Products.search(mpn: '5217TZG')
|
54
|
+
products_response.count.must_equal 2010
|
55
|
+
products_response.products.length.must_equal 10
|
56
|
+
end
|
57
|
+
|
58
|
+
it "must return proper response when valid store_id, brand_id and category_id are passed" do
|
59
|
+
HTTPClient.any_instance.stubs(:get).with('https://api.indix.com/v1/products', {:query => {:app_id=>'12345', :app_key=>'12345abcde', :storeId => 123, :brandId => 234, :categoryId => 345, :pageNumber => 1}}).returns(mock_response('products'))
|
60
|
+
|
61
|
+
Indix::Config.setup({:app_id => '12345', :app_key => '12345abcde'})
|
62
|
+
products_response = Indix::Products.search(stores: 123, brands: 234, category_id: 345)
|
63
|
+
products_response.count.must_equal 2010
|
64
|
+
products_response.products.length.must_equal 10
|
65
|
+
end
|
66
|
+
|
67
|
+
it "must return proper response when valid store_id, price_change, price_history_available and availability are passed" do
|
68
|
+
HTTPClient.any_instance.stubs(:get).with('https://api.indix.com/v1/products', {:query => {:app_id=>'12345', :app_key=>'12345abcde', :storeId => 123, :priceChange => 'PRICE_DECREASED', :availability => 'IN_STOCK', :priceHistoryAvailable => true, :pageNumber => 1}}).returns(mock_response('products'))
|
69
|
+
|
70
|
+
Indix::Config.setup({:app_id => '12345', :app_key => '12345abcde'})
|
71
|
+
products_response = Indix::Products.search(stores: 123, price_change: 'PRICE_DECREASED', availability: 'IN_STOCK', price_history_available: true)
|
72
|
+
products_response.count.must_equal 2010
|
73
|
+
products_response.products.length.must_equal 10
|
74
|
+
end
|
75
|
+
|
76
|
+
it "must return proper response when valid query, start_price, end_rice, sort_by and page_number are passed" do
|
77
|
+
HTTPClient.any_instance.stubs(:get).with('https://api.indix.com/v1/products', {:query => {:app_id=>'12345', :app_key=>'12345abcde', :query => 'nike', :startPrice => 100, :endPrice => 200, :sortBy => 'PRICE_LOW_TO_HIGH', :pageNumber => 2}}).returns(mock_response('products'))
|
78
|
+
|
79
|
+
Indix::Config.setup({:app_id => '12345', :app_key => '12345abcde'})
|
80
|
+
products_response = Indix::Products.search(query: 'nike', start_price: 100, end_price: 200, sort_by: 'PRICE_LOW_TO_HIGH', page_number: 2)
|
81
|
+
products_response.count.must_equal 2010
|
82
|
+
products_response.products.length.must_equal 10
|
83
|
+
end
|
84
|
+
|
85
|
+
it "must return proper response when valid url and offers_count are passed" do
|
86
|
+
HTTPClient.any_instance.stubs(:get).with('https://api.indix.com/v1/products', {:query => {:app_id=>'12345', :app_key=>'12345abcde', :url => 'www.google.com', :offersCount => 5, :pageNumber => 1}}).returns(mock_response('products'))
|
87
|
+
|
88
|
+
Indix::Config.setup({:app_id => '12345', :app_key => '12345abcde'})
|
89
|
+
products_response = Indix::Products.search(url: 'www.google.com', offers_count: 5)
|
90
|
+
products_response.count.must_equal 2010
|
91
|
+
products_response.products.length.must_equal 10
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
describe "Products Details API" do
|
96
|
+
it "must return proper response when a valid product_id is passed" do
|
97
|
+
HTTPClient.any_instance.stubs(:get).with('https://api.indix.com/v1/products/12345', {:query => {:app_id=>'12345', :app_key=>'12345abcde', :pageNumber => 1}}).returns(mock_response('product'))
|
98
|
+
|
99
|
+
Indix::Config.setup({:app_id => '12345', :app_key => '12345abcde'})
|
100
|
+
product = Indix::Products.find(12345)
|
101
|
+
product.id.must_equal '01aec3dc861c642805cb4be5784e2521'
|
102
|
+
product.title.must_equal 'Nike Revolution 2 Wolf Grey/Cool Grey/Volt/Black'
|
103
|
+
product.brand_id.must_equal 5572
|
104
|
+
product.brand_name.must_equal 'Nike'
|
105
|
+
product.image_url.must_equal 'http://www.zappos.com/images/z/2/0/8/4/1/6/2084160-p-DETAILED.jpg'
|
106
|
+
product.category_id_path.must_equal '10003 > 11200 > 11211'
|
107
|
+
product.category_name_path.must_equal 'Shoes & Accessories > Shoes > Men\'s Shoes'
|
108
|
+
product.upc.must_equal 'NA'
|
109
|
+
product.offers_count.must_equal 1
|
110
|
+
product.offers.count.must_equal 1
|
111
|
+
product.offers[0].id.must_equal '01aec3dc861c642805cb4be5784e2521'
|
112
|
+
product.offers[0].title.must_equal 'Nike Revolution 2 Wolf Grey/Cool Grey/Volt/Black'
|
113
|
+
product.offers[0].store_id.must_equal 57
|
114
|
+
product.offers[0].store_name.must_equal 'Zappos.com'
|
115
|
+
product.offers[0].product_url.must_equal 'http://www.zappos.com/nike-revolution-2-dark-grey-cool-grey-total-crimson-hyper-blue'
|
116
|
+
product.offers[0].image_url.must_equal 'http://www.zappos.com/images/z/2/0/8/4/1/6/2084160-p-DETAILED.jpg'
|
117
|
+
product.offers[0].sku.must_equal '8064765'
|
118
|
+
product.offers[0].mpn.must_equal 'NA'
|
119
|
+
product.offers[0].last_recorded_at.must_equal 1399287717330
|
120
|
+
product.offers[0].tags.count.must_equal 15
|
121
|
+
product.offers[0].tags[0].must_equal 'nike'
|
122
|
+
product.offers[0].price.list_price.must_equal 55
|
123
|
+
product.offers[0].price.sale_price.must_equal 55
|
124
|
+
product.offers[0].cart_price.must_equal false
|
125
|
+
product.offers[0].price_history_available.must_equal true
|
126
|
+
product.offers[0].availability.must_equal 'In Stock'
|
127
|
+
product.offers[0].buy_box_winner.must_equal false
|
128
|
+
product.offers[0].add_on_item.must_equal false
|
129
|
+
product.offers[0].new_offers.must_equal 0
|
130
|
+
product.offers[0].used_offers.must_equal 0
|
131
|
+
product.offers[0].refurbished_offers.must_equal 0
|
132
|
+
product.offers[0].user_ratings.must_equal 0
|
133
|
+
product.offers[0].average_rating.must_equal 0
|
134
|
+
product.offers[0].max_rating.must_equal 0
|
135
|
+
product.offers[0].sales_rank.must_equal 0
|
136
|
+
product.offers[0].attributes.count.must_equal 8
|
137
|
+
product.offers[0].attributes.keys[0].must_equal 'liningmaterial'
|
138
|
+
product.offers[0].attributes[:liningmaterial].must_equal 'Fabric'
|
139
|
+
end
|
140
|
+
|
141
|
+
it "must return proper response when a valid product_id, view and page_number are passed" do
|
142
|
+
HTTPClient.any_instance.stubs(:get).with('https://api.indix.com/v1/products/12345', {:query => {:app_id=>'12345', :app_key=>'12345abcde', :view => 'offers', :pageNumber => 2}}).returns(mock_response('product'))
|
143
|
+
|
144
|
+
Indix::Config.setup({:app_id => '12345', :app_key => '12345abcde'})
|
145
|
+
product = Indix::Products.find(12345, view: 'offers', page_number: 2)
|
146
|
+
product.id.must_equal '01aec3dc861c642805cb4be5784e2521'
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Indix::Resource do
|
4
|
+
|
5
|
+
before do
|
6
|
+
@object = Object.new
|
7
|
+
@object.extend(Indix::Resource)
|
8
|
+
end
|
9
|
+
|
10
|
+
it "must throw AuthenticationError when the API returns 401" do
|
11
|
+
HTTPClient.any_instance.stubs(:get).with('https://api.indix.com/v1/categories', {:query => {:app_id=>'12345', :app_key=>'12345abcde'}}).returns(mock_authentication_error_response())
|
12
|
+
|
13
|
+
Indix::Config.setup({:app_id => '12345', :app_key => '12345abcde'})
|
14
|
+
lambda {Indix::Categories.all}.must_raise Indix::AuthenticationError
|
15
|
+
end
|
16
|
+
|
17
|
+
it "must throw LimitExceededError when the API returns 429" do
|
18
|
+
HTTPClient.any_instance.stubs(:get).with('https://api.indix.com/v1/categories', {:query => {:app_id=>'12345', :app_key=>'12345abcde'}}).returns(mock_limit_exceeded_response())
|
19
|
+
|
20
|
+
Indix::Config.setup({:app_id => '12345', :app_key => '12345abcde'})
|
21
|
+
lambda {Indix::Categories.all}.must_raise Indix::LimitExceededError
|
22
|
+
end
|
23
|
+
|
24
|
+
it "must throw UnauthorizedAccessError when the API returns 402" do
|
25
|
+
HTTPClient.any_instance.stubs(:get).with('https://api.indix.com/v1/categories', {:query => {:app_id=>'12345', :app_key=>'12345abcde'}}).returns(mock_unauthorized_response())
|
26
|
+
|
27
|
+
Indix::Config.setup({:app_id => '12345', :app_key => '12345abcde'})
|
28
|
+
lambda {Indix::Categories.all}.must_raise Indix::UnauthorizedAccessError
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Indix::Stores do
|
4
|
+
|
5
|
+
describe "Stores Search API" do
|
6
|
+
it "must succeed when valid parameters are passed" do
|
7
|
+
HTTPClient.any_instance.stubs(:get).with('https://api.indix.com/v1/stores', {:query => {:app_id=>'12345', :app_key=>'12345abcde', :query => 'wal'}}).returns(mock_response('stores'))
|
8
|
+
|
9
|
+
Indix::Config.setup({:app_id => '12345', :app_key => '12345abcde'})
|
10
|
+
stores = Indix::Stores.search('wal')
|
11
|
+
stores.length.must_equal 5
|
12
|
+
stores[2].id.must_equal "95"
|
13
|
+
stores[2].name.must_equal "Walgreens"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'indix'
|
2
|
+
require 'minitest/spec'
|
3
|
+
require 'minitest/autorun'
|
4
|
+
require 'httpclient'
|
5
|
+
require 'mocha/mini_test'
|
6
|
+
|
7
|
+
def fixture_path
|
8
|
+
@path ||= File.expand_path('../fixtures', __FILE__)
|
9
|
+
end
|
10
|
+
|
11
|
+
def mock_response(request_type)
|
12
|
+
content = File.read(File.open(fixture_path + '/' + request_type + '.json'))
|
13
|
+
http_message = HTTP::Message.new_response(content)
|
14
|
+
end
|
15
|
+
|
16
|
+
def mock_authentication_error_response
|
17
|
+
http_message = HTTP::Message.new_response('{"status":401,"message":"Authentication error"')
|
18
|
+
http_message.status = 401
|
19
|
+
http_message
|
20
|
+
end
|
21
|
+
|
22
|
+
def mock_limit_exceeded_response
|
23
|
+
http_message = HTTP::Message.new_response('{"status":429,"message":"Too many requests"')
|
24
|
+
http_message.status = 429
|
25
|
+
http_message
|
26
|
+
end
|
27
|
+
|
28
|
+
def mock_unauthorized_response
|
29
|
+
http_message = HTTP::Message.new_response('{"status":402,"message":"Unauthorized"')
|
30
|
+
http_message.status = 402
|
31
|
+
http_message
|
32
|
+
end
|
metadata
ADDED
@@ -0,0 +1,143 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: indix
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: '1.0'
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- indix
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-05-28 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ~>
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.5'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ~>
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.5'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - '>='
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - '>='
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: mocha
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - '>='
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: httpclient
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ~>
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 2.3.4.1
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ~>
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: 2.3.4.1
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: hashie
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ~>
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: 2.0.5
|
76
|
+
type: :runtime
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ~>
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: 2.0.5
|
83
|
+
description: Official Ruby wrapper for Indix API
|
84
|
+
email:
|
85
|
+
- support@indix.com
|
86
|
+
executables: []
|
87
|
+
extensions: []
|
88
|
+
extra_rdoc_files: []
|
89
|
+
files:
|
90
|
+
- README.md
|
91
|
+
- lib/indix.rb
|
92
|
+
- lib/indix/brands.rb
|
93
|
+
- lib/indix/prices.rb
|
94
|
+
- lib/indix/version.rb
|
95
|
+
- lib/indix/config.rb
|
96
|
+
- lib/indix/offers.rb
|
97
|
+
- lib/indix/categories.rb
|
98
|
+
- lib/indix/products.rb
|
99
|
+
- lib/indix/resource.rb
|
100
|
+
- lib/indix/stores.rb
|
101
|
+
- spec/lib/indix/categories_spec.rb
|
102
|
+
- spec/lib/indix/prices_spec.rb
|
103
|
+
- spec/lib/indix/config_spec.rb
|
104
|
+
- spec/lib/indix/stores_spec.rb
|
105
|
+
- spec/lib/indix/products_spec.rb
|
106
|
+
- spec/lib/indix/offers_spec.rb
|
107
|
+
- spec/lib/indix/resource_spec.rb
|
108
|
+
- spec/lib/indix/brands_spec.rb
|
109
|
+
- spec/spec_helper.rb
|
110
|
+
homepage: http://www.indix.com
|
111
|
+
licenses: []
|
112
|
+
metadata: {}
|
113
|
+
post_install_message:
|
114
|
+
rdoc_options: []
|
115
|
+
require_paths:
|
116
|
+
- lib
|
117
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
118
|
+
requirements:
|
119
|
+
- - '>='
|
120
|
+
- !ruby/object:Gem::Version
|
121
|
+
version: '0'
|
122
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
123
|
+
requirements:
|
124
|
+
- - '>='
|
125
|
+
- !ruby/object:Gem::Version
|
126
|
+
version: '0'
|
127
|
+
requirements: []
|
128
|
+
rubyforge_project:
|
129
|
+
rubygems_version: 2.1.9
|
130
|
+
signing_key:
|
131
|
+
specification_version: 4
|
132
|
+
summary: Official Ruby wrapper for Indix API
|
133
|
+
test_files:
|
134
|
+
- spec/lib/indix/categories_spec.rb
|
135
|
+
- spec/lib/indix/prices_spec.rb
|
136
|
+
- spec/lib/indix/config_spec.rb
|
137
|
+
- spec/lib/indix/stores_spec.rb
|
138
|
+
- spec/lib/indix/products_spec.rb
|
139
|
+
- spec/lib/indix/offers_spec.rb
|
140
|
+
- spec/lib/indix/resource_spec.rb
|
141
|
+
- spec/lib/indix/brands_spec.rb
|
142
|
+
- spec/spec_helper.rb
|
143
|
+
has_rdoc:
|