luchadeer 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +19 -0
- data/.rspec +1 -0
- data/.travis.yml +6 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +60 -0
- data/LICENSE +20 -0
- data/README.md +58 -0
- data/Rakefile +1 -0
- data/lib/luchadeer.rb +32 -0
- data/lib/luchadeer/api.rb +51 -0
- data/lib/luchadeer/api/characters.rb +11 -0
- data/lib/luchadeer/api/companies.rb +11 -0
- data/lib/luchadeer/api/concepts.rb +11 -0
- data/lib/luchadeer/api/franchises.rb +11 -0
- data/lib/luchadeer/api/games.rb +11 -0
- data/lib/luchadeer/api/locations.rb +11 -0
- data/lib/luchadeer/api/objects.rb +11 -0
- data/lib/luchadeer/api/people.rb +11 -0
- data/lib/luchadeer/api/videos.rb +11 -0
- data/lib/luchadeer/character.rb +13 -0
- data/lib/luchadeer/client.rb +73 -0
- data/lib/luchadeer/company.rb +13 -0
- data/lib/luchadeer/concept.rb +13 -0
- data/lib/luchadeer/error.rb +50 -0
- data/lib/luchadeer/franchise.rb +13 -0
- data/lib/luchadeer/game.rb +13 -0
- data/lib/luchadeer/location.rb +13 -0
- data/lib/luchadeer/middleware/follow_redirects.rb +50 -0
- data/lib/luchadeer/middleware/parse_api_error.rb +18 -0
- data/lib/luchadeer/middleware/parse_http_error.rb +18 -0
- data/lib/luchadeer/middleware/parse_json.rb +28 -0
- data/lib/luchadeer/object.rb +13 -0
- data/lib/luchadeer/person.rb +13 -0
- data/lib/luchadeer/resource.rb +37 -0
- data/lib/luchadeer/search.rb +45 -0
- data/lib/luchadeer/version.rb +3 -0
- data/lib/luchadeer/video.rb +13 -0
- data/luchadeer.gemspec +27 -0
- data/spec/luchadeer/api/characters_spec.rb +28 -0
- data/spec/luchadeer/api/companies_spec.rb +28 -0
- data/spec/luchadeer/api/concepts_spec.rb +28 -0
- data/spec/luchadeer/api/franchises_spec.rb +28 -0
- data/spec/luchadeer/api/games_spec.rb +28 -0
- data/spec/luchadeer/api/locations_spec.rb +28 -0
- data/spec/luchadeer/api/objects_spec.rb +28 -0
- data/spec/luchadeer/api/people_spec.rb +28 -0
- data/spec/luchadeer/api/videos_spec.rb +28 -0
- data/spec/luchadeer/api_spec.rb +101 -0
- data/spec/luchadeer/character_spec.rb +27 -0
- data/spec/luchadeer/client_spec.rb +54 -0
- data/spec/luchadeer/company_spec.rb +27 -0
- data/spec/luchadeer/concept_spec.rb +27 -0
- data/spec/luchadeer/error_spec.rb +53 -0
- data/spec/luchadeer/franchise_spec.rb +27 -0
- data/spec/luchadeer/game_spec.rb +27 -0
- data/spec/luchadeer/location_spec.rb +27 -0
- data/spec/luchadeer/object_spec.rb +27 -0
- data/spec/luchadeer/person_spec.rb +27 -0
- data/spec/luchadeer/resource_spec.rb +70 -0
- data/spec/luchadeer/search_spec.rb +69 -0
- data/spec/luchadeer/video_spec.rb +27 -0
- data/spec/luchadeer_spec.rb +24 -0
- data/spec/spec_helper.rb +5 -0
- metadata +216 -0
@@ -0,0 +1,50 @@
|
|
1
|
+
module Luchadeer
|
2
|
+
class Error < StandardError
|
3
|
+
|
4
|
+
# http://www.giantbomb.com/api/documentation#toc-0-0
|
5
|
+
module Codes
|
6
|
+
OK = 1
|
7
|
+
INVALID_API_KEY = 100
|
8
|
+
OBJECT_NOT_FOUND = 101
|
9
|
+
URL_FORMAT_ERROR = 102
|
10
|
+
FILTER_ERROR = 104
|
11
|
+
SUBSCRIBER_ONLY = 105
|
12
|
+
end
|
13
|
+
|
14
|
+
# Used for bespoke status codes returned in the response body
|
15
|
+
def self.api_errors
|
16
|
+
{
|
17
|
+
Codes::INVALID_API_KEY => Luchadeer::Error::InvalidAPIKey,
|
18
|
+
Codes::OBJECT_NOT_FOUND => Luchadeer::Error::NotFound,
|
19
|
+
Codes::URL_FORMAT_ERROR => Luchadeer::Error::URLFormatError,
|
20
|
+
Codes::FILTER_ERROR => Luchadeer::Error::FilterError,
|
21
|
+
Codes::SUBSCRIBER_ONLY => Luchadeer::Error::SubscriberOnly
|
22
|
+
}
|
23
|
+
end
|
24
|
+
|
25
|
+
# Used for HTTP status codes
|
26
|
+
def self.http_errors
|
27
|
+
{
|
28
|
+
400 => Luchadeer::Error::BadRequest,
|
29
|
+
404 => Luchadeer::Error::NotFound,
|
30
|
+
500 => Luchadeer::Error::InternalServerError,
|
31
|
+
502 => Luchadeer::Error::InternalServerError, # unconfirmed
|
32
|
+
503 => Luchadeer::Error::InternalServerError, # unconfirmed
|
33
|
+
504 => Luchadeer::Error::InternalServerError, # unconfirmed
|
34
|
+
}
|
35
|
+
end
|
36
|
+
|
37
|
+
private
|
38
|
+
|
39
|
+
class RedirectLimitReached < Luchadeer::Error; end
|
40
|
+
class RequestTimeout < Luchadeer::Error; end
|
41
|
+
|
42
|
+
class InvalidAPIKey < Luchadeer::Error; end
|
43
|
+
class URLFormatError < Luchadeer::Error; end
|
44
|
+
class FilterError < Luchadeer::Error; end
|
45
|
+
class SubscriberOnly < Luchadeer::Error; end
|
46
|
+
class BadRequest < Luchadeer::Error; end
|
47
|
+
class NotFound < Luchadeer::Error; end
|
48
|
+
class InternalServerError < Luchadeer::Error; end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
require 'faraday'
|
2
|
+
require 'set'
|
3
|
+
require 'luchadeer/error'
|
4
|
+
|
5
|
+
module Luchadeer
|
6
|
+
module Middleware
|
7
|
+
class FollowRedirects < Faraday::Response::Middleware
|
8
|
+
FOLLOW_LIMIT = 3
|
9
|
+
|
10
|
+
def call(env)
|
11
|
+
follow_redirect(env, FOLLOW_LIMIT)
|
12
|
+
end
|
13
|
+
|
14
|
+
private
|
15
|
+
|
16
|
+
def follow_redirect(env, follows)
|
17
|
+
request_body = env[:body]
|
18
|
+
response = @app.call(env)
|
19
|
+
|
20
|
+
response.on_complete do |env|
|
21
|
+
if follow_redirect?(env, response)
|
22
|
+
raise Luchadeer::Error::RedirectLimitReached, response if follows.zero?
|
23
|
+
|
24
|
+
env = update_env(env, request_body, response)
|
25
|
+
response = follow_redirect(env, follows - 1)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
response
|
30
|
+
end
|
31
|
+
|
32
|
+
def follow_redirect?(env, response)
|
33
|
+
env[:method] == :get and [301, 302, 303, 307].include? response.status
|
34
|
+
end
|
35
|
+
|
36
|
+
def update_env(env, request_body, response)
|
37
|
+
env[:url] += response['location']
|
38
|
+
env[:method] = :get
|
39
|
+
|
40
|
+
[:status, :response, :response_headers].each do |key|
|
41
|
+
env.delete key
|
42
|
+
end
|
43
|
+
|
44
|
+
env
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
Faraday::Response.register_middleware follow_redirects: Luchadeer::Middleware::FollowRedirects
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'faraday'
|
2
|
+
require 'luchadeer/error'
|
3
|
+
|
4
|
+
module Luchadeer
|
5
|
+
module Middleware
|
6
|
+
class ParseAPIError < Faraday::Response::Middleware
|
7
|
+
|
8
|
+
def on_complete(response)
|
9
|
+
klass = Luchadeer::Error.api_errors[response.body[:status_code]]
|
10
|
+
|
11
|
+
fail(klass.new(response.body[:error])) if klass
|
12
|
+
end
|
13
|
+
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
Faraday::Response.register_middleware parse_api_error: Luchadeer::Middleware::ParseAPIError
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'faraday'
|
2
|
+
require 'luchadeer/error'
|
3
|
+
|
4
|
+
module Luchadeer
|
5
|
+
module Middleware
|
6
|
+
class ParseHTTPError < Faraday::Response::Middleware
|
7
|
+
|
8
|
+
def on_complete(response)
|
9
|
+
klass = Luchadeer::Error.http_errors[response.status.to_i]
|
10
|
+
|
11
|
+
fail(klass.new) if klass
|
12
|
+
end
|
13
|
+
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
Faraday::Response.register_middleware parse_http_error: Luchadeer::Middleware::ParseHTTPError
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'faraday'
|
2
|
+
require 'json'
|
3
|
+
|
4
|
+
# adapted from the 'twitter' gem
|
5
|
+
# https://github.com/sferik/twitter/blob/88d7b19e295f27e1dcf970b979585fa9d3984cd6/lib/twitter/rest/response/parse_json.rb
|
6
|
+
module Luchadeer
|
7
|
+
module Middleware
|
8
|
+
class ParseJSON < Faraday::Response::Middleware
|
9
|
+
WHITESPACE_REGEX = /\A^\s*$\z/
|
10
|
+
|
11
|
+
def parse(body)
|
12
|
+
case body
|
13
|
+
when WHITESPACE_REGEX, nil
|
14
|
+
nil
|
15
|
+
else
|
16
|
+
JSON.parse(body, symbolize_names: true)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def on_complete(response)
|
21
|
+
response.body = parse(response.body)
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
Faraday::Response.register_middleware parse_json: Luchadeer::Middleware::ParseJSON
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module Luchadeer
|
2
|
+
class Resource < OpenStruct
|
3
|
+
|
4
|
+
# http://andreapavoni.com/blog/2013/4/create-recursive-openstruct-from-a-ruby-hash
|
5
|
+
def initialize(hash = nil)
|
6
|
+
@table = {}
|
7
|
+
@hash_table = {}
|
8
|
+
|
9
|
+
return unless hash
|
10
|
+
|
11
|
+
hash.each do |k, v|
|
12
|
+
@hash_table[k.to_sym] = v
|
13
|
+
@table[k.to_sym] = deep_structify(k, v)
|
14
|
+
new_ostruct_member(k)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def to_h
|
19
|
+
@hash_table
|
20
|
+
end
|
21
|
+
|
22
|
+
def detail
|
23
|
+
api_detail_url ? Luchadeer.client.fetch(api_detail_url, false, self.class) : self
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
|
28
|
+
def deep_structify(k, v)
|
29
|
+
case v
|
30
|
+
when Hash then Luchadeer::Resource.new(v)
|
31
|
+
when Array then v.map { |n| Luchadeer::Resource.new(n) }
|
32
|
+
else v
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'luchadeer/character'
|
2
|
+
require 'luchadeer/company'
|
3
|
+
require 'luchadeer/concept'
|
4
|
+
require 'luchadeer/franchise'
|
5
|
+
require 'luchadeer/game'
|
6
|
+
require 'luchadeer/location'
|
7
|
+
require 'luchadeer/object'
|
8
|
+
require 'luchadeer/person'
|
9
|
+
require 'luchadeer/video'
|
10
|
+
|
11
|
+
module Luchadeer
|
12
|
+
class Search
|
13
|
+
attr_accessor :query
|
14
|
+
|
15
|
+
RESOURCE_TYPES = {
|
16
|
+
'character' => Luchadeer::Character,
|
17
|
+
'company' => Luchadeer::Company,
|
18
|
+
'concept' => Luchadeer::Concept,
|
19
|
+
'franchise' => Luchadeer::Franchise,
|
20
|
+
'game' => Luchadeer::Game,
|
21
|
+
'location' => Luchadeer::Location,
|
22
|
+
'object' => Luchadeer::Object,
|
23
|
+
'person' => Luchadeer::Person,
|
24
|
+
'video' => Luchadeer::Video
|
25
|
+
}
|
26
|
+
|
27
|
+
def initialize(query)
|
28
|
+
@query = query
|
29
|
+
end
|
30
|
+
|
31
|
+
def fetch
|
32
|
+
Luchadeer.client.get('search', search_params).body[:results].map do |r|
|
33
|
+
type = r.delete(:resource_type)
|
34
|
+
RESOURCE_TYPES[type] && RESOURCE_TYPES[type].new(r)
|
35
|
+
end.compact
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
def search_params
|
41
|
+
{ query: @query }
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
45
|
+
end
|
data/luchadeer.gemspec
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'luchadeer/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = 'luchadeer'
|
8
|
+
spec.version = Luchadeer::VERSION
|
9
|
+
spec.authors = ['Paul Friedman']
|
10
|
+
spec.email = ['paulrfri@gmail.com']
|
11
|
+
spec.summary = %q{The bombingest Giant Bomb API client library for Ruby.}
|
12
|
+
spec.homepage = 'https://github.com/paulfri/luchadeer'
|
13
|
+
spec.license = 'MIT'
|
14
|
+
|
15
|
+
spec.files = `git ls-files`.split($/)
|
16
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
17
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
18
|
+
spec.require_paths = ['lib']
|
19
|
+
|
20
|
+
spec.add_dependency 'faraday', '~> 0.9.0'
|
21
|
+
|
22
|
+
spec.add_development_dependency 'bundler', '~> 1.5'
|
23
|
+
spec.add_development_dependency 'rake'
|
24
|
+
spec.add_development_dependency 'rspec'
|
25
|
+
spec.add_development_dependency 'webmock'
|
26
|
+
spec.add_development_dependency 'coveralls'
|
27
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Luchadeer::API::Characters do
|
4
|
+
let(:client) { Luchadeer::Client.new }
|
5
|
+
|
6
|
+
describe '#characters' do
|
7
|
+
let(:character_id) { 1 }
|
8
|
+
let(:character_path) { %r(#{Luchadeer::Client::GIANT_BOMB}/character/3005-#{character_id}) }
|
9
|
+
|
10
|
+
it 'requests the right url' do
|
11
|
+
stub = stub_request(:get, character_path).to_return(body: '{ }')
|
12
|
+
client.character("#{character_id}")
|
13
|
+
expect(stub).to have_been_requested
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'returns a Luchadeer::Character' do
|
17
|
+
stub_request(:get, character_path).to_return(body: '{ "results": { "key": "value"}}')
|
18
|
+
expect(client.character("#{character_id}")).to be_instance_of Luchadeer::Character
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'caches responses' do
|
22
|
+
stub_request(:get, character_path).to_return(body: '{ }')
|
23
|
+
expect(client).to receive :cache
|
24
|
+
client.character("#{character_id}")
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Luchadeer::API::Characters do
|
4
|
+
let(:client) { Luchadeer::Client.new }
|
5
|
+
|
6
|
+
describe '#companies' do
|
7
|
+
let(:company_id) { 1 }
|
8
|
+
let(:company_path) { %r(#{Luchadeer::Client::GIANT_BOMB}/company/3010-#{company_id}) }
|
9
|
+
|
10
|
+
it 'requests the right url' do
|
11
|
+
stub = stub_request(:get, company_path).to_return(body: '{ }')
|
12
|
+
client.company("#{company_id}")
|
13
|
+
expect(stub).to have_been_requested
|
14
|
+
end
|
15
|
+
|
16
|
+
it 'returns a Luchadeer::Company' do
|
17
|
+
stub_request(:get, company_path).to_return(body: '{ "results": { "key": "value"}}')
|
18
|
+
expect(client.company("#{company_id}")).to be_instance_of Luchadeer::Company
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'caches responses' do
|
22
|
+
stub_request(:get, company_path).to_return(body: '{ }')
|
23
|
+
expect(client).to receive :cache
|
24
|
+
client.company("#{company_id}")
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
28
|
+
end
|