cheapshark 0.6.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.
- checksums.yaml +7 -0
- data/.gitignore +16 -0
- data/.rspec +3 -0
- data/.travis.yml +5 -0
- data/Gemfile +3 -0
- data/Guardfile +6 -0
- data/LICENSE.txt +22 -0
- data/README.md +52 -0
- data/Rakefile +2 -0
- data/cheapshark.gemspec +36 -0
- data/expectations.md +49 -0
- data/lib/cheapshark.rb +95 -0
- data/lib/cheapshark/config.rb +4 -0
- data/lib/cheapshark/fetchers/alerts_fetcher.rb +0 -0
- data/lib/cheapshark/fetchers/deal_fetcher.rb +14 -0
- data/lib/cheapshark/fetchers/deals_fetcher.rb +14 -0
- data/lib/cheapshark/fetchers/fetcher.rb +25 -0
- data/lib/cheapshark/fetchers/game_fetcher.rb +14 -0
- data/lib/cheapshark/fetchers/games_fetcher.rb +14 -0
- data/lib/cheapshark/fetchers/stores_fetcher.rb +14 -0
- data/lib/cheapshark/models/alert.rb +0 -0
- data/lib/cheapshark/models/deal.rb +48 -0
- data/lib/cheapshark/models/game.rb +22 -0
- data/lib/cheapshark/models/store.rb +11 -0
- data/lib/cheapshark/version.rb +3 -0
- data/spec/cheapshark_spec.rb +130 -0
- data/spec/fetchers/deal_fetcher.rb +38 -0
- data/spec/fetchers/games_fetcher_spec.rb +49 -0
- data/spec/models/deal_spec.rb +6 -0
- data/spec/models/game_spec.rb +170 -0
- data/spec/spec_helper.rb +22 -0
- data/spec/support/cheapshark_api_mock.rb +23 -0
- data/spec/support/fixtures/cheapshark_api_mock/arkham_by_id.json +29 -0
- data/spec/support/fixtures/cheapshark_api_mock/batman_games.json +1 -0
- data/spec/support/fixtures/cheapshark_api_mock/bio_inf_deal.json +28 -0
- metadata +284 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 845f882f1c716ed0233f3a66ffd8708001ad78ac
|
4
|
+
data.tar.gz: 8b552c4e4d38e11874ca63d3e9fa2fa70475fb21
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 8e24deb0199312b8cb60ff9809ec8248b3c852358c8a06177805b7c96d014e5eacb98731f359b267b0204412be856dd6bbe375e7110c1779e08fee97c69fef6d
|
7
|
+
data.tar.gz: e71f073b26d5964fdcf7c17479a68014ae86a8d67140c654ee166b55427fbb62f73a935646db3a6bc232f59c6b34791a3c59d8da1d18539132f4bfc11b0bc279
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/Guardfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2015 Antonio Gurgel
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
# CheapShark
|
2
|
+
|
3
|
+
[](https://gemnasium.com/GA114/cheapshark) [](https://codeclimate.com/github/GA114/cheapshark) [](https://travis-ci.org/GA114/cheapshark)
|
4
|
+
|
5
|
+
Ruby wrapper for [CheapShark's API](http://www.cheapshark.com/api/).
|
6
|
+
|
7
|
+
## Installation
|
8
|
+
|
9
|
+
Add this to your `Gemfile` and do a `bundle install`.
|
10
|
+
|
11
|
+
```ruby
|
12
|
+
gem 'cheapshark'
|
13
|
+
```
|
14
|
+
|
15
|
+
Or install it yourself:
|
16
|
+
|
17
|
+
$ gem install cheapshark
|
18
|
+
|
19
|
+
## Usage
|
20
|
+
|
21
|
+
``` ruby
|
22
|
+
require 'cheapshark'
|
23
|
+
CheapShark.games(title: 'Borderlands 2') # Returns an array of Game objects
|
24
|
+
CheapShark.games(title: 'Borderlands 2')[0] # Returns the likely most-relevant result
|
25
|
+
CheapShark.stores # Returns stores and their IDs
|
26
|
+
CheapShark.deals(storeID: 1, pageSize: 5) # Returns five best deals on Steam (CS sorts by deal rating by default)
|
27
|
+
CheapShark.deal(id: 'DCqsq6Hnmtzu2UVkBpD133kL1pG93Ovz4%2BEjTuJAx9c%3D') # Returns a specific deal.
|
28
|
+
```
|
29
|
+
|
30
|
+
Keep in mind that option names **must be properly capitalized**. The API will respond to `storeID` but ignore `storeid`.
|
31
|
+
|
32
|
+
``` ruby
|
33
|
+
CheapShark.deals(storeID: 1, pageSize: 5) # Right
|
34
|
+
CheapShark.deals(storeid: 1, pageSize: 5) # Wrong, will return five best deals from any store
|
35
|
+
CheapShark.deals(storeID: 1, pagesize: 5) # Wrong, will return the API default of sixty deals
|
36
|
+
CheapShark.deals(storeid: 1, pagesize: 5) # Very wrong, will return all deals
|
37
|
+
|
38
|
+
```
|
39
|
+
|
40
|
+
## To-dos
|
41
|
+
|
42
|
+
- Decide on garbage-input scenarios to handle (things like calling `CheapShark.games()` without params)
|
43
|
+
- Alert feature
|
44
|
+
- Complete [expectations.md](https://github.com/GA114/cheapshark/blob/master/expectations.md)
|
45
|
+
|
46
|
+
## Contributing
|
47
|
+
|
48
|
+
1. Fork it ( https://github.com/GA114/cheapshark/fork )
|
49
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
50
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
51
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
52
|
+
5. Create a new Pull Request
|
data/Rakefile
ADDED
data/cheapshark.gemspec
ADDED
@@ -0,0 +1,36 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'cheapshark/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "cheapshark"
|
8
|
+
spec.version = CheapShark::VERSION
|
9
|
+
spec.author = "Antonio Gurgel"
|
10
|
+
spec.email = "ag@antoniogurgel.com"
|
11
|
+
spec.summary = %q{Ruby wrapper gem for CheapShark's API.}
|
12
|
+
spec.description = %q{CheapShark aggregates sales from PC game stores.}
|
13
|
+
spec.homepage = "http://github.com/GA114/cheapshark"
|
14
|
+
spec.license = "MIT"
|
15
|
+
spec.platform = Gem::Platform::RUBY
|
16
|
+
|
17
|
+
spec.files = `git ls-files -z`.split("\x0")
|
18
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
19
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
20
|
+
spec.require_paths = ["lib"]
|
21
|
+
|
22
|
+
spec.add_development_dependency "bundler", "~> 1.7"
|
23
|
+
spec.add_development_dependency "webmock", "~> 1.20.4"
|
24
|
+
spec.add_development_dependency "sinatra", "~> 1.4.5"
|
25
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
26
|
+
spec.add_development_dependency "rspec", "~> 3.0"
|
27
|
+
spec.add_development_dependency "guard", "~> 2.12.4"
|
28
|
+
spec.add_development_dependency "pry"
|
29
|
+
spec.add_development_dependency "guard-rspec", "~> 4.5.0"
|
30
|
+
spec.add_development_dependency "io-console", "~> 0.4.3"
|
31
|
+
spec.add_development_dependency "vcr", "~> 2.9.3"
|
32
|
+
spec.add_development_dependency "simplecov", "~> 0.10.0"
|
33
|
+
spec.add_development_dependency "yard", "~> 0.8.7.6"
|
34
|
+
spec.add_runtime_dependency "httparty", "~> 0.13"
|
35
|
+
spec.add_runtime_dependency "json"
|
36
|
+
end
|
data/expectations.md
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
# Questions
|
2
|
+
|
3
|
+
[x] Where can I find $GAME for the cheapest price?
|
4
|
+
[x] What sales does $STORE have at the moment?
|
5
|
+
[ ] Which store has the best overall deals right now?
|
6
|
+
[ ] Which store has the most unique deals?
|
7
|
+
|
8
|
+
# Answers
|
9
|
+
|
10
|
+
## Find $GAME at lowest price
|
11
|
+
|
12
|
+
Search for games with single form input, which is just the name of the game.
|
13
|
+
Return a list of games, prices, and store link.
|
14
|
+
|
15
|
+
``` ruby
|
16
|
+
CheapShark.games(title: 'Borderlands 2') # returns an array of Game objects
|
17
|
+
```
|
18
|
+
|
19
|
+
Extra features (possibilities):
|
20
|
+
Search as you type (with Rails!)
|
21
|
+
|
22
|
+
## List $STORE's sales
|
23
|
+
|
24
|
+
Have user select a store from a list populated with API's store fetcher.
|
25
|
+
Return top $LIMIT or 10 deals of that store.
|
26
|
+
|
27
|
+
```ruby
|
28
|
+
CheapShark.deals(storeID: 1, pageSize: 5) # returns five best deals on Steam (CS sorts by deal rating by default)
|
29
|
+
```
|
30
|
+
|
31
|
+
Extra features (possibilities):
|
32
|
+
|
33
|
+
## Find store with best deals
|
34
|
+
|
35
|
+
Search all deals.
|
36
|
+
Return top $LIMIT or 10 deals.
|
37
|
+
|
38
|
+
```ruby
|
39
|
+
CheapShark.deals(limit: 10)
|
40
|
+
```
|
41
|
+
|
42
|
+
Extra features (possibilities):
|
43
|
+
|
44
|
+
## Find best unique deals
|
45
|
+
|
46
|
+
(Meaning, no other store has $GAME on sale?)
|
47
|
+
??
|
48
|
+
|
49
|
+
Extra features (possibilities):
|
data/lib/cheapshark.rb
ADDED
@@ -0,0 +1,95 @@
|
|
1
|
+
require 'uri'
|
2
|
+
require_relative 'cheapshark/version'
|
3
|
+
require_relative 'cheapshark/fetchers/games_fetcher.rb'
|
4
|
+
require_relative 'cheapshark/fetchers/game_fetcher.rb'
|
5
|
+
require_relative 'cheapshark/fetchers/deal_fetcher.rb'
|
6
|
+
require_relative 'cheapshark/fetchers/deals_fetcher.rb'
|
7
|
+
require_relative 'cheapshark/fetchers/stores_fetcher.rb'
|
8
|
+
|
9
|
+
# Base object to handle interaction with API.
|
10
|
+
#
|
11
|
+
module CheapShark
|
12
|
+
extend self
|
13
|
+
|
14
|
+
# Gets info about a specific deal, by ID.
|
15
|
+
#
|
16
|
+
# @param options [{Symbol => String}]
|
17
|
+
# @option options [String] :id the ID of the deal
|
18
|
+
# @example Returns "Borderlands 2" on the Humble Store.
|
19
|
+
# CheapShark.deal(id: 'DCqsq6Hnmtzu2UVkBpD133kL1pG93Ovz4%2BEjTuJAx9c%3D')
|
20
|
+
# @return [CheapShark::Deal]
|
21
|
+
def deal(options={})
|
22
|
+
options[:id] = URI.unescape(options[:id])
|
23
|
+
CheapShark::DealFetcher.new(options).results
|
24
|
+
end
|
25
|
+
|
26
|
+
# Searches for deals matching each criterion supplied, and returns them in a paginated list.
|
27
|
+
#
|
28
|
+
# @param options [{Symbol => String}]
|
29
|
+
# @option options [String] :storeID Comma-separated list of stores; omit for any store.
|
30
|
+
# @option options [Integer] :pageSize (60) Number of deals to return
|
31
|
+
# @option options [Integer] :pageNumber (0) Page to start on
|
32
|
+
# @option options [String] :sortBy ("Deal Rating") Can be "Deal Rating", "Title", "Savings", "Price", "Metacritic", "Release", or "Store".
|
33
|
+
# @option options [Integer] :desc (0) Sort descending?
|
34
|
+
# @option options [Integer] :lowerPrice (0) Minimum deal price.
|
35
|
+
# @option options [Integer] :upperPrice Maximum deal price. 50 is the same as no limit.
|
36
|
+
# @option options [Integer] :metacritic (0) Minimum Metacritic score.
|
37
|
+
# @option options [String] :title Match the supplied string anywhere in the game's title.
|
38
|
+
# @option options [Integer] :exact (0) Match exact title string.
|
39
|
+
# @option options [Integer] :AAA (0) Finds games with RETAIL PRICE >$29
|
40
|
+
# @option options [Integer] :steamworks (0) Find games that redeem on Steam (API has best-guess policy).
|
41
|
+
# @option options [Integer] :onSale (0) Find games currently on sale.
|
42
|
+
#
|
43
|
+
# @example Returns five best deals on Steam (API sorts by deal rating by default)
|
44
|
+
# CheapShark.deals(storeID: 1, pageSize: 5)
|
45
|
+
# @example Returns all deals with titles containing the word "civilization"
|
46
|
+
# CheapShark.deals(title: 'civilization')
|
47
|
+
# @example Returns all deals for "Grand Theft Auto V"
|
48
|
+
# CheapShark.deals(title: 'Grand Theft Auto V', exact: 1)
|
49
|
+
# @return [Array<CheapShark::Deal>]
|
50
|
+
def deals(options={})
|
51
|
+
CheapShark::DealsFetcher.new(options).results
|
52
|
+
end
|
53
|
+
|
54
|
+
# Searches for games matching either the title or Steam ID supplied.
|
55
|
+
#
|
56
|
+
# @param options [{Symbol => String}]
|
57
|
+
# @option options [String] :title Title of the game.
|
58
|
+
# @option options [Integer] :steamAppID Steam ID of the game.
|
59
|
+
# @option options [Integer] :limit Limit the amount of games to return.
|
60
|
+
# @example Search for the "Max Payne" series.
|
61
|
+
# CheapShark.games(title: 'Max Payne')
|
62
|
+
# @example Returns "Portal 2" (and use it as a Game object rather than an Array).
|
63
|
+
# CheapShark.games(steamAppID: 620)[0]
|
64
|
+
# @return [Array<CheapShark::Game>]
|
65
|
+
def games(options={})
|
66
|
+
CheapShark::GamesFetcher.new(options).results
|
67
|
+
end
|
68
|
+
|
69
|
+
|
70
|
+
# Returns a game identified by CheapShark ID and all current deals associated with it.
|
71
|
+
# @note Game IDs are different from deal IDs; the game IDs take on the form of an integer, whereas deal IDs are encoded strings.
|
72
|
+
#
|
73
|
+
# @param options [{Symbol => String}]
|
74
|
+
# @option options [String] :id ID of the game.
|
75
|
+
# @example Returns "Batman: Arkham City" and all deals it's in.
|
76
|
+
# CheapShark.game(id: 14)
|
77
|
+
# @returns [CheapShark::Game]
|
78
|
+
def game(options={})
|
79
|
+
CheapShark::GameFetcher.new(options).results
|
80
|
+
end
|
81
|
+
|
82
|
+
# Returns all stores tracked by CheapShark, as well as their IDs.
|
83
|
+
#
|
84
|
+
# @example
|
85
|
+
# CheapShark.stores()
|
86
|
+
# @returns [Array<CheapShark::Store>]
|
87
|
+
def stores(options={})
|
88
|
+
CheapShark::StoresFetcher.new(options).results
|
89
|
+
end
|
90
|
+
|
91
|
+
# TODO
|
92
|
+
# def alerts(options={})
|
93
|
+
# end
|
94
|
+
|
95
|
+
end
|
File without changes
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require_relative 'fetcher.rb'
|
2
|
+
require_relative '../models/deal.rb'
|
3
|
+
|
4
|
+
module CheapShark
|
5
|
+
class DealsFetcher < CheapShark::Fetcher
|
6
|
+
|
7
|
+
FETCHER_ENDPOINT = '/deals'
|
8
|
+
|
9
|
+
def results
|
10
|
+
@results.map { |result| CheapShark::Deal.new :search, result }
|
11
|
+
end
|
12
|
+
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'json'
|
2
|
+
require 'uri'
|
3
|
+
require 'httparty'
|
4
|
+
|
5
|
+
require_relative '../config'
|
6
|
+
|
7
|
+
module CheapShark
|
8
|
+
|
9
|
+
# Base fetcher class.
|
10
|
+
class Fetcher
|
11
|
+
|
12
|
+
include HTTParty
|
13
|
+
|
14
|
+
base_uri CheapShark::BASE_URI
|
15
|
+
|
16
|
+
def initialize(options)
|
17
|
+
@results = JSON.parse self.class.get( self.class::FETCHER_ENDPOINT, query: options ).body
|
18
|
+
end
|
19
|
+
|
20
|
+
def results
|
21
|
+
@results
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require_relative 'fetcher.rb'
|
2
|
+
require_relative '../models/game.rb'
|
3
|
+
|
4
|
+
module CheapShark
|
5
|
+
class GamesFetcher < CheapShark::Fetcher
|
6
|
+
|
7
|
+
FETCHER_ENDPOINT = '/games'
|
8
|
+
|
9
|
+
def results
|
10
|
+
@results.map { |result| CheapShark::Game.new :search, result }
|
11
|
+
end
|
12
|
+
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require_relative 'fetcher.rb'
|
2
|
+
require_relative '../models/store.rb'
|
3
|
+
|
4
|
+
module CheapShark
|
5
|
+
class StoresFetcher < CheapShark::Fetcher
|
6
|
+
|
7
|
+
FETCHER_ENDPOINT = '/stores'
|
8
|
+
|
9
|
+
def results
|
10
|
+
@results.map { |result| CheapShark::Store.new result }
|
11
|
+
end
|
12
|
+
|
13
|
+
end
|
14
|
+
end
|
File without changes
|
@@ -0,0 +1,48 @@
|
|
1
|
+
require 'uri'
|
2
|
+
|
3
|
+
module CheapShark
|
4
|
+
class Deal
|
5
|
+
attr_reader :store_id, :game_id, :name, :steam_app_id, :sale_price, :retail_price, :metacritic_score, :metacritic_link, :release_date, :publisher, :thumb, :cheaper_stores, :cheapest_price, :cheapest_date, :price, :internal_name, :deal_rating
|
6
|
+
|
7
|
+
# TODO: DRY up this abomination
|
8
|
+
def initialize(query_type, results)
|
9
|
+
case query_type
|
10
|
+
when :search
|
11
|
+
@internal_name = results['internalName']
|
12
|
+
@name = results['title']
|
13
|
+
@deal_id = results['dealID'].to_i
|
14
|
+
@store_id = results['storeID'].to_i
|
15
|
+
@game_id = results['gameID'].to_i
|
16
|
+
@sale_price = results['salePrice'].to_f
|
17
|
+
@retail_price = results['normalPrice'].to_f
|
18
|
+
@savings = results['savings'].to_f
|
19
|
+
@metacritic_score = results['metacriticScore'].to_i
|
20
|
+
@metacritic_link = results['metacriticLink']
|
21
|
+
@release_date = Time.at(results['releaseDate'].to_i)
|
22
|
+
@last_change = Time.at(results['lastChange'].to_i)
|
23
|
+
@deal_rating = results['dealRating'].to_f
|
24
|
+
@thumb = results['thumb']
|
25
|
+
when :by_id
|
26
|
+
@store_id = results['gameInfo']['storeID'].to_i
|
27
|
+
@game_id = results['gameInfo']['gameID'].to_i
|
28
|
+
@name = results['gameInfo']['name']
|
29
|
+
@steam_app_id = results['gameInfo']['steamAppID'].to_i
|
30
|
+
@sale_price = results['gameInfo']['salePrice'].to_f
|
31
|
+
@retail_price = results['gameInfo']['retailPrice'].to_f
|
32
|
+
@metacritic_score = results['gameInfo']['metacriticScore'].to_i
|
33
|
+
@metacritic_link = results['gameInfo']['metacriticLink']
|
34
|
+
@release_date = Time.at(results['gameInfo']['releaseDate'].to_i)
|
35
|
+
@publisher = results['gameInfo']['publisher']
|
36
|
+
@thumb = results['gameInfo']['thumb']
|
37
|
+
@cheaper_stores = results['cheaperStores'].map { |deal| Deal.new :game, deal }
|
38
|
+
@cheapest_price = results['cheapestPrice']['price'].to_f
|
39
|
+
@cheapest_date = Time.at(results['cheapestPrice']['date'].to_i)
|
40
|
+
when :game # derived from game object
|
41
|
+
@store_id = results['storeID']
|
42
|
+
@deal_id = results['dealID']
|
43
|
+
@price = results['price']
|
44
|
+
@retail_price = results['retailPrice']
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|