ruby-lol 1.0.0 → 1.1.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 7473a66c2ba969476e7a30e8fe148e4c974dc70b
4
- data.tar.gz: c50df90099feec488dca9afd5c17ba85624ca915
3
+ metadata.gz: f57d825feb79e42f3ebd252a9925ff247c6fd13d
4
+ data.tar.gz: 58acfbbf4839d94e1bfeaccb4161f0ddd9df2016
5
5
  SHA512:
6
- metadata.gz: a7efd709d007876b0c9e8972cc4b8af6d91c0956a4c1c695f2c5ae69c8652097539526d3bd3c33bfd4c5ea00046b2139981cd3bc0a3f9b90922ac8ca9dd2e996
7
- data.tar.gz: 5d27adae5e92111f5ec95bcc74a1b7f44f176509576773c3ee8cf59e0953c10acfaf291c93ac58ef575c5952f1e4eb80d594697135647f2e2a4aa2c0dd02f812
6
+ metadata.gz: a693d189f419894e304e744b9ddafcddf9dedee2dd5adf35daa4047621d113520b17f018aa4fcb7890f80625ce64270a89995b3ef5c66c40964fe20b82b2804a
7
+ data.tar.gz: b7a9734744ba482d66ae9e7c4e1b78e1fc722f1c18a307cede2563267436a5520b8241b1f0c60b52f7b44ec42b126d078b1af7a5d73ca7ef867182655a579a5a
data/Guardfile CHANGED
@@ -1,7 +1,7 @@
1
1
  # A sample Guardfile
2
2
  # More info at https://github.com/guard/guard#readme
3
3
 
4
- guard :rspec do
4
+ guard :rspec, cmd: "bundle exec rspec" do
5
5
  watch(%r{^spec/.+_spec\.rb$})
6
6
  watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
7
7
  watch('spec/spec_helper.rb') { "spec" }
@@ -21,4 +21,3 @@ guard :rspec do
21
21
  watch(%r{^spec/acceptance/(.+)\.feature$})
22
22
  watch(%r{^spec/acceptance/steps/(.+)_steps\.rb$}) { |m| Dir[File.join("**/#{m[1]}.feature")][0] || 'spec/acceptance' }
23
23
  end
