leaderboard 3.6.0 → 3.7.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rspec +1 -1
- data/.ruby-version +1 -3
- data/.travis.yml +1 -2
- data/CHANGELOG.markdown +4 -0
- data/README.markdown +33 -1
- data/Rakefile +0 -5
- data/leaderboard.gemspec +0 -3
- data/lib/competition_ranking_leaderboard.rb +98 -0
- data/lib/leaderboard.rb +1 -1
- data/lib/leaderboard/version.rb +1 -1
- data/lib/tie_ranking_leaderboard.rb +253 -0
- data/spec/competition_ranking_leaderboard_spec.rb +110 -0
- data/spec/leaderboard_spec.rb +250 -250
- data/spec/reverse_competition_ranking_leaderboard_spec.rb +116 -0
- data/spec/reverse_leaderboard_spec.rb +127 -127
- data/spec/reverse_tie_ranking_leaderboard_spec.rb +141 -0
- data/spec/spec_helper.rb +1 -1
- data/spec/tie_ranking_leaderboard_spec.rb +207 -0
- data/spec/version_spec.rb +1 -1
- metadata +26 -16
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 73f4fb333c04f1aef154ecf0469cdea2f3602c24
|
4
|
+
data.tar.gz: 6ada4c6ec175b491b2dec536b4961e3bd472eb54
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 104e46c727ed24d53883a4f45260af84fc3518d863ef662ccafab806152aea83aea40a5a740c80452535c2dcf25853cd54ce52aa7b398f9b019638654f44e99c
|
7
|
+
data.tar.gz: 96f0f5756c4a17bd0dd9e573a3e8b682f961168f7a47e2fb0f0100cd6ec427457afdacb194367bf01a6f38eb5032bdcd3458f344a8683450dc8697a5a31d62c6
|
data/.rspec
CHANGED
data/.ruby-version
CHANGED
data/.travis.yml
CHANGED
data/CHANGELOG.markdown
CHANGED
@@ -1,5 +1,9 @@
|
|
1
1
|
# CHANGELOG
|
2
2
|
|
3
|
+
## 3.7.0 (2014-07-28)
|
4
|
+
|
5
|
+
* Add support for tie handling in leaderboards [#46](https://github.com/agoragames/leaderboard/pull/46)
|
6
|
+
|
3
7
|
## 3.6.0 (2014-02-15)
|
4
8
|
|
5
9
|
* Allow for customization of member_data namespace [#45](https://github.com/agoragames/leaderboard/pull/45)
|
data/README.markdown
CHANGED
@@ -21,7 +21,7 @@ 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 Ruby 1.
|
24
|
+
The gem has been built and tested under Ruby 1.9.3 and Ruby 2.1.2.
|
25
25
|
|
26
26
|
## Usage
|
27
27
|
|
@@ -302,6 +302,38 @@ Use this method to do bulk insert of data, but be mindful of the amount of data
|
|
302
302
|
highscore_lb.rank_member_across(['highscores', 'more_highscores'], 'david', 50000, { :member_name => "david" })
|
303
303
|
```
|
304
304
|
|
305
|
+
### Alternate leaderboard types
|
306
|
+
|
307
|
+
The leaderboard library offers 3 styles of ranking. This is only an issue for members with the same score in a leaderboard.
|
308
|
+
|
309
|
+
Default: The `Leaderboard` class uses the default Redis sorted set ordering, whereby different members having the same score are ordered lexicographically. As per the Redis documentation on Redis sorted sets, "The lexicographic ordering used is binary, it compares strings as array of bytes."
|
310
|
+
|
311
|
+
Tie ranking: The `TieRankingLeaderboard` subclass of `Leaderboard` allows you to define a leaderboard where members with the same score are given the same rank. For example, members in a leaderboard with the associated scores would have the ranks of:
|
312
|
+
|
313
|
+
```
|
314
|
+
| member | score | rank |
|
315
|
+
-----------------------------
|
316
|
+
| member_1 | 50 | 1 |
|
317
|
+
| member_2 | 50 | 1 |
|
318
|
+
| member_3 | 30 | 2 |
|
319
|
+
| member_4 | 30 | 2 |
|
320
|
+
| member_5 | 10 | 3 |
|
321
|
+
```
|
322
|
+
|
323
|
+
The `TieRankingLeaderboard` accepts one additional option, `:ties_namespace` (default: ties), when initializing a new instance of this class. Please note that in its current implementation, the `TieRankingLeaderboard` class uses an additional sorted set to rank the scores, so please keep this in mind when you are doing any capacity planning for Redis with respect to memory usage.
|
324
|
+
|
325
|
+
Competition ranking: The `CompetitionRankingLeaderboard` subclass of `Leaderboard` allows you to define a leaderboard where members with the same score will have the same rank, and then a gap is left in the ranking numbers. For example, members in a leaderboard with the associated scores would have the ranks of:
|
326
|
+
|
327
|
+
```
|
328
|
+
| member | score | rank |
|
329
|
+
-----------------------------
|
330
|
+
| member_1 | 50 | 1 |
|
331
|
+
| member_2 | 50 | 1 |
|
332
|
+
| member_3 | 30 | 3 |
|
333
|
+
| member_4 | 30 | 3 |
|
334
|
+
| member_5 | 10 | 5 |
|
335
|
+
```
|
336
|
+
|
305
337
|
### Other useful methods
|
306
338
|
|
307
339
|
```
|
data/Rakefile
CHANGED
data/leaderboard.gemspec
CHANGED
@@ -0,0 +1,98 @@
|
|
1
|
+
require 'leaderboard'
|
2
|
+
|
3
|
+
class CompetitionRankingLeaderboard < Leaderboard
|
4
|
+
# Retrieve the rank for a member in the named leaderboard.
|
5
|
+
#
|
6
|
+
# @param leaderboard_name [String] Name of the leaderboard.
|
7
|
+
# @param member [String] Member name.
|
8
|
+
#
|
9
|
+
# @return the rank for a member in the leaderboard.
|
10
|
+
def rank_for_in(leaderboard_name, member)
|
11
|
+
member_score = score_for_in(leaderboard_name, member)
|
12
|
+
if @reverse
|
13
|
+
return @redis_connection.zcount(leaderboard_name, '-inf', "(#{member_score}") + 1 rescue nil
|
14
|
+
else
|
15
|
+
return @redis_connection.zcount(leaderboard_name, "(#{member_score}", '+inf') + 1 rescue nil
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
# Retrieve the score and rank for a member in the named leaderboard.
|
20
|
+
#
|
21
|
+
# @param leaderboard_name [String]Name of the leaderboard.
|
22
|
+
# @param member [String] Member name.
|
23
|
+
#
|
24
|
+
# @return the score and rank for a member in the named leaderboard as a Hash.
|
25
|
+
def score_and_rank_for_in(leaderboard_name, member)
|
26
|
+
responses = @redis_connection.multi do |transaction|
|
27
|
+
transaction.zscore(leaderboard_name, member)
|
28
|
+
if @reverse
|
29
|
+
transaction.zrank(leaderboard_name, member)
|
30
|
+
else
|
31
|
+
transaction.zrevrank(leaderboard_name, member)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
responses[0] = responses[0].to_f if responses[0]
|
36
|
+
responses[1] =
|
37
|
+
if @reverse
|
38
|
+
@redis_connection.zcount(leaderboard_name, '-inf', "(#{responses[0]}") + 1 rescue nil
|
39
|
+
else
|
40
|
+
@redis_connection.zcount(leaderboard_name, "(#{responses[0]}", '+inf') + 1 rescue nil
|
41
|
+
end
|
42
|
+
|
43
|
+
{@member_key => member, @score_key => responses[0], @rank_key => responses[1]}
|
44
|
+
end
|
45
|
+
|
46
|
+
# Retrieve a page of leaders from the named leaderboard for a given list of members.
|
47
|
+
#
|
48
|
+
# @param leaderboard_name [String] Name of the leaderboard.
|
49
|
+
# @param members [Array] Member names.
|
50
|
+
# @param options [Hash] Options to be used when retrieving the page from the named leaderboard.
|
51
|
+
#
|
52
|
+
# @return a page of leaders from the named leaderboard for a given list of members.
|
53
|
+
def ranked_in_list_in(leaderboard_name, members, options = {})
|
54
|
+
leaderboard_options = DEFAULT_LEADERBOARD_REQUEST_OPTIONS.dup
|
55
|
+
leaderboard_options.merge!(options)
|
56
|
+
|
57
|
+
ranks_for_members = []
|
58
|
+
|
59
|
+
responses = @redis_connection.multi do |transaction|
|
60
|
+
members.each do |member|
|
61
|
+
if @reverse
|
62
|
+
transaction.zrank(leaderboard_name, member)
|
63
|
+
else
|
64
|
+
transaction.zrevrank(leaderboard_name, member)
|
65
|
+
end
|
66
|
+
transaction.zscore(leaderboard_name, member)
|
67
|
+
end
|
68
|
+
end unless leaderboard_options[:members_only]
|
69
|
+
|
70
|
+
members.each_with_index do |member, index|
|
71
|
+
data = {}
|
72
|
+
data[@member_key] = member
|
73
|
+
unless leaderboard_options[:members_only]
|
74
|
+
data[@score_key] = responses[index * 2 + 1].to_f if responses[index * 2 + 1]
|
75
|
+
if @reverse
|
76
|
+
data[@rank_key] = @redis_connection.zcount(leaderboard_name, '-inf', "(#{data[@score_key]}") + 1 rescue nil
|
77
|
+
else
|
78
|
+
data[@rank_key] = @redis_connection.zcount(leaderboard_name, "(#{data[@score_key]}", '+inf') + 1 rescue nil
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
if leaderboard_options[:with_member_data]
|
83
|
+
data[@member_data_key] = member_data_for_in(leaderboard_name, member)
|
84
|
+
end
|
85
|
+
|
86
|
+
ranks_for_members << data
|
87
|
+
end
|
88
|
+
|
89
|
+
case leaderboard_options[:sort_by]
|
90
|
+
when :rank
|
91
|
+
ranks_for_members = ranks_for_members.sort_by { |member| member[@rank_key] }
|
92
|
+
when :score
|
93
|
+
ranks_for_members = ranks_for_members.sort_by { |member| member[@score_key] }
|
94
|
+
end
|
95
|
+
|
96
|
+
ranks_for_members
|
97
|
+
end
|
98
|
+
end
|
data/lib/leaderboard.rb
CHANGED
data/lib/leaderboard/version.rb
CHANGED
@@ -0,0 +1,253 @@
|
|
1
|
+
require 'leaderboard'
|
2
|
+
|
3
|
+
class TieRankingLeaderboard < Leaderboard
|
4
|
+
# Default options when creating a leaderboard. Page size is 25 and reverse
|
5
|
+
# is set to false, meaning various methods will return results in
|
6
|
+
# highest-to-lowest order.
|
7
|
+
DEFAULT_OPTIONS = {
|
8
|
+
:page_size => DEFAULT_PAGE_SIZE,
|
9
|
+
:reverse => false,
|
10
|
+
:member_key => :member,
|
11
|
+
:rank_key => :rank,
|
12
|
+
:score_key => :score,
|
13
|
+
:member_data_key => :member_data,
|
14
|
+
:member_data_namespace => 'member_data',
|
15
|
+
:ties_namespace => 'ties'
|
16
|
+
}
|
17
|
+
|
18
|
+
# Create a new instance of a leaderboard.
|
19
|
+
#
|
20
|
+
# @param leaderboard [String] Name of the leaderboard.
|
21
|
+
# @param options [Hash] Options for the leaderboard such as +:page_size+.
|
22
|
+
# @param redis_options [Hash] Options for configuring Redis.
|
23
|
+
#
|
24
|
+
# Examples
|
25
|
+
#
|
26
|
+
# leaderboard = Leaderboard.new('highscores')
|
27
|
+
# leaderboard = Leaderboard.new('highscores', {:page_size => 10})
|
28
|
+
def initialize(leaderboard_name, options = DEFAULT_OPTIONS, redis_options = DEFAULT_REDIS_OPTIONS)
|
29
|
+
super
|
30
|
+
|
31
|
+
leaderboard_options = DEFAULT_OPTIONS.dup
|
32
|
+
leaderboard_options.merge!(options)
|
33
|
+
|
34
|
+
@ties_namespace = leaderboard_options[:ties_namespace]
|
35
|
+
end
|
36
|
+
|
37
|
+
# Delete the named leaderboard.
|
38
|
+
#
|
39
|
+
# @param leaderboard_name [String] Name of the leaderboard.
|
40
|
+
def delete_leaderboard_named(leaderboard_name)
|
41
|
+
@redis_connection.multi do |transaction|
|
42
|
+
transaction.del(leaderboard_name)
|
43
|
+
transaction.del(member_data_key(leaderboard_name))
|
44
|
+
transaction.del(ties_leaderboard_key(leaderboard_name))
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
# Rank a member in the named leaderboard.
|
49
|
+
#
|
50
|
+
# @param leaderboard_name [String] Name of the leaderboard.
|
51
|
+
# @param member [String] Member name.
|
52
|
+
# @param score [float] Member score.
|
53
|
+
# @param member_data [String] Optional member data.
|
54
|
+
def rank_member_in(leaderboard_name, member, score, member_data = nil)
|
55
|
+
@redis_connection.multi do |transaction|
|
56
|
+
transaction.zadd(leaderboard_name, score, member)
|
57
|
+
transaction.zadd(ties_leaderboard_key(leaderboard_name), score, score.to_f.to_s)
|
58
|
+
transaction.hset(member_data_key(leaderboard_name), member, member_data) if member_data
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
# Rank a member across multiple leaderboards.
|
63
|
+
#
|
64
|
+
# @param leaderboards [Array] Leaderboard names.
|
65
|
+
# @param member [String] Member name.
|
66
|
+
# @param score [float] Member score.
|
67
|
+
# @param member_data [String] Optional member data.
|
68
|
+
def rank_member_across(leaderboards, member, score, member_data = nil)
|
69
|
+
@redis_connection.multi do |transaction|
|
70
|
+
leaderboards.each do |leaderboard_name|
|
71
|
+
transaction.zadd(leaderboard_name, score, member)
|
72
|
+
transaction.zadd(ties_leaderboard_key(leaderboard_name), score, score.to_f.to_s)
|
73
|
+
transaction.hset(member_data_key(leaderboard_name), member, member_data) if member_data
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
# Rank an array of members in the named leaderboard.
|
79
|
+
#
|
80
|
+
# @param leaderboard_name [String] Name of the leaderboard.
|
81
|
+
# @param members_and_scores [Splat or Array] Variable list of members and scores
|
82
|
+
def rank_members_in(leaderboard_name, *members_and_scores)
|
83
|
+
if members_and_scores.is_a?(Array)
|
84
|
+
members_and_scores.flatten!
|
85
|
+
end
|
86
|
+
|
87
|
+
@redis_connection.multi do |transaction|
|
88
|
+
members_and_scores.each_slice(2) do |member_and_score|
|
89
|
+
transaction.zadd(leaderboard_name, member_and_score[1], member_and_score[0])
|
90
|
+
transaction.zadd(ties_leaderboard_key(leaderboard_name), member_and_score[0], member_and_score[0].to_f.to_s)
|
91
|
+
end
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
# Remove a member from the named leaderboard.
|
96
|
+
#
|
97
|
+
# @param leaderboard_name [String] Name of the leaderboard.
|
98
|
+
# @param member [String] Member name.
|
99
|
+
def remove_member_from(leaderboard_name, member)
|
100
|
+
member_score = @redis_connection.zscore(leaderboard_name, member) || nil
|
101
|
+
can_delete_score = member_score && members_from_score_range_in(leaderboard_name, member_score, member_score).length == 1
|
102
|
+
|
103
|
+
@redis_connection.multi do |transaction|
|
104
|
+
transaction.zrem(leaderboard_name, member)
|
105
|
+
transaction.zrem(ties_leaderboard_key(leaderboard_name), member_score.to_f.to_s) if can_delete_score
|
106
|
+
transaction.hdel(member_data_key(leaderboard_name), member)
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
# Retrieve the rank for a member in the named leaderboard.
|
111
|
+
#
|
112
|
+
# @param leaderboard_name [String] Name of the leaderboard.
|
113
|
+
# @param member [String] Member name.
|
114
|
+
#
|
115
|
+
# @return the rank for a member in the leaderboard.
|
116
|
+
def rank_for_in(leaderboard_name, member)
|
117
|
+
member_score = score_for_in(leaderboard_name, member)
|
118
|
+
if @reverse
|
119
|
+
return @redis_connection.zrank(ties_leaderboard_key(leaderboard_name), member_score.to_f.to_s) + 1 rescue nil
|
120
|
+
else
|
121
|
+
return @redis_connection.zrevrank(ties_leaderboard_key(leaderboard_name), member_score.to_f.to_s) + 1 rescue nil
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
# Retrieve the score and rank for a member in the named leaderboard.
|
126
|
+
#
|
127
|
+
# @param leaderboard_name [String]Name of the leaderboard.
|
128
|
+
# @param member [String] Member name.
|
129
|
+
#
|
130
|
+
# @return the score and rank for a member in the named leaderboard as a Hash.
|
131
|
+
def score_and_rank_for_in(leaderboard_name, member)
|
132
|
+
member_score = @redis_connection.zscore(leaderboard_name, member)
|
133
|
+
|
134
|
+
responses = @redis_connection.multi do |transaction|
|
135
|
+
transaction.zscore(leaderboard_name, member)
|
136
|
+
if @reverse
|
137
|
+
transaction.zrank(ties_leaderboard_key(leaderboard_name), member_score.to_f.to_s)
|
138
|
+
else
|
139
|
+
transaction.zrevrank(ties_leaderboard_key(leaderboard_name), member_score.to_f.to_s)
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
responses[0] = responses[0].to_f if responses[0]
|
144
|
+
responses[1] = responses[1] + 1 rescue nil
|
145
|
+
|
146
|
+
{@member_key => member, @score_key => responses[0], @rank_key => responses[1]}
|
147
|
+
end
|
148
|
+
|
149
|
+
# Remove members from the named leaderboard in a given score range.
|
150
|
+
#
|
151
|
+
# @param leaderboard_name [String] Name of the leaderboard.
|
152
|
+
# @param min_score [float] Minimum score.
|
153
|
+
# @param max_score [float] Maximum score.
|
154
|
+
def remove_members_in_score_range_in(leaderboard_name, min_score, max_score)
|
155
|
+
@redis_connection.multi do |transaction|
|
156
|
+
transaction.zremrangebyscore(leaderboard_name, min_score, max_score)
|
157
|
+
transaction.zremrangebyscore(ties_leaderboard_key(leaderboard_name), min_score, max_score)
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
# Expire the given leaderboard in a set number of seconds. Do not use this with
|
162
|
+
# leaderboards that utilize member data as there is no facility to cascade the
|
163
|
+
# expiration out to the keys for the member data.
|
164
|
+
#
|
165
|
+
# @param leaderboard_name [String] Name of the leaderboard.
|
166
|
+
# @param seconds [int] Number of seconds after which the leaderboard will be expired.
|
167
|
+
def expire_leaderboard_for(leaderboard_name, seconds)
|
168
|
+
@redis_connection.multi do |transaction|
|
169
|
+
transaction.expire(leaderboard_name, seconds)
|
170
|
+
transaction.expire(ties_leaderboard_key(leaderboard_name), seconds)
|
171
|
+
transaction.expire(member_data_key(leaderboard_name), seconds)
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
# Expire the given leaderboard at a specific UNIX timestamp. Do not use this with
|
176
|
+
# leaderboards that utilize member data as there is no facility to cascade the
|
177
|
+
# expiration out to the keys for the member data.
|
178
|
+
#
|
179
|
+
# @param leaderboard_name [String] Name of the leaderboard.
|
180
|
+
# @param timestamp [int] UNIX timestamp at which the leaderboard will be expired.
|
181
|
+
def expire_leaderboard_at_for(leaderboard_name, timestamp)
|
182
|
+
@redis_connection.multi do |transaction|
|
183
|
+
transaction.expireat(leaderboard_name, timestamp)
|
184
|
+
transaction.expireat(ties_leaderboard_key(leaderboard_name), timestamp)
|
185
|
+
transaction.expireat(member_data_key(leaderboard_name), timestamp)
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
189
|
+
# Retrieve a page of leaders from the named leaderboard for a given list of members.
|
190
|
+
#
|
191
|
+
# @param leaderboard_name [String] Name of the leaderboard.
|
192
|
+
# @param members [Array] Member names.
|
193
|
+
# @param options [Hash] Options to be used when retrieving the page from the named leaderboard.
|
194
|
+
#
|
195
|
+
# @return a page of leaders from the named leaderboard for a given list of members.
|
196
|
+
def ranked_in_list_in(leaderboard_name, members, options = {})
|
197
|
+
leaderboard_options = DEFAULT_LEADERBOARD_REQUEST_OPTIONS.dup
|
198
|
+
leaderboard_options.merge!(options)
|
199
|
+
|
200
|
+
ranks_for_members = []
|
201
|
+
|
202
|
+
responses = @redis_connection.multi do |transaction|
|
203
|
+
members.each do |member|
|
204
|
+
if @reverse
|
205
|
+
transaction.zrank(leaderboard_name, member)
|
206
|
+
else
|
207
|
+
transaction.zrevrank(leaderboard_name, member)
|
208
|
+
end
|
209
|
+
transaction.zscore(leaderboard_name, member)
|
210
|
+
end
|
211
|
+
end unless leaderboard_options[:members_only]
|
212
|
+
|
213
|
+
members.each_with_index do |member, index|
|
214
|
+
data = {}
|
215
|
+
data[@member_key] = member
|
216
|
+
unless leaderboard_options[:members_only]
|
217
|
+
data[@score_key] = responses[index * 2 + 1].to_f if responses[index * 2 + 1]
|
218
|
+
|
219
|
+
if @reverse
|
220
|
+
data[@rank_key] = @redis_connection.zrank(ties_leaderboard_key(leaderboard_name), data[@score_key].to_s) + 1 rescue nil
|
221
|
+
else
|
222
|
+
data[@rank_key] = @redis_connection.zrevrank(ties_leaderboard_key(leaderboard_name), data[@score_key].to_s) + 1 rescue nil
|
223
|
+
end
|
224
|
+
end
|
225
|
+
|
226
|
+
if leaderboard_options[:with_member_data]
|
227
|
+
data[@member_data_key] = member_data_for_in(leaderboard_name, member)
|
228
|
+
end
|
229
|
+
|
230
|
+
ranks_for_members << data
|
231
|
+
end
|
232
|
+
|
233
|
+
case leaderboard_options[:sort_by]
|
234
|
+
when :rank
|
235
|
+
ranks_for_members = ranks_for_members.sort_by { |member| member[@rank_key] }
|
236
|
+
when :score
|
237
|
+
ranks_for_members = ranks_for_members.sort_by { |member| member[@score_key] }
|
238
|
+
end
|
239
|
+
|
240
|
+
ranks_for_members
|
241
|
+
end
|
242
|
+
|
243
|
+
protected
|
244
|
+
|
245
|
+
# Key for ties leaderboard.
|
246
|
+
#
|
247
|
+
# @param leaderboard_name [String] Name of the leaderboard.
|
248
|
+
#
|
249
|
+
# @return a key in the form of +leaderboard_name:ties_namespace+
|
250
|
+
def ties_leaderboard_key(leaderboard_name)
|
251
|
+
"#{leaderboard_name}:#{@ties_namespace}"
|
252
|
+
end
|
253
|
+
end
|