best_buy_ruby 0.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.
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