forked from BinaryMuse/battlenet
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Brandon Tilley
committed
Apr 15, 2011
1 parent
69ffe83
commit 824dbdd
Showing
11 changed files
with
352 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,2 @@ | ||
module Battlenet | ||
# Your code goes here... | ||
end | ||
require 'battlenet/api' | ||
require 'battlenet/api/realm' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
module Battlenet | ||
module Adapter | ||
class NotImplementedException < Exception; end | ||
|
||
class AbstractAdapter | ||
def get(url) | ||
raise NotImplementedException.new("Please implement #get in your adapter") | ||
end | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
require 'battlenet/adapter/abstract_adapter' | ||
require 'net/http' | ||
|
||
module Battlenet | ||
module Adapter | ||
class NetHTTP < AbstractAdapter | ||
def get(url) | ||
uri = URI.parse url | ||
response = Net::HTTP.get_response uri | ||
[response.code.to_i, response.body] | ||
end | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
require 'battlenet/adapter/abstract_adapter' | ||
require 'typhoeus' | ||
|
||
module Battlenet | ||
module Adapter | ||
class Typhoeus < AbstractAdapter | ||
def get(url) | ||
response = ::Typhoeus::Request.get url | ||
[response.code.to_i, response.body] | ||
end | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
module Battlenet | ||
module Adapter; end | ||
|
||
module AdapterManager | ||
class InvalidAdapter < Exception; end | ||
|
||
extend self | ||
|
||
@adapters = { | ||
:net_http => "NetHTTP", | ||
:typhoeus => "Typhoeus" | ||
} | ||
|
||
def adapters | ||
@adapters | ||
end | ||
|
||
def fetch(adapter_name) | ||
unless adapters.include? adapter_name | ||
raise InvalidAdapter.new("#{adapter_name.to_s} is not a valid adapter") | ||
end | ||
|
||
adapter_class = adapters[adapter_name] | ||
adapter = load_adapter adapter_name, adapter_class | ||
end | ||
|
||
private | ||
|
||
def load_adapter(adapter_name, klass_name) | ||
begin | ||
klass = Battlenet::Adapter.const_get("#{klass_name}", false) | ||
rescue NameError | ||
begin | ||
adapter_file = "battlenet/adapter/#{adapter_name.to_s}" | ||
require adapter_file | ||
klass = Battlenet::Adapter.const_get("#{klass_name}", false) | ||
rescue LoadError | ||
raise InvalidAdapter.new("adapter #{klass_name} does not exist, and file #{adapter_file} does not exist") | ||
rescue NameError | ||
raise InvalidAdapter.new("expected #{adapter_file} to define Battlenet::Adapter::#{klass_name}") | ||
end | ||
end | ||
|
||
return klass.new | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
require 'battlenet/adapter_manager' | ||
require 'cgi' | ||
require 'json' | ||
|
||
module Battlenet | ||
module API | ||
class APIError < Exception | ||
attr_reader :code, :body | ||
def initialize(code, body) | ||
@code = code | ||
@body = body | ||
end | ||
|
||
def to_s | ||
"Status: #{code} Body: #{body}" | ||
end | ||
end | ||
|
||
extend self | ||
|
||
@config = { | ||
:indifferent_hashes => true, | ||
:http_adapter => :net_http, | ||
:region => :us | ||
} | ||
|
||
def set_option(setting, value) | ||
@config[setting] = value | ||
end | ||
|
||
def get_option(setting, default = nil) | ||
@config[setting] || default | ||
end | ||
|
||
def adapter | ||
@adapter ||= Battlenet::AdapterManager.fetch get_option(:http_adapter) | ||
end | ||
|
||
def base_url | ||
region = get_option(:region, :us).to_s | ||
"http://#{region}.battle.net/api/wow" | ||
end | ||
|
||
def make_api_call(path, query = {}) | ||
query_string = query.empty? ? '' : make_query_string(query) | ||
url = base_url | ||
url << (path.start_with?('/') ? '' : '/') | ||
url << path | ||
url << query_string | ||
code, body = get url | ||
raise APIError.new(code, body) unless code == 200 | ||
JSON::parse body | ||
end | ||
|
||
def get(url) | ||
adapter.get(url) | ||
end | ||
|
||
def make_query_string(query) | ||
query_string = "?" | ||
query.each do |key, value| | ||
case value | ||
when String | ||
query_string << "#{key}=#{CGI.escape value}&" | ||
when Array | ||
value.each { |v| query_string << "#{key}=#{CGI.escape v}&" } | ||
end | ||
end | ||
|
||
query_string.chomp("&").chomp("?") | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
module Battlenet | ||
module API | ||
module Realm | ||
extend self | ||
|
||
@api = Battlenet::API | ||
|
||
def status(options = {}) | ||
data = @api.make_api_call 'realm/status', options | ||
data["realms"] | ||
end | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,3 @@ | ||
module Battlenet | ||
VERSION = "0.0.0" | ||
VERSION = "0.1.0" | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
require 'battlenet/adapter/abstract_adapter' | ||
|
||
describe Battlenet::Adapter::AbstractAdapter do | ||
it "has a method 'get'" do | ||
subject.should respond_to :get | ||
end | ||
|
||
context "#get" do | ||
it "is abstract" do | ||
lambda { | ||
subject.get('fake_url') | ||
}.should raise_error Battlenet::Adapter::NotImplementedException | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
require 'battlenet/adapter_manager' | ||
|
||
describe Battlenet::AdapterManager do | ||
it "has a list of adapters" do | ||
subject.adapters.should be_a Hash | ||
end | ||
|
||
context "#fetch" do | ||
it "raises an exception if an invalid adapter is passed" do | ||
lambda { | ||
subject.fetch(:some_fake_adapter) | ||
}.should raise_error Battlenet::AdapterManager::InvalidAdapter | ||
end | ||
|
||
it "requires a library file based on the adapter chosen if the class doesn't exist" do | ||
subject.should_receive(:require).once.with('battlenet/adapter/net_http') | ||
begin | ||
subject.fetch(:net_http) | ||
rescue Battlenet::AdapterManager::InvalidAdapter | ||
# expected | ||
end | ||
end | ||
|
||
it "raises an error if the adapter class doesn't exist and the library can't be loaded" do | ||
old_adapters = subject.adapters | ||
subject.instance_variable_set(:@adapters, {:adapter => "SuperAdapter"}) | ||
|
||
lambda { | ||
subject.fetch(:adapter) | ||
}.should raise_error Battlenet::AdapterManager::InvalidAdapter, /does not exist/ | ||
|
||
subject.instance_variable_set(:@adapters, old_adapters) | ||
end | ||
|
||
it "raises an error if the adapter library is loaded but doesn't define the adapter class" do | ||
subject.should_receive(:require).once.with('battlenet/adapter/net_http').and_return(nil) | ||
lambda { | ||
subject.fetch(:net_http) | ||
}.should raise_error Battlenet::AdapterManager::InvalidAdapter, /expected (.*) to define/ | ||
end | ||
|
||
it "returns an instance of the adapter" do | ||
adapter = subject.fetch(:net_http) | ||
adapter.should be_a Battlenet::Adapter::NetHTTP | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,115 @@ | ||
require 'battlenet/api' | ||
|
||
describe Battlenet::API do | ||
context "configuration management" do | ||
it "defauls to nil when getting an unset option" do | ||
subject.get_option(:a_fake_setting_i_made_up).should be_nil | ||
end | ||
|
||
it "returns a passed value if an option is not set" do | ||
subject.get_option(:a_fake_setting_i_made_up, "value").should == "value" | ||
end | ||
|
||
it "allows setting and retrieving a value" do | ||
subject.set_option(:a_fake_setting_i_made_up, "my_value") | ||
subject.get_option(:a_fake_setting_i_made_up).should == "my_value" | ||
end | ||
end | ||
|
||
context "default configuration" do | ||
it "defaults to the US region" do | ||
subject.get_option(:region).should == :us | ||
end | ||
|
||
it "defaults to indifferent hashes" do | ||
subject.get_option(:indifferent_hashes).should == true | ||
end | ||
|
||
it "defaults to the Net::HTTP library" do | ||
subject.get_option(:http_adapter).should == :net_http | ||
end | ||
end | ||
|
||
context "HTTP adapter" do | ||
it "retrieval is via the Adapter module" do | ||
adapter = subject.get_option(:http_adapter) | ||
Battlenet::AdapterManager.should_receive(:fetch).with(adapter) | ||
subject.send(:adapter) | ||
end | ||
|
||
it "caches its adapter" do | ||
mock_adapter = mock("adapter") | ||
Battlenet::AdapterManager.should_receive(:fetch).with(any_args()).and_return(mock_adapter) | ||
adapter = subject.send(:adapter) | ||
subject.set_option(:http_adapter, :fake_adapter) | ||
subject.send(:adapter).should == mock_adapter | ||
end | ||
end | ||
|
||
it "returns a base URL dependant on the region" do | ||
old_region = subject.get_option(:region) | ||
subject.set_option(:region, :eu) | ||
subject.send(:base_url).should == "http://eu.battle.net/api/wow" | ||
subject.set_option(:region, old_region) | ||
end | ||
|
||
context "#make_query_string" do | ||
it "produces an empty string with an empty hash" do | ||
str = subject.send(:make_query_string, {}) | ||
str.should be_empty | ||
end | ||
|
||
it "starts with a question mark" do | ||
str = subject.send(:make_query_string, {:first => "value1", :second => "value2"}) | ||
str.start_with?("?").should == true | ||
end | ||
|
||
it "parses a basic hash" do | ||
str = subject.send(:make_query_string, {:first => "value1", :second => "value2"}) | ||
str.should == "?first=value1&second=value2" | ||
end | ||
|
||
it "parses a hash with array values" do | ||
str = subject.send(:make_query_string, {:first => ["value1", "value2"], :second => "value3"}) | ||
str.should == "?first=value1&first=value2&second=value3" | ||
end | ||
|
||
it "escapes values" do | ||
str = subject.send(:make_query_string, {:first => ["value1", "va&lue2"], :second => "val&ue3"}) | ||
str.should == "?first=value1&first=va%26lue2&second=val%26ue3" | ||
end | ||
end | ||
|
||
context "#make_api_call" do | ||
it "makes a get call with the correct URL" do | ||
subject.should_receive(:get).once.with("http://us.battle.net/api/wow/my/path").and_return([200, '{"testing": "value"}']) | ||
subject.send(:make_api_call, '/my/path') | ||
end | ||
|
||
it "adds a slash to the path if necessary" do | ||
subject.should_receive(:get).once.with("http://us.battle.net/api/wow/my/path").and_return([200, '{"testing": "value"}']) | ||
subject.send(:make_api_call, 'my/path') | ||
end | ||
|
||
it "converts the second parameter into a query string" do | ||
options = {:first => ["value1", "va&lue2"], :second => "val&ue3"} | ||
query_string = subject.send(:make_query_string, options) | ||
subject.should_receive(:get).once.with("http://us.battle.net/api/wow/my/path#{query_string}").and_return([200, '{"testing": "value"}']) | ||
subject.send(:make_api_call, 'my/path', options) | ||
end | ||
|
||
it "raises an exception on an error" do | ||
subject.adapter.should_receive(:get).and_return([404, "not found"]) | ||
lambda { | ||
subject.make_api_call('my/path') | ||
}.should raise_error Battlenet::API::APIError, /404 (.*) not found/ | ||
end | ||
|
||
it "returns the data as JSON" do | ||
subject.adapter.should_receive(:get).and_return([200, '{"testing": "value"}']) | ||
data = subject.make_api_call('my/path') | ||
data.should be_a Hash | ||
data["testing"].should == "value" | ||
end | ||
end | ||
end |