Permalink
Browse files

Refactor code and add documentation.

* Add documentation for the main Battlenet class
* Refactor some code in Battlenet into private methods and modify
  specs accordingly
* Move individual API modules into Battlenet::Modules parent module
  • Loading branch information...
Brandon Tilley
Brandon Tilley committed Nov 27, 2011
1 parent 40753e9 commit 62a131c0263288aa362c24782d3d266773af8f36
View
@@ -3,3 +3,5 @@
Gemfile.lock
pkg/*
.rvmrc
+.yardoc/*
+doc/*
View
@@ -0,0 +1,8 @@
+--readme README.md
+--markup markdown
+--markup-provider redcarpet
+--title "Battlenet Documentation"
+lib/**/*.rb
+-
+README.md
+LICENSE
View
@@ -2,3 +2,9 @@ source "http://rubygems.org"
# Specify your gem's dependencies in battlenet.gemspec
gemspec
+
+group :documentation do
+ gem "yard"
+ gem "redcarpet"
+ gem "github-markup"
+end
View
@@ -79,6 +79,62 @@ If you would like to contribute to the project, please feel free to do so. Just
Please do not change the contents of the `VERSION` file, or if you do, do so in a separate commit so that I can cherry-pick around it.
+Setting Up the Development Environment
+--------------------------------------
+
+The development environment is managed with Bundler.
+
+To install just the gems you need to hack on Battlenet and run the specs, run
+
+ bundle install --without documentation
+
+To install all development gems, including the ones used to generate documentation, run
+
+ bundle install
+
+To run the specs, run
+
+ rake
+
+Writing an Integration Test
+---------------------------
+
+High-level integration testing against the Community Platform API is handled via VCR. After the first time running a spec that hits the API, VCR saves the HTTP response in a fixture file and uses this file to run against in the future.
+
+Here's an example (the character integration specs):
+
+ it "fetches character data" do
+ VCR.use_cassette('character_mortawa') do
+ character = api.character 'nazjatar', 'mortawa'
+ character['level'].should == 85
+ end
+ end
+
+ it "fetches additional character data" do
+ VCR.use_cassette('character_mortawa_titles') do
+ character = api.character 'nazjatar', 'mortawa', :fields => 'titles'
+ character['titles'].find { |t| t['selected'] == true }['name'].should == "Twilight Vanquisher %s"
+ end
+ end
+
+ it "fetches characters with non-ASCII characters in their name" do
+ VCR.use_cassette('character_nonstandard_name') do
+ character = api.character 'nazjatar', 'Hikô'
+ character['level'].should == 85
+ end
+ end
+
+You should always wrap tests that hit the actual API in the `VCR.use_cassette` block, and the resulting fixture file should be checked in with your test.
+
+Building the Documentation
+--------------------------
+
+If you have the necessary gems installed (defined in the `documentation` group in the Gemfile), you can easily generate the documentation via
+
+ yard
+
+The generated documentation can be found in `doc/`; open `doc/index.html` to view it.
+
License
=======
View
@@ -9,25 +9,75 @@
require 'battlenet/modules/arena'
require 'battlenet/modules/data'
+# Battlenet exposes the Blizzard Battle.net Community Platform API via an
+# easy-to-use interface.
+#
+# The main API class includes several Modules that define methods for collecting
+# specific API data. See the documentation for `Battlenet::Modules` for a list of
+# these modules.
+#
+# Specific details about the information returned from the API can be found at Blizzard's
+# [official Community Platform API documentation](https://blizzard.github.com/api-wow-docs/).
+#
+# @example Return basic information about a character named Cyaga from the US realm Nazjatar
+#
+# api = Battlenet.new :us
+# char = api.character 'Nazjatar', 'Cyaga'
+# puts char['level']
+# # => 85
+#
+# @example Return additional information about a character
+#
+# api = Battlenet.new :us
+# char = api.character 'Nazjatar', 'Cyaga', :fields => 'titles'
+# selected_title = char['titles'].find { |t| t['selected'] == true }
+# puts selected_title['name']
+# # => %s, Guardian of Cenarius
+#
+# @see Battlenet::Modules
+#
+# @author Brandon Tilley <brandon@brandontilley.com>
class Battlenet
+
+ # `Battlenet::Modules` is a namespace for modules that define methods that
+ # retrieve data from the Community Platform API. Methods for retrieving information
+ # about related resources are grouped in the same sub-Module. See documentation for
+ # the individual Modules for more information about the methods contained within.
+ module Modules; end
+
include HTTParty
- include Battlenet::Character
- include Battlenet::Guild
- include Battlenet::Realm
- include Battlenet::Auction
- include Battlenet::Item
- include Battlenet::Quest
- include Battlenet::Arena
- include Battlenet::Data
+ include Battlenet::Modules::Character
+ include Battlenet::Modules::Guild
+ include Battlenet::Modules::Realm
+ include Battlenet::Modules::Auction
+ include Battlenet::Modules::Item
+ include Battlenet::Modules::Quest
+ include Battlenet::Modules::Arena
+ include Battlenet::Modules::Data
class << self
+ # Whether or not to raise exceptions on non-200 responses from the API endpoint.
+ # A value of `false` causes exceptions to be raised. Defaults to `false`.
+ #
+ # @return [boolean]
attr_accessor :fail_silently
+
+ # The locale to use for API calls. Defaults to `nil`, which makes requests with
+ # no `locale` parameter set.
+ #
+ # @return [String|nil]
attr_accessor :locale
+
@fail_silently = false
@locale = nil
end
+ # Creates a new instance of the Battlenet API.
+ #
+ # @param region [Symbol] the region to perform API calls against.
+ # @param public [String|nil] the public key to use when signing requests
+ # @param private [String|nil] the private key to use when signing requests
def initialize(region = :us, public = nil, private = nil)
@public = public
@private = private
@@ -53,45 +103,75 @@ def initialize(region = :us, public = nil, private = nil)
self.class.base_uri @base_uri
end
- def fullpath(path)
- "#{@endpoint}#{path}"
- end
-
+ # Signs and performs an HTTP GET request. The request is only signed if a public and private
+ # key were provided during object instantiation.
+ #
+ # @param path (see #make_request)
+ # @param params (see #make_request)
+ # @return (see #make_request)
+ # @raise (see #make_request)
+ # @see (see #make_request)
def get(path, params = {})
make_request :get, path, params
end
- def make_request(verb, path, params = {})
- options = {}
- headers = {}
-
- if @public && @private
- now = Time.now
- signed = sign_request verb, path, now
- headers.merge!({
- "Authorization" => "BNET #{@public}:#{signed}",
- "Date" => now.httpdate
- })
+ private
+
+ # Returns the full URI for the given path based on the API endpoint set (varies by region).
+ #
+ # @return [String] the full URI for the path
+ def fullpath(path)
+ "#{@endpoint}#{path}"
end
- options[:headers] = headers unless headers.empty?
- options[:query] = params unless params.empty?
+ # Signs and performs an HTTP request. The request is only signed if a public and private
+ # key were provided during object instantiation.
+ #
+ # @param verb [Symbol] the HTTP verb to perform
+ # @param path [String] the path to GET
+ # @param params [Hash] options to be turned into query string parameters
+ # @return [Object] the response object from HTTParty
+ # @raise Exception if the response has a non-200 response and `Battlenet.fail_silently` is `false`
+ # @see http://rubydoc.info/github/jnunemaker/httparty/master/HTTParty/Response
+ # @private
+ def make_request(verb, path, params = {})
+ options = {}
+ headers = {}
- if Battlenet.locale
- options[:query] ||= {}
- options[:query].merge!({ :locale => Battlenet.locale })
- end
+ if @public && @private
+ now = Time.now
+ signed = sign_request verb, path, now
+ headers.merge!({
+ "Authorization" => "BNET #{@public}:#{signed}",
+ "Date" => now.httpdate
+ })
+ end
+
+ options[:headers] = headers unless headers.empty?
+ options[:query] = params unless params.empty?
+
+ if Battlenet.locale
+ options[:query] ||= {}
+ options[:query].merge!({ :locale => Battlenet.locale })
+ end
- response = self.class.send(verb, path, options)
+ response = self.class.send(verb, path, options)
- if response.code != 200 && Battlenet.fail_silently == false
- raise "Non-200 response: #{response.code}, #{response.body}"
+ if response.code != 200 && Battlenet.fail_silently == false
+ raise "Non-200 response: #{response.code}, #{response.body}"
+ end
+ response
end
- response
- end
- def sign_request(verb, path, time)
- auth = Battlenet::Authentication.new @private
- auth.sign verb, fullpath(path), time
- end
+ # Signs an HTTP request.
+ #
+ # @param verb [Symbol] the HTTP verb for the request being signed
+ # @param path [String] the path for the rquest being signed
+ # @param time [Time] the time to use when signing the request
+ # @return [String] value to be used as the final portion of the `Authorization` HTTP header
+ # @see Battlenet::Authentication
+ def sign_request(verb, path, time)
+ auth = Battlenet::Authentication.new @private
+ auth.sign verb, fullpath(path), time
+ end
end
@@ -1,13 +1,15 @@
require 'uri'
class Battlenet
- module Arena
- def arena(realm, size, name, options = {})
- realm = URI.escape realm
- size = URI.escape size
- name = URI.escape name
+ module Modules
+ module Arena
+ def arena(realm, size, name, options = {})
+ realm = URI.escape realm
+ size = URI.escape size
+ name = URI.escape name
- get "/arena/#{realm}/#{size}/#{name}", options
+ get "/arena/#{realm}/#{size}/#{name}", options
+ end
end
end
end
@@ -1,18 +1,20 @@
require 'uri'
class Battlenet
- module Auction
- def auction(realm, options = {})
- realm = URI.escape realm
+ module Modules
+ module Auction
+ def auction(realm, options = {})
+ realm = URI.escape realm
- get "/auction/data/#{realm}", options
- end
+ get "/auction/data/#{realm}", options
+ end
- def auction_data(realm, options = {})
- data = auction(realm, options)
- files = data["files"].first
- url = files["url"]
- get url
+ def auction_data(realm, options = {})
+ data = auction(realm, options)
+ files = data["files"].first
+ url = files["url"]
+ get url
+ end
end
end
end
@@ -1,12 +1,14 @@
require 'uri'
class Battlenet
- module Character
- def character(realm, name, options = {})
- realm = URI.escape realm
- name = URI.escape name
+ module Modules
+ module Character
+ def character(realm, name, options = {})
+ realm = URI.escape realm
+ name = URI.escape name
- get "/character/#{realm}/#{name}", options
+ get "/character/#{realm}/#{name}", options
+ end
end
end
end
Oops, something went wrong.

0 comments on commit 62a131c

Please sign in to comment.