bn 0.0.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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 2822afc6d969ba0f64f38060a6408eaa684b9ef8
4
+ data.tar.gz: 0d13387ecc63fdfa99d4ccdd8d4a061f614cdae1
5
+ SHA512:
6
+ metadata.gz: 5d7f33cb1db092af1f8bd7add060a4424cbfa4e1b5990d37c7dc44e9d35f7ca6c3db8b16a36c627a69682378210774552c4fc551c2b66206e5f92c1f069a8b5d
7
+ data.tar.gz: 7424238727dd121b472b3e0c5d7b78a32a860bc44d2d24891c75ad5790eb585a588e914f4053043b9aeda41b7a890f376c8b779cfd59c5fb25d9d46854d1df60
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source "https://rubygems.org"
2
+
3
+ gemspec
@@ -0,0 +1,22 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ bn (0.0.1)
5
+ httpi (~> 2.4.1)
6
+ version (~> 1.0.0)
7
+
8
+ GEM
9
+ remote: https://rubygems.org/
10
+ specs:
11
+ httpi (2.4.1)
12
+ rack
13
+ rack (1.6.4)
14
+ rake (10.4.2)
15
+ version (1.0.0)
16
+
17
+ PLATFORMS
18
+ ruby
19
+
20
+ DEPENDENCIES
21
+ bn!
22
+ rake (~> 10.4.2)
@@ -0,0 +1,202 @@
1
+ # BN
2
+
3
+ BN is a [Battle.net](http://battle.net) API adapter and entity mapper.
4
+
5
+ ## Install
6
+
7
+ ### Bundler: `gem 'bn'`
8
+
9
+ ### RubyGems: `gem install bn`
10
+
11
+ ## Usage
12
+
13
+ ### Requiring
14
+
15
+ You can require the whole library with
16
+
17
+ ```rb
18
+ require "bn"
19
+ ```
20
+
21
+ Or you can require individual files/groups of files with
22
+
23
+ ```rb
24
+ require "bn/api/d3"
25
+ require "bn/entity/d3"
26
+ ```
27
+
28
+ ### API
29
+
30
+ **Mapping**
31
+
32
+ The `BN::API::Mapper` will send an HTTP request, parse the JSON response body, and create a new instance of
33
+ the entity associated with the API call.
34
+
35
+ ```rb
36
+ require "bn/api/mapper"
37
+
38
+ mapper = BN::API::Mapper.new(key: "00000000000000000000000000000000")
39
+
40
+ p mapper.d3.profile(battle_tag: "Example#0000") #=> #<BN::Entity::D3::Profile:0x007fa2a10e29a0 @battle_tag="Example#0000" ...>
41
+ ```
42
+
43
+ If called without arguments, the mapper will return a `BN::API::Mapping` instance, which associates API calls with
44
+ `Entity` instances. It also holds the list of middleware which the API HTTP response will go through before returning:
45
+
46
+ ```rb
47
+ require "bn/api/mapper"
48
+
49
+ mapper = BN::API::Mapper.new(key: "00000000000000000000000000000000")
50
+ mapping = mapper.d3.profile
51
+
52
+ p mapping.api_class # => BN::API::D3
53
+ p mapping.api_method # => :profile
54
+ p mapping.middleware # => [BN::Middleware::HTTPResponse, BN::Middleware::KeyConverter, BN::Middleware::APIError, BN::Middleware::D3::Profile]
55
+
56
+ mapping.execute(battle_tag: "Example#0000") #=> #<BN::Entity::D3::Profile:0x007fa2a10e29a0 @battle_tag="Example#0000" ...>
57
+ ```
58
+
59
+ This would allow you to manipulate the middleware before executing.
60
+
61
+ [Read more about middleware here.](#middleware)
62
+
63
+ **HTTP**
64
+
65
+ This simply sends an HTTP request to the API and returns it.
66
+ Useful for when you do not need entities or middleware.
67
+
68
+ ```rb
69
+ require "bn/api/d3"
70
+
71
+ api = BN::API::D3.new(key: "00000000000000000000000000000000")
72
+
73
+ p api.profile(battle_tag: "Example#0000") #=> #<HTTPI::Response:0x007fa2a0d0a5d0 @code=301 ...>
74
+ ```
75
+
76
+ ### Entity
77
+
78
+ An entity is a subclass of `BN::Entity::Base` for profiles, characters, items, and other game items.
79
+
80
+ You can initialize entities with an object responding to `#to_h` or use attribute setters after initialization.
81
+
82
+ ```rb
83
+ require "bn/entity/d3/hero"
84
+
85
+ hero = BN::Entity::D3::Hero.new(name: "Gronc")
86
+ hero.level = 70
87
+ ```
88
+
89
+ Some entities also come with some helper methods for calculations:
90
+
91
+ ```rb
92
+ hero.strength = 220
93
+
94
+ # Calculate the damage per second based on hero attributes
95
+ p hero.damage # => 12345
96
+ ```
97
+
98
+ ### Middleware
99
+
100
+ Middleware converts data from one form to another, raising an error on failure.
101
+
102
+ For example, the `BN::Middleware::HTTPResponse` accepts anything that responds to `#body` and attempts to parse
103
+ the body as JSON. If the response body could not be parsed or the JSON API response returned an error, then an error
104
+ will be raised.
105
+
106
+ This is useful if you're not using `BN::API` to send HTTP requests to the Battle.net API.
107
+
108
+ ```rb
109
+ require "net/http"
110
+ require "uri"
111
+ require "bn/middleware/http_response"
112
+
113
+ uri = URI("https://us.api.battle.net/d3/profile/Example-0000")
114
+ uri.query = URI.encode_www_form(apikey: "00000000000000000000000000000000", locale: "en_US")
115
+
116
+ response = Net::HTTP.get_response(uri)
117
+ data = BN::Middleware::HTTPResponse.execute(response)
118
+
119
+ p data # => { battle_tag: "Example#0000" }
120
+ ```
121
+
122
+ **Chaining**
123
+
124
+ Middleware can be chained together if the result of one conforms to the requirements of another:
125
+
126
+ ```rb
127
+ require "bn/api/d3"
128
+ require "bn/middleware/http_response"
129
+ require "bn/middleware/d3/profile"
130
+
131
+ api = BN::API::D3.new(key: "00000000000000000000000000000000")
132
+
133
+ response = api.profile(battle_tag: "Example#0000")
134
+
135
+ data = BN::Middleware::HTTPResponse.execute(response)
136
+ profile = BN::Middleware::D3::Profile.execute(data)
137
+
138
+ p profile #=> #<BN::Entity::D3::Profile:0x007fa2a10e29a0 @battle_tag="Example#0000" ...>
139
+ ```
140
+
141
+ To make chaining easier, there is a helper method on `BN::Middleware`:
142
+
143
+ ```rb
144
+ require "bn/api/d3"
145
+ require "bn/middleware"
146
+
147
+ api = BN::API::D3.new(key: "00000000000000000000000000000000")
148
+
149
+ response = api.profile(battle_tag: "Example#0000")
150
+
151
+ data = BN::Middleware::HTTPResponse.execute(response)
152
+ profile = BN::Middleware::D3::Profile.execute(data)
153
+ profile = BN::Middleware.execute(data, BN::Middleware::HTTPResponse, BN::Middleware::D3::Profile)
154
+
155
+ p profile #=> #<BN::Entity::D3::Profile:0x007fa2a10e29a0 @battle_tag="Example#0000" ...>
156
+ ```
157
+
158
+ Middleware given can either be classes or instances. Usually subclassed from `BN::Middleware::Base`, but can be anything
159
+ responding to `#execute`.
160
+
161
+ **Subclassing**
162
+
163
+ You can subclass `BN::Middleware::Base` to create your own transformations, such as manipulating JSON API responses
164
+ or initializing your own profile/item/etc objects:
165
+
166
+ ```rb
167
+ require "bn/middleware/base"
168
+
169
+ class HeroMiddleware < BN::Middleware::Base
170
+ def execute(data)
171
+ hero_data = data[:heroes].first
172
+
173
+ Hero.new(data[:hero_data])
174
+ end
175
+ end
176
+
177
+ class Hero
178
+ def initialize(name)
179
+ @name = name
180
+ end
181
+
182
+ attr_reader :name
183
+ end
184
+
185
+ require "bn/api/d3"
186
+ require "bn/middleware/http_response"
187
+
188
+ api = BN::API::D3.new(key: "00000000000000000000000000000000")
189
+
190
+ response = api.hero(battle_tag: "Example#0000", id: 1234)
191
+
192
+ data = BN::Transform::HTTPResponse.execute(response)
193
+ hero = HeroTransform.execute(data)
194
+
195
+ p hero #=> #<Hero:0x007fa2a10e29a0 @name="Gronc">
196
+ ```
197
+
198
+ ## Copyright
199
+
200
+ Copyright © 2015 Ryan Scott Lewis <ryan@rynet.us>.
201
+
202
+ The MIT License (MIT) - See LICENSE for further details.
@@ -0,0 +1,14 @@
1
+ require "pathname"
2
+ require "rake/version_task"
3
+ require "rubygems/package_task"
4
+
5
+ gemspec = Pathname.glob(Pathname.new(__FILE__).join("..", "*.gemspec")).first
6
+ $spec = Gem::Specification.load(gemspec.to_s)
7
+
8
+ Gem::PackageTask.new($spec) do |task|
9
+ task.need_zip = false
10
+ end
11
+
12
+ Rake::VersionTask.new do |task|
13
+ task.with_git_tag = true
14
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.0.1
@@ -0,0 +1,23 @@
1
+ require "pathname"
2
+
3
+ Gem::Specification.new do |s|
4
+ # Variables
5
+ s.author = "Ryan Scott Lewis"
6
+ s.email = "ryan@rynet.us"
7
+ s.summary = "A Battle.net API adapter and entity mapper."
8
+ s.license = "MIT"
9
+
10
+ # Dependencies
11
+ s.add_dependency "version", "~> 1.0.0"
12
+ s.add_dependency "httpi", "~> 2.4.1"
13
+ s.add_development_dependency "rake", "~> 10.4.2"
14
+
15
+ # Pragmatically set variables
16
+ s.homepage = "http://github.com/RyanScottLewis/#{s.name}"
17
+ s.version = Pathname.glob("VERSION*").first.read rescue "0.0.0"
18
+ s.description = s.summary
19
+ s.name = Pathname.new(__FILE__).basename(".gemspec").to_s
20
+ s.require_paths = ["lib"]
21
+ s.files = Dir["{{Rake,Gem}file{.lock,},README*,VERSION,LICENSE,*.gemspec,{lib,bin,examples,spec,test}/**/*}"]
22
+ s.test_files = Dir["{examples,spec,test}/**/*"]
23
+ end
@@ -0,0 +1,9 @@
1
+ require "version"
2
+
3
+ # Battle.net adapter and entity mapper.
4
+ module BN
5
+ is_versioned
6
+ end
7
+
8
+ require "bn/api"
9
+ require "bn/middleware"
@@ -0,0 +1,19 @@
1
+ module BN
2
+ # The API requestors.
3
+ module API
4
+ # The valid regions for the API.
5
+ # Contains name, host, and valid locales for each region.
6
+ REGIONS = {
7
+ us: { name: "US", uri: "https://us.api.battle.net", locales: %w(en_US es_MX pt_BR) },
8
+ eu: { name: "Europe", uri: "https://us.api.battle.net", locales: %w(en_GB es_ES fr_FR ru_RU de_DE pt_PT it_IT) },
9
+ kr: { name: "Korea", uri: "https://kr.api.battle.net", locales: %w(ko_KR) },
10
+ tw: { name: "Taiwan", uri: "https://tw.api.battle.net", locales: %w(zh_TW) },
11
+ cn: { name: "China", uri: "https://api.battlenet.com.cn", locales: %w(zh_CN) },
12
+ sea: { name: "South East Asia", uri: "https://sea.api.battle.net", locales: %w(en_US) }
13
+ }
14
+ end
15
+ end
16
+
17
+ require "bn/api/d3"
18
+ require "bn/api/sc2"
19
+ require "bn/api/wow"
@@ -0,0 +1,78 @@
1
+ require "httpi"
2
+ require "bn/helpers/has_attributes"
3
+ require "bn/error/api/invalid_key"
4
+ require "bn/error/api/invalid_region"
5
+ require "bn/error/api/invalid_locale"
6
+
7
+ module BN
8
+ module API
9
+ # The base class for API requesters.
10
+ class Base
11
+ include Helpers::HasAttributes
12
+
13
+ def initialize(attributes={})
14
+ self.region = :us
15
+
16
+ super
17
+
18
+ raise Error::API::InvalidKey if @key.nil?
19
+ end
20
+
21
+ attribute(:key) { |value| validate_key(value) }
22
+
23
+ attribute(:region) { |value| validate_and_convert_region(value) }
24
+
25
+ attribute(:locale) { |value| validate_locale(value) }
26
+
27
+ protected
28
+
29
+ # Send an HTTP GET request.
30
+ #
31
+ # @param [#to_s] url
32
+ # @param [#to_h] query
33
+ # @return [HTTPI::Response]
34
+ def get(url, query={})
35
+ url = url.to_s.gsub(%r{^/}, "")
36
+ query = query.to_h
37
+
38
+ request = HTTPI::Request.new
39
+ request.url = "#{@region[:host]}/#{url}"
40
+ request.query = { apikey: @key, locale: @locale }.merge(query)
41
+
42
+ HTTPI.get(request)
43
+ end
44
+
45
+ def validate_key(value)
46
+ value = value.to_s.delete(" ")
47
+
48
+ raise Error::API::InvalidKey if value.empty?
49
+
50
+ value
51
+ end
52
+
53
+ def validate_and_convert_region(region_key)
54
+ region_key = region_key.to_sym
55
+
56
+ raise Error::API::InvalidRegion unless BN::API::REGIONS.keys.include?(region_key)
57
+
58
+ region = REGIONS[region_key]
59
+ @locale = region[:locales].first
60
+
61
+ region
62
+ end
63
+
64
+ def validate_locale(locale)
65
+ locale = locale.to_s.strip
66
+ locale = @region[:locales].first if locale.empty?
67
+
68
+ raise Error::API::InvalidLocale, region: @region unless @region[:locales].include?(locale)
69
+
70
+ locale
71
+ end
72
+
73
+ def sanitize_battle_tag(value)
74
+ value.to_s.delete(" ").gsub(/#/, "-")
75
+ end
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,44 @@
1
+ require "bn/api/base"
2
+
3
+ module BN
4
+ module API
5
+ # The the Diablo 3 API requester.
6
+ class D3 < Base
7
+ # Request a profile.
8
+ #
9
+ # @param [#to_h] options
10
+ # @option options [#to_s] :battle_tag The battle tag.
11
+ # @return [HTTPI::Response]
12
+ def profile(options={})
13
+ options = options.to_h
14
+
15
+ battle_tag = sanitize_battle_tag(options.delete(:battle_tag))
16
+
17
+ get("/d3/profile/#{battle_tag}", options)
18
+ end
19
+
20
+ # Request a hero.
21
+ #
22
+ # @param [#to_h] options
23
+ # @option options [#to_s] :battle_tag The battle tag.
24
+ # @option options [#to_s] :id The hero's ID.
25
+ # @return [HTTPI::Response]
26
+ def hero(options={})
27
+ options = options.to_h
28
+
29
+ battle_tag = sanitize_battle_tag(options.delete(:battle_tag))
30
+ id = sanitize_id(options.delete(:id))
31
+
32
+ get("/d3/profile/#{battle_tag}/hero/#{id}", options)
33
+ end
34
+
35
+ protected
36
+
37
+ def sanitize_id(id)
38
+ id = id.to_s.gsub(/[^0-9]/, "") unless id.is_a?(Integer)
39
+
40
+ id.to_i
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,74 @@
1
+ require "bn/api/base"
2
+
3
+ module BN
4
+ module API
5
+ # The the StarCraft 3 API requester.
6
+ class SC3 < Base
7
+ # Request a profile.
8
+ #
9
+ # @param [#to_h] options
10
+ # @option options [#to_s] :id The ID of the profile.
11
+ # @option options [#to_s] :region The region of the profile.
12
+ # @option options [#to_s] :name The name of the profile
13
+ # @return [HTTPI::Response]
14
+ def profile(options={})
15
+ get(profile_uri(options))
16
+ end
17
+
18
+ # Request a profile's ladders.
19
+ #
20
+ # @param [#to_h] options
21
+ # @option options [#to_s] :id The ID of the profile.
22
+ # @option options [#to_s] :region The region of the profile.
23
+ # @option options [#to_s] :name The name of the profile
24
+ # @return [HTTPI::Response]
25
+ def ladders(options={})
26
+ get(profile_uri(options, "ladders"))
27
+ end
28
+
29
+ # Request a profile's matches.
30
+ #
31
+ # @param [#to_h] options
32
+ # @option options [#to_s] :id The ID of the profile.
33
+ # @option options [#to_s] :region The region of the profile.
34
+ # @option options [#to_s] :name The name of the profile
35
+ # @return [HTTPI::Response]
36
+ def matches(options={})
37
+ get(profile_uri(options, "matches"))
38
+ end
39
+
40
+ # Request a ladder.
41
+ #
42
+ # @param [#to_h] options
43
+ # @option options [#to_s] :id The ID of the ladder.
44
+ # @return [HTTPI::Response]
45
+ def ladder(options={})
46
+ options = options.to_h
47
+
48
+ get("/sc2/ladder/#{options[:id]}")
49
+ end
50
+
51
+ # Request achievements.
52
+ #
53
+ # @return [HTTPI::Response]
54
+ def achievements
55
+ get("/sc2/data/achievements")
56
+ end
57
+
58
+ # Request rewards.
59
+ #
60
+ # @return [HTTPI::Response]
61
+ def achievements
62
+ get("/sc2/data/rewards")
63
+ end
64
+
65
+ protected
66
+
67
+ def profile_uri(options, path=nil)
68
+ options = options.to_h
69
+
70
+ "/sc2/profile/#{options[:id]}/#{options[:region]}/#{options[:name]}#{"/#{path}" unless path.nil?}"
71
+ end
72
+ end
73
+ end
74
+ end