best_buy_ruby 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (49) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +21 -0
  3. data/.reek.yml +127 -0
  4. data/.rspec +3 -0
  5. data/.rubocop.yml +74 -0
  6. data/.travis.yml +33 -0
  7. data/CHANGELOG.md +10 -0
  8. data/CODE_OF_CONDUCT.md +74 -0
  9. data/CONTRIBUTING.md +42 -0
  10. data/Gemfile +5 -0
  11. data/LICENSE.txt +21 -0
  12. data/README.md +83 -0
  13. data/Rakefile +6 -0
  14. data/best_buy_ruby.gemspec +42 -0
  15. data/bin/console +15 -0
  16. data/bin/setup +8 -0
  17. data/docs/categories_api.md +25 -0
  18. data/docs/general_overview.md +67 -0
  19. data/docs/products_api.md +85 -0
  20. data/docs/stores_api.md +68 -0
  21. data/lib/best_buy.rb +34 -0
  22. data/lib/best_buy/base.rb +13 -0
  23. data/lib/best_buy/base/version.rb +7 -0
  24. data/lib/best_buy/base_api.rb +46 -0
  25. data/lib/best_buy/categories.rb +23 -0
  26. data/lib/best_buy/config.rb +17 -0
  27. data/lib/best_buy/helpers/api_helper.rb +13 -0
  28. data/lib/best_buy/helpers/conditions/category_condition.rb +19 -0
  29. data/lib/best_buy/helpers/conditions/max_price_condition.rb +19 -0
  30. data/lib/best_buy/helpers/conditions/min_price_condition.rb +19 -0
  31. data/lib/best_buy/helpers/conditions/new_condition.rb +19 -0
  32. data/lib/best_buy/helpers/conditions/pre_owned_condition.rb +19 -0
  33. data/lib/best_buy/helpers/conditions/refurbished_condition.rb +19 -0
  34. data/lib/best_buy/models/address.rb +23 -0
  35. data/lib/best_buy/models/base_category.rb +12 -0
  36. data/lib/best_buy/models/category.rb +20 -0
  37. data/lib/best_buy/models/collection_header.rb +20 -0
  38. data/lib/best_buy/models/collections_response.rb +19 -0
  39. data/lib/best_buy/models/image.rb +16 -0
  40. data/lib/best_buy/models/offer.rb +18 -0
  41. data/lib/best_buy/models/product.rb +39 -0
  42. data/lib/best_buy/models/shipping_level_of_service.rb +13 -0
  43. data/lib/best_buy/models/store.rb +26 -0
  44. data/lib/best_buy/products.rb +53 -0
  45. data/lib/best_buy/search_query_builder.rb +21 -0
  46. data/lib/best_buy/stores.rb +30 -0
  47. data/lib/generators/best_buy/config/config_generator.rb +13 -0
  48. data/lib/generators/best_buy/config/templates/config.rb +5 -0
  49. metadata +234 -0
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ task :code_analysis do
4
+ sh 'bundle exec rubocop lib spec'
5
+ sh 'bundle exec reek lib'
6
+ end
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'lib/best_buy/base/version'
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = 'best_buy_ruby'
7
+ spec.version = BestBuy::Base::VERSION
8
+ spec.authors = ['Sandro Damilano']
9
+ spec.email = ['sandro.damilano@rootstrap.com']
10
+
11
+ spec.summary = 'A wrapper for Best Buy APIs.'
12
+ spec.homepage = 'https://github.com/rootstrap/best_buy_ruby'
13
+ spec.license = 'MIT'
14
+ spec.required_ruby_version = Gem::Requirement.new('>= 2.3.0')
15
+
16
+ spec.metadata['homepage_uri'] = spec.homepage
17
+ spec.metadata['source_code_uri'] = 'https://github.com/rootstrap/best_buy_ruby'
18
+ spec.metadata['changelog_uri'] = 'https://github.com/rootstrap/best_buy_ruby'
19
+
20
+ # Specify which files should be added to the gem when it is released.
21
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
22
+ spec.files = Dir.chdir(File.expand_path(__dir__)) do
23
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
24
+ end
25
+ spec.bindir = 'exe'
26
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
27
+ spec.require_paths = ['lib']
28
+
29
+ # Production dependencies
30
+ spec.add_dependency 'activesupport', '~> 6.0.2.1'
31
+ spec.add_dependency 'faraday', '~> 1.0.0'
32
+
33
+ # Development dependencies
34
+ spec.add_development_dependency 'ammeter'
35
+ spec.add_development_dependency 'railties'
36
+ spec.add_development_dependency 'rake'
37
+ spec.add_development_dependency 'reek'
38
+ spec.add_development_dependency 'rspec'
39
+ spec.add_development_dependency 'rubocop'
40
+ spec.add_development_dependency 'simplecov'
41
+ spec.add_development_dependency 'webmock'
42
+ end
@@ -0,0 +1,15 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require 'bundler/setup'
5
+ require 'best_buy_ruby/base'
6
+
7
+ # You can add fixtures and/or initialization code here to make experimenting
8
+ # with your gem easier. You can also use a different console, if you like.
9
+
10
+ # (If you use this, don't forget to add pry to your Gemfile!)
11
+ # require "pry"
12
+ # Pry.start
13
+
14
+ require 'irb'
15
+ IRB.start(__FILE__)
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,25 @@
1
+ # Categories API
2
+
3
+ ## The Category object
4
+
5
+ Attributes:
6
+
7
+ - `id`: Used to find all results within a specific category (e.g., 'abcat0100000')
8
+ - `name`: Used to find all subcategories (e.g., parents, siblings, children) within a specific category
9
+ - `url`: URL to corresponding BESTBUY.COM category page
10
+ - `active`: Indicates if the category is currently active or not
11
+ - `path`: Array of parent categories, starting with the root and finishing with the present one
12
+ - `sub_categories`: Array of child categories. Each one is a [BaseCategory](categories_api.md#the-basecategory-object) object
13
+
14
+ #### The BaseCategory object
15
+
16
+ A minimalistic version of a category. Used to represent the categories in occasions where not the whole information is available (like the categories returned as `sub_categories`)
17
+
18
+ Attributes:
19
+
20
+ - `id`: Used to find all results within a specific category (e.g., abcat0100000)
21
+ - `name`: Used to find all subcategories (e.g., parents, siblings, children) within a specific category
22
+
23
+ ## Interface
24
+
25
+ (For more methods, check the [common API interface](general_overview.md#common-methods))
@@ -0,0 +1,67 @@
1
+ # General Overview
2
+
3
+ The different APIs accessible by this gem are:
4
+
5
+ - [Products](products_api.md)
6
+ - [Stores](stores_api.md)
7
+ - [Categories](categories_api.md)
8
+
9
+ In spite of having each their own specification, they all share some basics listed here.
10
+
11
+ ## Common interface
12
+
13
+ This method can be used with any of the APIs:
14
+
15
+ #### `get_all(search_query:, pagination:)`
16
+ _alias: `index`_
17
+
18
+ Retrieves a collection of items (these depend on the API). These items will be filtered by `search_query` and limited by `pagination`.
19
+
20
+ Params:
21
+
22
+ - `search_query`: A string representing the query added to the URL to filter the items (See [Search Techniques](https://bestbuyapis.github.io/api-documentation/#search-techniques) in the Best Buy API reference). Optional.
23
+ - `pagination`: See [Pagination](general_overview.md#pagination). Optional.
24
+
25
+ Returns: a [`CollectionsResponse`](general_overview.md#collections-response) object
26
+
27
+ ```ruby
28
+ search_query = '(active=true)'
29
+ pagination_params = { page: 2, page_size: 20 }
30
+
31
+ BestBuy::Categories.new(your_api_key).get_all(search_query: search_query, pagination: pagination_params)
32
+ ```
33
+
34
+ ## Collections response
35
+
36
+ Every request made that returns a collection of items (no matter what *kind* of item) will return an object called `CollectionsResponse`. This object contains two attributes:
37
+
38
+ - `header`
39
+ - `collection`
40
+
41
+ The `collection` will contain a list of objects of the requested collection (`Product`, `Store`, etc).
42
+
43
+ The `header` will be a `CollectionHeader` object which will contain some metadata of the request itself. Its attributes include:
44
+
45
+ - `canonical_url`: the non-server part of the query
46
+ - `current_page`: the page being returned
47
+ - `partial`: flag indicating whether or not the query returned only partial results (in the event of a timeout)
48
+ - `from`: the index of the first item returned on the current page
49
+ - `to`: the index of the last item returned on the current page
50
+ - `total`: the total number of items returned by the query
51
+ - `total_pages`: the number of pages required to list all items
52
+ - `query_time`: the time required to search the database
53
+ - `total_time`: the time required to parse, search, format and return results
54
+
55
+ ## Pagination
56
+
57
+ Best Buy APIs accept pagination parameters to control the amount of results returned. That's why for the `get_all` method, for example, there's an optional `pagination` parameter, which consists of a hash with two also optional keys:
58
+
59
+ - `:page`: number of the page of results you’d like returned
60
+ - `:page_size`: amount of results per page (default: 10, max: 100)
61
+
62
+ Example:
63
+ ```ruby
64
+ pagination_params = { page: 3, page_size: 50 }
65
+
66
+ BestBuy::Stores.new(your_api_key).get_all(pagination: pagination_params)
67
+ ```
@@ -0,0 +1,85 @@
1
+ # Products API
2
+
3
+ ## The Product object
4
+
5
+ Attributes:
6
+
7
+ - `active`: Identifies if product is currently supported in the BESTBUY.COM catalog
8
+ - `category_path`: A hierarchical view of a product returned as a collection
9
+ - `alternate_categories`: Alternative categories of the product
10
+ - `images`: An array of [Images](products_api.md#the-image-object)
11
+ - `name`: Product name
12
+ - `offers`: An array of [Offers](products_api.md#the-offer-object)
13
+ - `regular_price`: Product’s regular selling price
14
+ - `sale_price`: Current item selling price
15
+ - `shipping_cost`: Provides product’s lowest shipping costs
16
+ - `shipping_levels_of_service`: An array of [Shipping levels of service](products_api.md#the-shippinglevelofservice-object)
17
+ - `sku`: Best Buy unique 7-digit product identifier
18
+ - `type`: Best Buy product type. See [Product type details](https://bestbuyapis.github.io/api-documentation/#listing-products) in the Best Buy API reference for further information
19
+ - `upc`: Universal Product Code (UPC)
20
+ - `url`: URL to BESTBUY.COM product detail page
21
+ - `raw_attributes`: Hash containing all information returned by the Best Buy API about the product. Any attribute returned not present in the object can be found here.
22
+
23
+ #### The Image object
24
+
25
+ Attributes:
26
+
27
+ - `height`: Height of the image
28
+ - `width`: Width of the image
29
+ - `unit_of_measure`: Unit in which height and width are expressed
30
+ - `href`: URL of the image
31
+ - `primary`: If it's the main image or not
32
+ - `rel`: Name of the image
33
+
34
+ #### The Offer object
35
+
36
+ Attributes:
37
+
38
+ - `id`: Offer identifier
39
+ - `offer_name`: Offer name
40
+ - `content_notes`: Notes about the offer
41
+ - `start_date`: Offer start date
42
+ - `end_date`: Offer end date
43
+ - `text`: Offer description
44
+ - `type`: Offer types can include: special_offer, digital_insert and deal_of_the_day (See the [oficial documentation](https://bestbuyapis.github.io/api-documentation/#offers-and-deals) for further info)
45
+ - `url`: URL of offer information on BESTBUY.COM
46
+
47
+ #### The ShippingLevelOfService object
48
+
49
+ Represents the shipping options of the product, with their own prices.
50
+
51
+ Attributes:
52
+
53
+ - `service_level_id`: ID of the shipping level of service
54
+ - `service_level_name`: Name of the shipping level of service
55
+ - `unit_shipping_price`: Price of the shipping level of service
56
+
57
+ ## Interface
58
+
59
+ (For more methods, check the [common API interface](general_overview.md#common-methods))
60
+
61
+ #### `get_by(conditions)`
62
+
63
+ Params:
64
+
65
+ - `conditions`: A hash including certain search conditions. All of them are optional.
66
+
67
+ - `:category_id`: The ID of a category. Returns only products of that category.
68
+ - `:min_price`: Minimum price allowed for the returned products. It will take into account products on sale.
69
+ - `:max_price`: Maximum price allowed for the returned products. It will take into account products on sale.
70
+ - `:item_condition`: The condition all returned products must have. Can be either `new`, `pre-owned` or `refurbished`.
71
+ - `:pagination`: See [Pagination](general_overview.md#pagination)
72
+
73
+ Returns: a [`CollectionsResponse`](general_overview.md#collections-response) object
74
+
75
+ ```ruby
76
+ conditions = {
77
+ category_id: 'cat02015',
78
+ min_price: 10,
79
+ max_price: 15,
80
+ item_condition: 'new',
81
+ pagination: { page: 4, page_size: 100 }
82
+ }
83
+
84
+ BestBuy::Products.new(your_api_key).get_by(conditions)
85
+ ```
@@ -0,0 +1,68 @@
1
+ # Stores API
2
+
3
+ ## The Store object
4
+
5
+ Attributes:
6
+
7
+ - `location_type`: Whether the location is a Store or a Warehouse
8
+ - `long_name`: Full store name
9
+ - `name`: Store name
10
+ - `opening_time`: See [opening_time](stores_api.md#opening_time)
11
+ - `phone`: Store phone number; phone number for Express stores goes to Best Buy Customer Service
12
+ - `services`: Collection of services offered at each Best Buy store
13
+ - `store_id`: Store number
14
+ - `store_type`: Indicates the type of store, and is only present if locationType is ‘Store’. See the [official documentation](https://bestbuyapis.github.io/api-documentation/#common-attributes56) for more details
15
+ - `store_address`: See [The Address object](stores_api.md#the-address-object)
16
+
17
+ #### `opening_time`
18
+
19
+ Array of hashes containing info about the opening hours for each day for the next two weeks. It has the following keys:
20
+
21
+ - `:day`: Name of the day of the week (e.g.: 'Sunday')
22
+ - `:date`: Date of the day (string formatted as: YYYY-MM-DD)
23
+ - `:open`: Opening time (24-hour clock. E.g.: `'10:00'`. `'Close'` if the store is closed)
24
+ - `:close`: Closing time (24-hour clock. E.g.: `'21:00'`. `'Close'` if the store is closed)
25
+
26
+ #### The Address object
27
+
28
+ Object that keeps all the address information of the store.
29
+
30
+ Attributes:
31
+
32
+ - `address`: Street address
33
+ - `address2`: Street address 2 provides additional street address information for the Best Buy store in the result set
34
+ - `city`: City name
35
+ - `region`: State, territory
36
+ - `country`: Country name
37
+ - `postal_code`: 5-digit postal code
38
+ - `full_postal_code`: 9-digit postal code if available for store location
39
+ - `gmt_offset`: Time difference from GMT
40
+ - `lat`: Latitude
41
+ - `lng`: Longitude
42
+
43
+ Note: All these attributes are accessible directly by the Store object
44
+
45
+ ```ruby
46
+ store = Store.new({ address: '50 Holyoke St' })
47
+ store.address # returns '50 Holyoke St'
48
+ ```
49
+
50
+ ## Interface
51
+
52
+ (For more methods, check the [common API interface](general_overview.md#common-methods))
53
+
54
+ #### `find(store_id)`
55
+
56
+ Returns the store matching the requested ID.
57
+
58
+ Params:
59
+
60
+ - `store_id`: The ID of the required store
61
+
62
+ Returns: a `Store` object
63
+
64
+ ```ruby
65
+ store_id = 418
66
+
67
+ BestBuy::Stores.new(your_api_key).find(store_id)
68
+ ```
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'active_support/core_ext/array'
4
+ require 'active_support/core_ext/hash'
5
+ require 'active_support/core_ext/module/delegation'
6
+ require 'active_support/core_ext/string'
7
+ require 'faraday'
8
+
9
+ require 'best_buy/helpers/api_helper'
10
+ require 'best_buy/helpers/conditions/category_condition'
11
+ require 'best_buy/helpers/conditions/max_price_condition'
12
+ require 'best_buy/helpers/conditions/min_price_condition'
13
+ require 'best_buy/helpers/conditions/new_condition'
14
+ require 'best_buy/helpers/conditions/pre_owned_condition'
15
+ require 'best_buy/helpers/conditions/refurbished_condition'
16
+
17
+ require 'best_buy/base_api'
18
+ require 'best_buy/categories'
19
+ require 'best_buy/products'
20
+ require 'best_buy/search_query_builder'
21
+ require 'best_buy/stores'
22
+
23
+ require 'best_buy/models/address'
24
+ require 'best_buy/models/base_category'
25
+ require 'best_buy/models/category'
26
+ require 'best_buy/models/collection_header'
27
+ require 'best_buy/models/collections_response'
28
+ require 'best_buy/models/image'
29
+ require 'best_buy/models/offer'
30
+ require 'best_buy/models/product'
31
+ require 'best_buy/models/shipping_level_of_service'
32
+ require 'best_buy/models/store'
33
+
34
+ require 'generators/best_buy/config/config_generator'
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'best_buy/base/version'
4
+
5
+ module BestBuy
6
+ # Starting point of your gem
7
+ module Base
8
+ # Base error class
9
+ class Error < StandardError; end
10
+
11
+ # Your code goes here...
12
+ end
13
+ end
@@ -0,0 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ module BestBuy
4
+ module Base
5
+ VERSION = '0.1.0'
6
+ end
7
+ end
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ module BestBuy
4
+ class BaseAPI
5
+ # All subclasses must implement:
6
+ # :model_class
7
+ # :collection_name
8
+ # :api_url
9
+
10
+ BASE_URL = 'https://api.bestbuy.com'
11
+
12
+ attr_reader :api_key
13
+
14
+ def initialize(api_key)
15
+ @api_key = api_key
16
+ end
17
+
18
+ def get_all(search_query: '', pagination: {})
19
+ request_params = {
20
+ apiKey: api_key,
21
+ format: 'json',
22
+ show: 'all'
23
+ }.merge(pagination)
24
+
25
+ response = APIHelper.new.parse_response(get_response(search_query, request_params))
26
+
27
+ CollectionsResponse.new(
28
+ response: response,
29
+ collection_name: collection_name,
30
+ collection_type: model_class
31
+ )
32
+ end
33
+ alias_method :index, :get_all
34
+
35
+ protected
36
+
37
+ def connection
38
+ @connection ||= Faraday.new(url: BaseAPI::BASE_URL)
39
+ end
40
+
41
+ def get_response(search_query, params)
42
+ url = URI.escape(api_url + search_query) # rubocop:disable Lint/UriEscapeUnescape
43
+ connection.get(url, params).body
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'best_buy'
4
+
5
+ module BestBuy
6
+ class Categories < BaseAPI
7
+ CATEGORIES_API = '/v1/categories'
8
+
9
+ protected
10
+
11
+ def model_class
12
+ Category
13
+ end
14
+
15
+ def collection_name
16
+ :categories
17
+ end
18
+
19
+ def api_url
20
+ CATEGORIES_API
21
+ end
22
+ end
23
+ end