bestbuy_api 0.1.0 → 1.0.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d5f754a396c74d1b261ee6a128194d3ac2edc688621ba22b31963dd9611d7597
4
- data.tar.gz: 962ade249e82c4cfa4592da1d928ead4c4a4b5efcd156f080b51078cc353a091
3
+ metadata.gz: 30fe2e8e4bea5f47e2b7914ab5503254caad2b44196d2f78a1ce80a141cadbaa
4
+ data.tar.gz: 1748654ec2820ffec00ad63ecb5a9e4c4cfbd4831d0c662b61a1b526e8e288cb
5
5
  SHA512:
6
- metadata.gz: ab324760e5daefe668c269db7a3ca8f80e3c81bd4927832c3b0231f1230e94514ba955298237fe68d1f115474fae7a31a79cbf253ca3f87759fbed8dc8e40dcb
7
- data.tar.gz: 7cdfb22fc14a3ec62788955b467a21cfeab9f983a35c93626b37e408f8bd0aa9e13bcfcb4184d943d76095bb47ef5464737786156c766d576d5ad5d68695fd77
6
+ metadata.gz: a03f206f578e31ebf60120de11a6753aafdc78f884dd0f17dca2caaa11857ed3a125f6e68e2d098bbaf49f1a085cb8f470b3ab547c91be08f0344866b12d9c35
7
+ data.tar.gz: cb3fd58846fb529926735e7259808b12e6305f0a1f5127bbef81d91deda0fa312b1e581322b89999d82a6de674d6b43b5e913227f2256a702ef80359d21a8778
@@ -0,0 +1,3 @@
1
+ detectors:
2
+ UtilityFunction:
3
+ public_methods_only: true
@@ -1,4 +1,6 @@
1
1
  Metrics/LineLength:
2
2
  Max: 120
3
3
  Metrics/BlockLength:
4
- Max: 150
4
+ Max: 150
5
+ Style/Documentation:
6
+ Enabled: false
data/README.md CHANGED
@@ -1,5 +1,7 @@
1
1
  # Best Buy API
2
2
 