24
-
data/README.md CHANGED
@@ -27,12 +27,15 @@ Or install it yourself as:
27
27
  ```ruby
28
28
  require 'lol'
29
29
 
30
- client = Lol::Client.new "my_api_key", {region: "euw"}
30
+ client = Lol::Client.new "my_api_key", region: "euw"
31
31
  # => <Lol::Client:0x000000020c0b28 @api_key="my_api_key", @region="euw", @cached=false>
32
32
 
33
- # NEW! You can cache requests using Redis now
33
+ # You can cache requests using Redis now
34
34
  # ttl defaults to 900
35
- client = Lol::Client.new "my_api_key", {region: "euw", redis: "redis://localhost:6379", ttl: 900}
35
+ client = Lol::Client.new "my_api_key", region: "euw", redis: "redis://localhost:6379", ttl: 900
36
+
37
+ # You can specify your rate limits so that the library will throttle requests to avoid errors
38
+ client = Lol::Client.new "new_api_key", region: "euw", rate_limit_requests: 1, rate_limit_seconds: 10
36
39
 
37
40
  # Available Requests
38
41
  client.champion
data/lib/lol.rb CHANGED
@@ -2,6 +2,7 @@ require 'active_support/core_ext/string/inflections'
2
2
  require 'httparty'
3
3
  require 'uri'
4
4
  require 'redis'
5
+ require 'glutton_ratelimit'
5
6
 
6
7
  module Lol
7
8
  # Takes a hash and returns a copy of it with the keys that have been underscored
@@ -13,69 +13,73 @@ module Lol
13
13
  # @return [Integer] the ttl on cached requests
14
14
  attr_reader :ttl
15
15
 
16
+ # @!attribute[r] rate_limiter
17
+ # @return [Object] the rate limiter, if one exists (else nil)
18
+ attr_reader :rate_limiter
19
+
16
20
  # @return [ChampionRequest]
17
21
  def champion
18
- @champion_request ||= ChampionRequest.new(api_key, region, cache_store)
22
+ @champion_request ||= ChampionRequest.new(api_key, region, cache_store, rate_limiter)
19
23
  end
20
24
 
21
25
  # @return [ChampionMasteryRequest]
22
26
  def champion_mastery
23
- @champion_mastery_request ||= ChampionMasteryRequest.new(api_key, region, cache_store)
27
+ @champion_mastery_request ||= ChampionMasteryRequest.new(api_key, region, cache_store, rate_limiter)
24
28
  end
25
29
 
26
30
  # @return [MatchRequest]
27
31
  def match
28
- @match_request ||= MatchRequest.new(api_key, region, cache_store)
32
+ @match_request ||= MatchRequest.new(api_key, region, cache_store, rate_limiter)
29
33
  end
30
34
 
31
35
  # @return [LeagueRequest]
32
36
  def league
33
- @league_request ||= LeagueRequest.new(api_key, region, cache_store)
37
+ @league_request ||= LeagueRequest.new(api_key, region, cache_store, rate_limiter)
34
38
  end
35
39
 
36
40
  # @return [RunesRequest]
37
41
  def runes
38
- @runes_request ||= RunesRequest.new(api_key, region, cache_store)
42
+ @runes_request ||= RunesRequest.new(api_key, region, cache_store, rate_limiter)
39
43
  end
40
44
 
41
45
  # @return [MasteriesRequest]
42
46
  def masteries
43
- @masteries_request ||= MasteriesRequest.new(api_key, region, cache_store)
47
+ @masteries_request ||= MasteriesRequest.new(api_key, region, cache_store, rate_limiter)
44
48
  end
45
49
 
46
50
  # @return [SpectatorRequest]
47
51
  def spectator
48
- @spectator_request ||= SpectatorRequest.new(api_key, region, cache_store)
52
+ @spectator_request ||= SpectatorRequest.new(api_key, region, cache_store, rate_limiter)
49
53
  end
50
54
 
51
55
  # @return [SummonerRequest]
52
56
  def summoner
53
- @summoner_request ||= SummonerRequest.new(api_key, region, cache_store)
57
+ @summoner_request ||= SummonerRequest.new(api_key, region, cache_store, rate_limiter)
54
58
  end
55
59
 
56
60
  # @return [StaticRequest]
57
61
  def static
58
- @static_request ||= StaticRequest.new(api_key, region, cache_store)
62
+ @static_request ||= StaticRequest.new(api_key, region, cache_store, rate_limiter)
59
63
  end
60
64
 
61
65
  # @return [LolStatusRequest]
62
66
  def lol_status
63
- @lol_status ||= LolStatusRequest.new(api_key, region, cache_store)
67
+ @lol_status ||= LolStatusRequest.new(api_key, region, cache_store, rate_limiter)
64
68
  end
65
69
 
66
70
  # @return [CurrentGameRequest]
67
71
  def current_game
68
- @current_game ||= CurrentGameRequest.new(api_key, region, cache_store)
72
+ @current_game ||= CurrentGameRequest.new(api_key, region, cache_store, rate_limiter)
69
73
  end
70
74
 
71
75
  # @return [FeaturedGamesRequest]
72
76
  def featured_games
73
- @featured_games ||= FeaturedGamesRequest.new(api_key, region, cache_store)
77
+ @featured_games ||= FeaturedGamesRequest.new(api_key, region, cache_store, rate_limiter)
74
78
  end
75
79
 
76
80
  # @return [TournamentProviderRequest]
77
81
  def tournament
78
- @tournament ||= TournamentRequest.new(api_key, region, cache_store)
82
+ @tournament ||= TournamentRequest.new(api_key, region, cache_store, rate_limiter)
79
83
  end
80
84
 
81
85
  # Initializes a Lol::Client
@@ -84,11 +88,14 @@ module Lol
84
88
  # @option options [String] :region ("EUW") The region on which the requests will be made
85
89
  # @option options [String] :redis the redis url to use for caching
86
90
  # @option options [Integer] :ttl (900) the cache ttl
91
+ # @option options [Fixnum] :rate_limit_requests number of requests
92
+ # @option options [Fixnum] :rate_limit_seconds number of seconds to limit the rate in
87
93
  # @return [Lol::Client]
88
94
  def initialize api_key, options = {}
89
95
  @api_key = api_key
90
96
  @region = options.delete(:region) || "euw"
91
97
  set_up_cache(options.delete(:redis), options.delete(:ttl))
98
+ set_up_rate_limiter(options.delete(:rate_limit_requests), options.delete(:rate_limit_seconds))
92
99
  end
93
100
 
94
101
  def set_up_cache(redis_url, ttl)
@@ -99,6 +106,13 @@ module Lol
99
106
  @redis = Redis.new :url => redis_url
100
107
  end
101
108
 
109
+ def set_up_rate_limiter(number_of_requests, number_of_seconds)
110
+ return @rate_limited = false unless number_of_requests
111
+
112
+ @rate_limited = true
113
+ @rate_limiter = GluttonRatelimit::AveragedThrottle.new number_of_requests, number_of_seconds
114
+ end
115
+
102
116
  # Returns an options hash with cache keys
103
117
  # @return [Hash]
104
118
  def cache_store
@@ -109,6 +123,11 @@ module Lol
109
123
  }
110
124
  end
111
125
 
126
+ # @return [Boolean] true if requests are automatically rate limited
127
+ def rate_limited?
128
+ @rate_limiter
129
+ end
130
+
112
131
  # @return [Boolean] true if requests are cached
113
132
  def cached?
114
133
  @cached
@@ -10,13 +10,11 @@ module Lol
10
10
 
11
11
  # Get match by match ID.
12
12
  # @param [Integer] match_id Match ID
13
- # @param [String] tournament_code Optional tournament code the match belongs to
13
+ # @option options [Integer] forAccountId Optional used to identify the participant to be unobfuscated
14
+ # @option options [Integer] forPlatformId Optional used to identify the participant to be unobfuscated (for when user have changed regions)
14
15
  # @return [DynamicModel] Match representation
15
- def find match_id, tournament_code: nil
16
- url = "matches/#{match_id}".tap do |u|
17
- u << "/by-tournament-code/#{tournament_code}" if tournament_code
18
- end
19
- DynamicModel.new perform_request api_url url
16
+ def find options={}, match_id:
17
+ DynamicModel.new perform_request api_url "matches/#{match_id}", options
20
18
  end
21
19
 
22
20
  # Get match timeline by match ID.
@@ -33,6 +31,14 @@ module Lol
33
31
  perform_request api_url "matches/by-tournament-code/#{tournament_code}/ids"
34
32
  end
35
33
 
34
+ # Get match by match ID and tournament code.
35
+ # @param [Integer] match_id Match ID
36
+ # @param [String] tournament_code Tournament code the match belongs to
37
+ # @return [DynamicModel] Match representation
38
+ def find_by_tournament match_id, tournament_code
39
+ DynamicModel.new perform_request api_url "matches/#{match_id}/by-tournament-code/#{tournament_code}"
40
+ end
41
+
36
42
  # Get matchlist for ranked games played on given account ID and platform ID and filtered using given filter parameters, if any.
37
43
  # @param [Integer] account_id Account ID
38
44
  # @param [Hash] options the options to pass to the call
@@ -24,6 +24,10 @@ module Lol
24
24
  # @return [Object] the cache_store
25
25
  attr_reader :cache_store
26
26
 
27
+ # @!attribute[r] rate_limiter
28
+ # @return [Object] the rate limiter, if one exists (else nil)
29
+ attr_reader :rate_limiter
30
+
27
31
  # Returns the supported API Version.
28
32
  # @return [String] v3
29
33
  def self.api_version
@@ -54,15 +58,16 @@ module Lol
54
58
  # @option cache_store [Boolean] :cached should the request be cached
55
59
  # @option cacche_store [Integer] :ttl ttl for cache keys
56
60
  # @return [Request]
57
- def initialize api_key, region, cache_store = {}
58
- @cache_store = cache_store
61
+ def initialize api_key, region, cache_store = {}, rate_limiter = nil
62
+ @cache_store = cache_store
63
+ @rate_limiter = rate_limiter
59
64
  raise InvalidCacheStore if cached? && !store.is_a?(Redis)
60
65
  @api_key = api_key
61
- @region = region
66
+ @region = region
62
67
  end
63
68
 
64
69
  def platform
65
- self.class.platforms[region.to_sym]
70
+ self.class.platforms[region.downcase.to_sym]
66
71
  end
67
72
 
68
73
  # Returns the supported API Version.
@@ -103,7 +108,8 @@ module Lol
103
108
  uri.to_s
104
109
  end
105
110
 
106
- # Calls the API via HTTParty and handles errors
111
+ # Calls the API via HTTParty and handles errors caching it if a cache is
112
+ # enabled and rate limiting it if a rate limiter is configured
107
113
  # @param url [String] the url to call
108
114
  # @param verb [Symbol] HTTP verb to use. Defaults to :get
109
115
  # @param body [Hash] Body for POST request
@@ -115,11 +121,18 @@ module Lol
115
121
  if can_cache && result = store.get("#{clean_url(url)}#{options_id}")
116
122
  return JSON.parse(result)
117
123
  end
118
- response = perform_uncached_request url, verb, body, options
124
+ response = perform_rate_limited_request(url, verb, body, options)
119
125
  store.setex "#{clean_url(url)}#{options_id}", ttl, response.to_json if can_cache
120
126
  response
121
127
  end
122
128
 
129
+ def perform_rate_limited_request url, verb = :get, body = nil, options = {}
130
+ return perform_uncached_request(url, verb, body, options) unless rate_limiter
131
+ @rate_limiter.times 1 do
132
+ perform_uncached_request(url, verb, body, options)
133
+ end
134
+ end
135
+
123
136
  def perform_uncached_request url, verb = :get, body = nil, options = {}
124
137
  options[:headers] ||= {}
125
138
  options[:headers].merge!({
@@ -7,7 +7,7 @@ module Lol
7
7
 
8
8
  # @!visibility private
9
9
  def api_base_url
10
- "https://global.api.riotgames.com"
10
+ "https://americas.api.riotgames.com"
11
11
  end
12
12
 
13
13
  # Creates a tournament provider and returns its ID.
@@ -26,10 +26,9 @@ module Lol
26
26
  # @param [String] name Name of the tournament
27
27
  # @return [Integer] Tournament ID
28
28
  def create_tournament provider_id:, name: nil
29
- body = {
30
- "providerId" => provider_id,
31
- "name" => name
32
- }.compact
29
+ body = { "providerId" => provider_id, "name" => name }.delete_if do |k, v|
30
+ v.nil?
31
+ end
33
32
  perform_request api_url("tournaments"), :post, body
34
33
  end
35
34
 
@@ -1,3 +1,3 @@
1
1
  module Lol
2
- VERSION = "1.0.0"
2
+ VERSION = "1.1.1"
3
3
  end
@@ -35,4 +35,5 @@ Gem::Specification.new do |spec|
35
35
  spec.add_runtime_dependency "httparty", "0.14.0" # due to https://github.com/jnunemaker/httparty/issues/533
36
36
  spec.add_runtime_dependency "activesupport"
37
37
  spec.add_runtime_dependency "redis"
38
+ spec.add_runtime_dependency "glutton_ratelimit"
38
39
  end
@@ -45,6 +45,23 @@ describe Client do
45
45
  expect(champion_request.cache_store).to eq(real_redis.cache_store)
46
46
  end
47
47
  end
48
+
49
+ context "rate_limiting" do
50
+ let(:client) { Client.new "foo", rate_limit_requests: 10 }
51
+
52
+ it "sets rate limiting if specified in the options" do
53
+ expect(client.rate_limited?).to be_truthy
54
+ end
55
+
56
+ it "instantiates a rate limiter if it is in the options" do
57
+ expect(client.rate_limiter).not_to be_nil
58
+ end
59
+
60
+ it "passes the rate limiter to the request" do
61
+ champion_request = client.champion
62
+ expect(champion_request.rate_limiter).to eq(client.rate_limiter)
63
+ end
64
+ end
48
65
  end
49
66
 
50
67
  describe "#cached?" do
@@ -65,7 +82,7 @@ describe Client do
65
82
  end
66
83
 
67
84
  it "initializes the ChampionRequest with the current API key and region" do
68
- expect(ChampionRequest).to receive(:new).with(subject.api_key, subject.region, subject.cache_store)
85
+ expect(ChampionRequest).to receive(:new).with(subject.api_key, subject.region, subject.cache_store, subject.rate_limiter)
69
86
 
70
87
  subject.champion
71
88
  end
@@ -77,7 +94,7 @@ describe Client do
77
94
  end
78
95
 
79
96
  it "initializes the MatchRequest with the current API key and region" do
80
- expect(MatchRequest).to receive(:new).with(subject.api_key, subject.region, subject.cache_store)
97
+ expect(MatchRequest).to receive(:new).with(subject.api_key, subject.region, subject.cache_store, subject.rate_limiter)
81
98
 
82
99
  subject.match
83
100
  end
@@ -89,7 +106,7 @@ describe Client do
89
106
  end
90
107
 
91
108
  it "initializes the RunesRequest with the current API key and region" do
92
- expect(RunesRequest).to receive(:new).with(subject.api_key, subject.region, subject.cache_store)
109
+ expect(RunesRequest).to receive(:new).with(subject.api_key, subject.region, subject.cache_store, subject.rate_limiter)
93
110
 
94
111
  subject.runes
95
112
  end
@@ -101,7 +118,7 @@ describe Client do
101
118
  end
102
119
 
103
120
  it "initializes the MasteriesRequest with the current API key and region" do
104
- expect(MasteriesRequest).to receive(:new).with(subject.api_key, subject.region, subject.cache_store)
121
+ expect(MasteriesRequest).to receive(:new).with(subject.api_key, subject.region, subject.cache_store, subject.rate_limiter)
105
122
 
106
123
  subject.masteries
107
124
  end
@@ -113,7 +130,7 @@ describe Client do
113
130
  end
114
131
 
115
132
  it "initializes the LeagueRequest with the current API key and region" do
116
- expect(LeagueRequest).to receive(:new).with(subject.api_key, subject.region, subject.cache_store)
133
+ expect(LeagueRequest).to receive(:new).with(subject.api_key, subject.region, subject.cache_store, subject.rate_limiter)
117
134
 
118
135
  subject.league
119
136
  end
@@ -125,7 +142,7 @@ describe Client do
125
142
  end
126
143
 
127
144
  it "initializes the SummonerRequest with the current API key and region" do
128
- expect(SummonerRequest).to receive(:new).with(subject.api_key, subject.region, subject.cache_store)
145
+ expect(SummonerRequest).to receive(:new).with(subject.api_key, subject.region, subject.cache_store, subject.rate_limiter)
129
146
 
130
147
  subject.summoner
131
148
  end
@@ -137,7 +154,7 @@ describe Client do
137
154
  end
138
155
 
139
156
  it "initializes the StaticRequest with the current API key and region" do
140
- expect(StaticRequest).to receive(:new).with(subject.api_key, subject.region, subject.cache_store)
157
+ expect(StaticRequest).to receive(:new).with(subject.api_key, subject.region, subject.cache_store, subject.rate_limiter)
141
158
 
142
159
  subject.static
143
160
  end
@@ -11,22 +11,9 @@ describe MatchRequest do
11
11
  end
12
12
 
13
13
  describe "#find" do
14
- context "without a tournament code" do
15
- let(:result) { subject.find 1 }
16
- before { stub_request subject, 'match', "matches/1" }
17
-
18
- it "returns a DynamicModel" do
19
- expect(result).to be_a DynamicModel
20
- end
21
- end
22
-
23
- context "with a tournament code" do
24
- let(:result) { subject.find 1, tournament_code: 2 }
25
- before { stub_request subject, 'match-with-tc', "matches/1/by-tournament-code/2" }
26
-
27
- it "returns a DynamicModel" do
28
- expect(result).to be_a DynamicModel
29
- end
14
+ it "returns a DynamicModel" do
15
+ stub_request subject, 'match', "matches/1"
16
+ expect(subject.find match_id: 1).to be_a DynamicModel
30
17
  end
31
18
  end
32
19
 
@@ -42,7 +29,14 @@ describe MatchRequest do
42
29
  stub_request subject, 'ids-by-tc', "matches/by-tournament-code/1/ids"
43
30
  result = subject.ids_by_tournament_code '1'
44
31
  expect(result).to be_a Array
45
- expect(result.map(&:class).uniq).to eq [Integer]
32
+ expect(result.map(&:class).uniq).to eq [Fixnum]
33
+ end
34
+ end
35
+
36
+ describe "#find_by_tournament" do
37
+ it "returns a DynamicModel" do
38
+ stub_request subject, 'match-with-tc', "matches/1/by-tournament-code/2"
39
+ expect(subject.find_by_tournament 1, 2).to be_a DynamicModel
46
40
  end
47
41
  end
48
42
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ruby-lol
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.0
4
+ version: 1.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Giovanni Intini
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-07-24 00:00:00.000000000 Z
11
+ date: 2017-08-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -240,6 +240,20 @@ dependencies:
240
240
  - - ">="
241
241
  - !ruby/object:Gem::Version
242
242
  version: '0'
243
+ - !ruby/object:Gem::Dependency
244
+ name: glutton_ratelimit
245
+ requirement: !ruby/object:Gem::Requirement
246
+ requirements:
247
+ - - ">="
248
+ - !ruby/object:Gem::Version
249
+ version: '0'
250
+ type: :runtime
251
+ prerelease: false
252
+ version_requirements: !ruby/object:Gem::Requirement
253
+ requirements:
254
+ - - ">="
255
+ - !ruby/object:Gem::Version
256
+ version: '0'
243
257
  description: Ruby wrapper to Riot Games API. Maps results to full blown ruby objects.
244
258
  email:
245
259
  - giovanni@mikamai.com