leaderboard 3.10.0 → 3.11.0
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 +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
|