leaderboard 3.10.0 → 3.11.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.markdown +6 -0
- data/LICENSE.txt +1 -1
- data/README.markdown +6 -2
- data/lib/competition_ranking_leaderboard.rb +39 -10
- data/lib/leaderboard.rb +27 -5
- data/lib/leaderboard/version.rb +1 -1
- data/lib/tie_ranking_leaderboard.rb +6 -4
- data/spec/leaderboard_spec.rb +14 -0
- data/spec/version_spec.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3f0aeb0cd68034cf6d268f8f1d8d4e8a39c0df66
|
4
|
+
data.tar.gz: 4576a03574ab9f93200d11ab861b9b3203a179dc
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ac3cc4247ea3c1ca634375112b2614dbe18a1d1a8ab818f08c2f27fe1c1167dea897b95eb7014704a81c0a9303ed03865537837f0eb7efed8bd1b34e8990de1e
|
7
|
+
data.tar.gz: 68128561ee0b7d89d929c251d19b5463ca836325d15a1a163a48e370dba1a39e8475106c7575d9ddbc0ea04dcdbeb8c544e88512879ca25805d124f023ae2b6a
|
data/CHANGELOG.markdown
CHANGED
@@ -1,5 +1,11 @@
|
|
1
1
|
# CHANGELOG
|
2
2
|
|
3
|
+
## 3.11.0 (2016-09-16)
|
4
|
+
|
5
|
+
* More pipelining [#58](https://github.com/agoragames/leaderboard/pull/58).
|
6
|
+
Also adds `members_data_for(...) and `members_data_for_in(...)` methods.
|
7
|
+
* Guard against an out of bounds index in `member_at`
|
8
|
+
|
3
9
|
## 3.10.0 (2015-03-20)
|
4
10
|
|
5
11
|
* Fixes TieRankingLeaderboard doesn't rank if the score is 0 [#53](https://github.com/agoragames/leaderboard/issues/53).
|
data/LICENSE.txt
CHANGED
data/README.markdown
CHANGED
@@ -21,7 +21,9 @@ check out the [Redis documentation](http://redis.io/documentation).
|
|
21
21
|
|
22
22
|
## Compatibility
|
23
23
|
|
24
|
-
The gem has been built and tested under
|
24
|
+
The gem has been built and tested under 2.2.1.
|
25
|
+
|
26
|
+
NOTE: The gem should work fine in earlier versions of Ruby such as 1.8.7 or 1.9.3. There are no specific aspects of Ruby 2.x that we utilize at this time.
|
25
27
|
|
26
28
|
## Usage
|
27
29
|
|
@@ -184,6 +186,7 @@ You can pass various options to the calls `leaders`, `all_leaders`, `around_me`,
|
|
184
186
|
* `:page_size` - An integer value to change the page size for that call.
|
185
187
|
* `:members_only` - `true` or `false` (default) to return only the members without their score and rank.
|
186
188
|
* `:sort_by` - Valid values for `:sort_by` are `:none` (default), `:score` and `:rank`.
|
189
|
+
* `:include_missing` - `true` (default) or `false` to return members that are not ranked.
|
187
190
|
|
188
191
|
You can also use the `members` and `members_in` methods as aliases for the `leaders` and `leaders_in` methods.
|
189
192
|
|
@@ -340,6 +343,7 @@ Competition ranking: The `CompetitionRankingLeaderboard` subclass of `Leaderboar
|
|
340
343
|
```
|
341
344
|
delete_leaderboard: Delete the current leaderboard
|
342
345
|
member_data_for(member): Retrieve the optional member data for a given member in the leaderboard
|
346
|
+
members_data_for(members): Retrieve the optional member data for a given list of members in the leaderboard
|
343
347
|
update_member_data(member, member_data): Update the optional member data for a given member in the leaderboard
|
344
348
|
remove_member_data(member): Remove the optional member data for a given member in the leaderboard
|
345
349
|
remove_member(member): Remove a member from the leaderboard
|
@@ -482,5 +486,5 @@ Unofficially supported (they need some feature parity love):
|
|
482
486
|
|
483
487
|
## Copyright
|
484
488
|
|
485
|
-
Copyright (c) 2011-
|
489
|
+
Copyright (c) 2011-2016 David Czarnecki. See LICENSE.txt for further details.
|
486
490
|
|
@@ -67,29 +67,36 @@ class CompetitionRankingLeaderboard < Leaderboard
|
|
67
67
|
end
|
68
68
|
end unless leaderboard_options[:members_only]
|
69
69
|
|
70
|
+
included_members = []
|
71
|
+
scores = []
|
72
|
+
|
70
73
|
members.each_with_index do |member, index|
|
71
74
|
data = {}
|
72
75
|
data[@member_key] = member
|
73
76
|
unless leaderboard_options[:members_only]
|
74
77
|
data[@score_key] = responses[index * 2 + 1].to_f if responses[index * 2 + 1]
|
78
|
+
|
75
79
|
if data[@score_key] == nil
|
76
80
|
next unless leaderboard_options[:include_missing]
|
77
81
|
end
|
78
|
-
|
79
|
-
if @reverse
|
80
|
-
data[@rank_key] = @redis_connection.zcount(leaderboard_name, '-inf', "(#{data[@score_key]}") + 1 rescue nil
|
81
|
-
else
|
82
|
-
data[@rank_key] = @redis_connection.zcount(leaderboard_name, "(#{data[@score_key]}", '+inf') + 1 rescue nil
|
83
|
-
end
|
84
82
|
end
|
85
83
|
|
86
|
-
|
87
|
-
|
88
|
-
end
|
84
|
+
included_members << member
|
85
|
+
scores << data[@score_key]
|
89
86
|
|
90
87
|
ranks_for_members << data
|
91
88
|
end
|
92
89
|
|
90
|
+
if leaderboard_options[:with_member_data]
|
91
|
+
members_data_for_in(leaderboard_name, included_members).each_with_index do |member_data, index|
|
92
|
+
ranks_for_members[index][@member_data_key] = member_data
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
rankings_for_members_having_scores_in(leaderboard_name, included_members, scores).each_with_index do |rank, index|
|
97
|
+
ranks_for_members[index][@rank_key] = rank
|
98
|
+
end
|
99
|
+
|
93
100
|
case leaderboard_options[:sort_by]
|
94
101
|
when :rank
|
95
102
|
ranks_for_members = ranks_for_members.sort_by { |member| member[@rank_key] }
|
@@ -99,4 +106,26 @@ class CompetitionRankingLeaderboard < Leaderboard
|
|
99
106
|
|
100
107
|
ranks_for_members
|
101
108
|
end
|
102
|
-
|
109
|
+
|
110
|
+
protected
|
111
|
+
|
112
|
+
# Retrieve a list of the rankings of leaders given their member names and scores
|
113
|
+
#
|
114
|
+
# @param leaderboard_name [String] Name of the leaderboard.
|
115
|
+
# @param members [Array] Member names.
|
116
|
+
# @param scores [Array] a list of scores for the members, aligned with the member names
|
117
|
+
#
|
118
|
+
# @return a list of the rankings for the passed in members and scores
|
119
|
+
def rankings_for_members_having_scores_in(leaderboard_name, members, scores)
|
120
|
+
@redis_connection.multi do |transaction|
|
121
|
+
members.each_with_index do |member, index|
|
122
|
+
if @reverse
|
123
|
+
transaction.zcount(leaderboard_name, '-inf', "(#{scores[index]}")
|
124
|
+
else
|
125
|
+
transaction.zcount(leaderboard_name, "(#{scores[index]}", '+inf')
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end.map{|rank| rank ? rank + 1 : rank}
|
129
|
+
end
|
130
|
+
|
131
|
+
end
|
data/lib/leaderboard.rb
CHANGED
@@ -219,6 +219,26 @@ class Leaderboard
|
|
219
219
|
@redis_connection.hget(member_data_key(leaderboard_name), member)
|
220
220
|
end
|
221
221
|
|
222
|
+
# Retrieve the optional member data for a given member in the named leaderboard.
|
223
|
+
#
|
224
|
+
# @param leaderboard_name [String] Name of the leaderboard.
|
225
|
+
# @param members [Array] Member names.
|
226
|
+
#
|
227
|
+
# @return array of strings of optional member data.
|
228
|
+
def members_data_for_in(leaderboard_name, members)
|
229
|
+
return [] unless members.size > 0
|
230
|
+
@redis_connection.hmget(member_data_key(leaderboard_name), *members)
|
231
|
+
end
|
232
|
+
|
233
|
+
# Retrieve the optional member data for the given members in the leaderboard.
|
234
|
+
#
|
235
|
+
# @param members [Array] Member names.
|
236
|
+
#
|
237
|
+
# @return array of strings of optional member data.
|
238
|
+
def members_data_for(members)
|
239
|
+
members_data_for_in(@leaderboard_name, members)
|
240
|
+
end
|
241
|
+
|
222
242
|
# Update the optional member data for a given member in the leaderboard.
|
223
243
|
#
|
224
244
|
# @param member [String] Member name.
|
@@ -860,7 +880,7 @@ class Leaderboard
|
|
860
880
|
#
|
861
881
|
# @return a page of leaders from the named leaderboard.
|
862
882
|
def member_at_in(leaderboard_name, position, options = {})
|
863
|
-
if position <= total_members_in(leaderboard_name)
|
883
|
+
if position > 0 && position <= total_members_in(leaderboard_name)
|
864
884
|
leaderboard_options = DEFAULT_LEADERBOARD_REQUEST_OPTIONS.dup
|
865
885
|
leaderboard_options.merge!(options)
|
866
886
|
page_size = validate_page_size(leaderboard_options[:page_size]) || @page_size
|
@@ -964,13 +984,15 @@ class Leaderboard
|
|
964
984
|
data[@score_key] = responses[index * 2 + 1].to_f if responses[index * 2 + 1]
|
965
985
|
end
|
966
986
|
|
967
|
-
if leaderboard_options[:with_member_data]
|
968
|
-
data[@member_data_key] = member_data_for_in(leaderboard_name, member)
|
969
|
-
end
|
970
|
-
|
971
987
|
ranks_for_members << data
|
972
988
|
end
|
973
989
|
|
990
|
+
if leaderboard_options[:with_member_data]
|
991
|
+
members_data_for_in(leaderboard_name, members).each_with_index do |member_data, index|
|
992
|
+
ranks_for_members[index][@member_data_key] = member_data
|
993
|
+
end
|
994
|
+
end
|
995
|
+
|
974
996
|
case leaderboard_options[:sort_by]
|
975
997
|
when :rank
|
976
998
|
ranks_for_members = ranks_for_members.sort_by { |member| member[@rank_key] }
|
data/lib/leaderboard/version.rb
CHANGED
@@ -249,13 +249,15 @@ class TieRankingLeaderboard < Leaderboard
|
|
249
249
|
end
|
250
250
|
end
|
251
251
|
|
252
|
-
if leaderboard_options[:with_member_data]
|
253
|
-
data[@member_data_key] = member_data_for_in(leaderboard_name, member)
|
254
|
-
end
|
255
|
-
|
256
252
|
ranks_for_members << data
|
257
253
|
end
|
258
254
|
|
255
|
+
if leaderboard_options[:with_member_data]
|
256
|
+
members_data_for_in(leaderboard_name, members).each_with_index do |member_data, index|
|
257
|
+
ranks_for_members[index][@member_data_key] = member_data
|
258
|
+
end
|
259
|
+
end
|
260
|
+
|
259
261
|
case leaderboard_options[:sort_by]
|
260
262
|
when :rank
|
261
263
|
ranks_for_members = ranks_for_members.sort_by { |member| member[@rank_key] }
|
data/spec/leaderboard_spec.rb
CHANGED
@@ -199,6 +199,14 @@ describe 'Leaderboard' do
|
|
199
199
|
expect(@leaderboard.member_data_for('member_id')).to eq({'username' => 'member_name', 'other_data_key' => 'other_data_value'}.to_s)
|
200
200
|
end
|
201
201
|
|
202
|
+
it 'should allow you to retrieve optional member data for multiple members' do
|
203
|
+
rank_members_in_leaderboard(Leaderboard::DEFAULT_PAGE_SIZE)
|
204
|
+
|
205
|
+
members_data = @leaderboard.members_data_for(['member_1', 'member_3'])
|
206
|
+
expect(members_data[0]).to eq({:member_name => 'Leaderboard member 1'}.to_s)
|
207
|
+
expect(members_data[1]).to eq({:member_name => 'Leaderboard member 3'}.to_s)
|
208
|
+
end
|
209
|
+
|
202
210
|
it 'should allow you to update optional member data' do
|
203
211
|
@leaderboard.rank_member('member_id', 1, {'username' => 'member_name'})
|
204
212
|
|
@@ -234,6 +242,12 @@ describe 'Leaderboard' do
|
|
234
242
|
expect(@leaderboard.member_at(1, :with_member_data => true)[:member_data]).to eq({:member_name => 'Leaderboard member 50'}.to_s)
|
235
243
|
end
|
236
244
|
|
245
|
+
it 'should not return a single member when calling member_at with a position < 0' do
|
246
|
+
rank_members_in_leaderboard(5)
|
247
|
+
expect(@leaderboard.member_at(1)[:rank]).to eql(1)
|
248
|
+
expect(@leaderboard.member_at(-5)).to be nil
|
249
|
+
end
|
250
|
+
|
237
251
|
it 'should return the correct information when calling around_me' do
|
238
252
|
rank_members_in_leaderboard(Leaderboard::DEFAULT_PAGE_SIZE * 3 + 1)
|
239
253
|
|
data/spec/version_spec.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: leaderboard
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.
|
4
|
+
version: 3.11.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- David Czarnecki
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2016-09-16 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: redis
|