3
+ [![Build Status](https://travis-ci.org/mbayucot/bestbuy_api.svg?branch=master)](https://travis-ci.org/mbayucot/bestbuy_api)
4
+
3
5
  A Ruby wrapper for the [Best Buy developer API](https://developer.bestbuy.com/).
4
6
 
5
7
  ## Installation
@@ -3,8 +3,6 @@ require 'bestbuy_api/product'
3
3
  require 'bestbuy_api/store'
4
4
  require 'bestbuy_api/category'
5
5
 
6
- # Handles BestBuy api queries. Documentation is located at
7
- # https://bestbuyapis.github.io/api-documentation.
8
6
  module BestbuyApi
9
7
  class << self
10
8
  attr_accessor :api_key
@@ -4,13 +4,11 @@ module BestbuyApi
4
4
  # Defines the attributes for the categories api. Documentation is
5
5
  # located at https://bestbuyapis.github.io/api-documentation/#categories-api.
6
6
  class Category < Model
7
- PATH = 'categories'.freeze
7
+ path 'categories'
8
8
 
9
- ATTRIBUTES = {
10
- id: { search: true },
11
- name: { search: true },
12
- subcategory_id: { kw: 'subCategories.id' },
13
- subcategory_name: { kw: 'subCategories.name' }
14
- }.freeze
9
+ attribute :id, search: true
10
+ attribute :name, search: true
11
+ attribute :subcategory_id, field: 'subCategories.id'
12
+ attribute :subcategory_name, field: 'subCategories.name'
15
13
  end
16
14
  end
@@ -1,10 +1,11 @@
1
+ require_relative 'params'
2
+ require_relative 'request'
1
3
  require 'forwardable'
2
4
 
3
5
  module BestbuyApi
4
- # Collect the parameters and validates the attributes
5
6
  class Criteria
6
7
  extend Forwardable
7
- def_delegators :request, :items, :pagination, :url
8
+ def_delegators :response, :items, :pagination, :url
8
9
 
9
10
  def initialize(klass)
10
11
  @klass = klass
@@ -15,18 +16,14 @@ module BestbuyApi
15
16
  end
16
17
 
17
18
  def select(args)
18
- # Check on attributes that are readable
19
- attributes = @klass::ATTRIBUTES.select { |_k, v| v.key?(:read) ? v[:read] : true }
20
- args.each { |k, _v| assert_keys(attributes.keys, k) }
19
+ assert_keys(args, @klass.attributes[:read])
21
20
 
22
21
  criteria[:attributes] = args
23
22
  self
24
23
  end
25
24
 
26
25
  def where(args)
27
- # Check on attributes that are searchable
28
- attributes = @klass::ATTRIBUTES.select { |_k, v| v.key?(:search) && v[:search] }
29
- args.each { |k, _v| assert_keys(attributes.keys, k) }
26
+ assert_keys(args, @klass.attributes[:search])
30
27
 
31
28
  criteria[:conditions].merge!(args)
32
29
  self
@@ -42,17 +39,26 @@ module BestbuyApi
42
39
  self
43
40
  end
44
41
 
45
- private
46
-
47
- def request
48
- @request ||= BestbuyApi::Request.new(@klass::PATH, @klass::ATTRIBUTES, criteria)
42
+ def response
43
+ params = Params.new(criteria, @klass.attributes)
44
+ request.find(params.structure)
49
45
  end
50
46
 
51
- def assert_keys(valid_keys, key)
52
- return true if valid_keys.include?(key)
47
+ private
53
48
 
54
- raise MissingAttributeError, "Unknown attribute: #{key.inspect}. Valid attributes are: " \
49
+ def assert_keys(args, attributes)
50
+ valid_keys = attributes.keys
51
+ args.each do |key, _v|
52
+ unless valid_keys.include?(key)
53
+ raise MissingAttributeError, "Unknown attribute: #{key.inspect}. Valid attributes are: " \
55
54
  "#{valid_keys.map(&:inspect).join(', ')}"
55
+ end
56
+ end
57
+ end
58
+
59
+ def request
60
+ api_key = BestbuyApi.config.api_key
61
+ @request ||= Request.new(api_key, @klass.attributes[:path])
56
62
  end
57
63
  end
58
64
  end
@@ -1,8 +1,21 @@
1
1
  require_relative 'criteria'
2
2
 
3
3
  module BestbuyApi
4
- # Chains method calls to build up queries
5
4
  class Model
5
+ def self.attributes
6
+ @attributes ||= { path: nil, read: {}, search: {} }
7
+ end
8
+
9
+ def self.path(path = nil)
10
+ attributes[:path] = path
11
+ end
12
+
13
+ def self.attribute(id, columns = { search: false, read: true })
14
+ row = { id => columns }
15
+ attributes[:read].merge!(row) unless columns[:read] == false
16
+ attributes[:search].merge!(row) unless columns[:search] == false
17
+ end
18
+
6
19
  def self.select(*args)
7
20
  Criteria.new(self).select(args.uniq)
8
21
  end
@@ -0,0 +1,53 @@
1
+ module BestbuyApi
2
+ class Params
3
+ def initialize(criteria, attributes)
4
+ @criteria = criteria
5
+ @attributes = attributes
6
+ end
7
+
8
+ def structure
9
+ { slug: build_filters, query: build_response_options }
10
+ end
11
+
12
+ private
13
+
14
+ def build_filters
15
+ collection = collect_search
16
+ collection.empty? ? '' : query_string(collection)
17
+ end
18
+
19
+ def build_response_options
20
+ query = @criteria.slice(:limit, :page)
21
+ query[:show] = collect_read
22
+ query
23
+ end
24
+
25
+ def collect_read
26
+ Array[@criteria[:attributes].map do |key|
27
+ elements = @attributes[:read]
28
+ if elements.key?(key)
29
+ attribute = elements[key]
30
+ attribute.key?(:field) ? attribute[:field] : key
31
+ end
32
+ end].join(',')
33
+ end
34
+
35
+ def collect_search
36
+ @criteria[:conditions].map do |key, value|
37
+ elements = @attributes[:search]
38
+ if elements.key?(key)
39
+ attribute = elements[key]
40
+ attribute.key?(:field) ? { attribute[:field] => value } : { key => value }
41
+ end
42
+ end.reduce({}, :merge)
43
+ end
44
+
45
+ def query_string(props)
46
+ search = props.delete('search')
47
+ uri = URI.encode_www_form(props)
48
+ search_query = "(search=#{search})" if search
49
+ uri = format("#{search_query}%<and>s", and: "&#{uri}") if search_query && uri
50
+ "(#{uri})"
51
+ end
52
+ end
53
+ end
@@ -4,23 +4,24 @@ module BestbuyApi
4
4
  # Defines the attributes for the products api. Documentation is
5
5
  # located at https://bestbuyapis.github.io/api-documentation/#products-api.
6
6
  class Product < Model
7
- PATH = 'products'.freeze
7
+ path 'products'
8
8
 
9
- ATTRIBUTES = {
10
- keyword: { kw: 'search', search: true, read: false },
11
- sku: { search: true },
12
- category_id: { kw: 'categoryPath.id', search: true },
13
- category_name: { kw: 'categoryPath.name', search: true },
14
- condition: { search: true },
15
- customer_rating: { kw: 'customerReviewAverage', search: true },
16
- manufacturer: { search: true },
17
- regular_price: { kw: 'regularPrice' },
18
- sale_price: { kw: 'salePrice' },
19
- shipping_cost: { kw: 'shippingCost' },
20
- reviews_count: { kw: 'customerReviewCount' },
21
- discount: { kw: 'percentSavings' },
22
- free_shipping: { kw: 'freeShipping' },
23
- url: {}, name: {}, description: {}, image: {}
24
- }.freeze
9
+ attribute :keyword, field: 'search', search: true, read: false
10
+ attribute :sku, search: true
11
+ attribute :category_id, field: 'categoryPath.id', search: true
12
+ attribute :category_name, field: 'categoryPath.name', search: true
13
+ attribute :condition, search: true
14
+ attribute :customer_rating, field: 'customerReviewAverage', search: true
15
+ attribute :manufacturer, search: true
16
+ attribute :regular_price, field: 'regularPrice'
17
+ attribute :sale_price, field: 'salePrice'
18
+ attribute :shipping_cost, field: 'shippingCost'
19
+ attribute :reviews_count, field: 'customerReviewCount'
20
+ attribute :discount, field: 'percentSavings'
21
+ attribute :free_shipping, field: 'freeShipping'
22
+ attribute :url
23
+ attribute :name
24
+ attribute :description
25
+ attribute :image
25
26
  end
26
27
  end
@@ -1,81 +1,24 @@
1
1
  require 'httparty'
2
+ require_relative 'response'
2
3
 
3
4
  module BestbuyApi
4
- # Wrap HTTParty gem to query the api
5
5
  class Request
6
6
  include HTTParty
7
7
  base_uri 'https://api.bestbuy.com/v1'
8
- PAGE_VARS = %w[totalPages total currentPage].freeze
9
8
 
10
- def initialize(path, attributes, criteria)
11
- # Get your API Key at https://developer.bestbuy.com/.
12
- api_key = BestbuyApi.config.api_key
13
- raise MissingApiKeyError, 'API Key is not defined' if api_key.nil?
9
+ def initialize(api_key, path)
10
+ raise MissingApiKeyError, 'API Key is not defined' if api_key.empty?
14
11
 
15
12
  @path = path
16
- @attributes = attributes
17
- @criteria = criteria
18
- @query = { apiKey: api_key, format: 'json' }
13
+ @options = { apiKey: api_key, format: 'json' }
19
14
  end
20
15
 
21
- def items
22
- response[@path] if response.key?(@path)
23
- end
24
-
25
- def pagination
26
- response.select { |k| PAGE_VARS.include?(k) }
27
- end
28
-
29
- def url
30
- response.request.last_uri.to_s
31
- end
32
-
33
- private
34
-
35
- def response
36
- @response ||= find
37
- end
38
-
39
- def find
40
- response = self.class.get("/#{@path}#{slug}", query: params)
41
- raise RequestError, "#{response.code} Request Error" if response.code != 200
42
-
43
- response
44
- end
45
-
46
- # Collect attributes that are readable and substitute using kw or key
47
- def slug
48
- attributes = @attributes.select { |_k, v| v.key?(:search) && v[:search] }
49
- opts = @criteria[:conditions].map do |k, v|
50
- attributes[k].key?(:kw) ? { attributes[k][:kw] => v } : { k => v }
51
- end
52
- opts = opts.reduce({}, :merge)
53
-
54
- encode_slug(opts)
55
- end
56
-
57
- # Collect attributes that are searchable and substitute using kw or key
58
- def params
59
- attributes = @attributes.select { |_k, v| v.key?(:read) ? v[:read] : true }
60
- opts = Array[@criteria[:attributes].map do |k|
61
- attributes[k].key?(:kw) ? attributes[k][:kw] : k
62
- end].join(',')
63
-
64
- join_fields(opts)
65
- end
66
-
67
- def encode_slug(opts)
68
- search = opts.delete('search') if opts.key?('search')
69
- slug = URI.encode_www_form(opts)
70
- slug = format("(search=#{search})%<and>s", and: ("&#{slug}" unless slug.empty?)) if search
71
- return "(#{slug})" unless slug.empty?
72
- end
16
+ def find(params)
17
+ result = self.class.get("/#{@path}#{params[:slug]}", query: @options.merge(params[:query]))
18
+ code = result.code
19
+ raise RequestError, "#{code} Request Error: #{result.request.last_uri}" if code != 200
73
20
 
74
- def join_fields(opts)
75
- params = @criteria.slice(:limit, :page)
76
- params[:show] = opts unless opts.empty?
77
- @query.merge!(params) unless params.empty?
78
- @query
21
+ Response.new(result, @path)
79
22
  end
80
23
  end
81
24
  end
@@ -0,0 +1,22 @@
1
+ module BestbuyApi
2
+ class Response
3
+ PAGE_VARS = %w[totalPages total currentPage].freeze
4
+
5
+ def initialize(result, path)
6
+ @result = result
7
+ @path = path
8
+ end
9
+
10
+ def items
11
+ @result[@path] if @result.key?(@path)
12
+ end
13
+
14
+ def pagination
15
+ @result.select { |key| PAGE_VARS.include?(key) }
16
+ end
17
+
18
+ def url
19
+ @result.request.last_uri.to_s
20
+ end
21
+ end
22
+ end
@@ -1,20 +1,21 @@
1
1
  require_relative 'model'
2
- require_relative 'request'
3
2
 
4
3
  module BestbuyApi
5
4
  # Defines the attributes for the stores api. Documentation is
6
5
  # located at https://bestbuyapis.github.io/api-documentation/#stores-api.
7
6
  class Store < Model
8
- PATH = 'stores'.freeze
7
+ path 'stores'
9
8
 
10
- ATTRIBUTES = {
11
- id: { kw: 'storeId', search: true },
12
- city: { search: true },
13
- state: { kw: 'region', search: true },
14
- postal_code: { kw: 'fullPostalCode', search: true },
15
- store_type: { kw: 'storeType' },
16
- name: {}, address: {}, address2: {}, country: {},
17
- hours: {}, phone: {}
18
- }.freeze
9
+ attribute :id, field: 'storeId', search: true
10
+ attribute :city, search: true
11
+ attribute :state, field: 'region', search: true
12
+ attribute :postal_code, field: 'fullPostalCode', search: true
13
+ attribute :store_type, field: 'storeType'
14
+ attribute :name
15
+ attribute :address
16
+ attribute :address2
17
+ attribute :country
18
+ attribute :hours
19
+ attribute :phone
19
20
  end
20
21
  end
@@ -1,3 +1,3 @@
1
1
  module BestbuyApi
2
- VERSION = '0.1.0'.freeze
2
+ VERSION = '1.0.0'.freeze
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bestbuy_api
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Michael John Bayucot
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2018-12-01 00:00:00.000000000 Z
11
+ date: 2019-01-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: httparty
@@ -128,6 +128,7 @@ extensions: []
128
128
  extra_rdoc_files: []
129
129
  files:
130
130
  - ".gitignore"
131
+ - ".reek.yml"
131
132
  - ".rspec"
132
133
  - ".rubocop.yml"
133
134
  - ".travis.yml"
@@ -141,8 +142,10 @@ files:
141
142
  - lib/bestbuy_api/criteria.rb
142
143
  - lib/bestbuy_api/exceptions.rb
143
144
  - lib/bestbuy_api/model.rb
145
+ - lib/bestbuy_api/params.rb
144
146
  - lib/bestbuy_api/product.rb
145
147
  - lib/bestbuy_api/request.rb
148
+ - lib/bestbuy_api/response.rb
146
149
  - lib/bestbuy_api/store.rb
147
150
  - lib/bestbuy_api/version.rb
148
151
  homepage: https://github.com/mbayucot/bestbuy-api