Class: TieRankingLeaderboard
- Inherits:
-
Leaderboard
- Object
- Leaderboard
- TieRankingLeaderboard
- Defined in:
- lib/tie_ranking_leaderboard.rb
Constant Summary collapse
- DEFAULT_OPTIONS =
Default options when creating a leaderboard. Page size is 25 and reverse is set to false, meaning various methods will return results in highest-to-lowest order.
{ :page_size => DEFAULT_PAGE_SIZE, :reverse => false, :member_key => :member, :rank_key => :rank, :score_key => :score, :member_data_key => :member_data, :member_data_namespace => 'member_data', :ties_namespace => 'ties' }
Constants inherited from Leaderboard
Leaderboard::DEFAULT_LEADERBOARD_REQUEST_OPTIONS, Leaderboard::DEFAULT_PAGE_SIZE, Leaderboard::DEFAULT_REDIS_HOST, Leaderboard::DEFAULT_REDIS_OPTIONS, Leaderboard::DEFAULT_REDIS_PORT, Leaderboard::VERSION
Instance Attribute Summary
Attributes inherited from Leaderboard
#leaderboard_name, #page_size, #reverse
Instance Method Summary collapse
-
#change_score_for_member_in(leaderboard_name, member, delta, member_data = nil) ⇒ Object
Change the score for a member in the named leaderboard by a delta which can be positive or negative.
-
#delete_leaderboard_named(leaderboard_name) ⇒ Object
Delete the named leaderboard.
-
#expire_leaderboard_at_for(leaderboard_name, timestamp) ⇒ Object
Expire the given leaderboard at a specific UNIX timestamp.
-
#expire_leaderboard_for(leaderboard_name, seconds) ⇒ Object
Expire the given leaderboard in a set number of seconds.
-
#initialize(leaderboard_name, options = DEFAULT_OPTIONS, redis_options = DEFAULT_REDIS_OPTIONS) ⇒ TieRankingLeaderboard
constructor
Create a new instance of a leaderboard.
-
#rank_for_in(leaderboard_name, member) ⇒ Object
Retrieve the rank for a member in the named leaderboard.
-
#rank_member_across(leaderboards, member, score, member_data = nil) ⇒ Object
Rank a member across multiple leaderboards.
-
#rank_member_in(leaderboard_name, member, score, member_data = nil) ⇒ Object
Rank a member in the named leaderboard.
-
#rank_members_in(leaderboard_name, *members_and_scores) ⇒ Object
Rank an array of members in the named leaderboard.
-
#ranked_in_list_in(leaderboard_name, members, options = {}) ⇒ Object
Retrieve a page of leaders from the named leaderboard for a given list of members.
-
#remove_member_from(leaderboard_name, member) ⇒ Object
Remove a member from the named leaderboard.
-
#remove_members_in_score_range_in(leaderboard_name, min_score, max_score) ⇒ Object
Remove members from the named leaderboard in a given score range.
-
#score_and_rank_for_in(leaderboard_name, member) ⇒ Object
Retrieve the score and rank for a member in the named leaderboard.
Methods inherited from Leaderboard
#all_leaders, #all_leaders_from, #around_me, #around_me_in, #change_score_for, #check_member?, #check_member_in?, #delete_leaderboard, #disconnect, #expire_leaderboard, #expire_leaderboard_at, #intersect_leaderboards, #leaders, #leaders_in, #member_at, #member_at_in, #member_data_for, #member_data_for_in, #members_data_for, #members_data_for_in, #members_from_rank_range, #members_from_rank_range_in, #members_from_score_range, #members_from_score_range_in, #merge_leaderboards, #page_for, #page_for_in, #percentile_for, #percentile_for_in, #rank_for, #rank_member, #rank_member_if, #rank_member_if_in, #rank_members, #ranked_in_list, #remove_member, #remove_member_data, #remove_member_data_in, #remove_members_in_score_range, #remove_members_outside_rank, #remove_members_outside_rank_in, #score_and_rank_for, #score_for, #score_for_in, #score_for_percentile, #score_for_percentile_in, #top, #top_in, #total_members, #total_members_in, #total_members_in_score_range, #total_members_in_score_range_in, #total_pages, #total_pages_in, #total_scores, #total_scores_in, #update_member_data, #update_member_data_in
Constructor Details
#initialize(leaderboard_name, options = DEFAULT_OPTIONS, redis_options = DEFAULT_REDIS_OPTIONS) ⇒ TieRankingLeaderboard
Create a new instance of a leaderboard.
Examples
leaderboard = Leaderboard.new('highscores')
leaderboard = Leaderboard.new('highscores', {:page_size => 10})
28 29 30 31 32 33 34 35 |
# File 'lib/tie_ranking_leaderboard.rb', line 28 def initialize(leaderboard_name, = DEFAULT_OPTIONS, = DEFAULT_REDIS_OPTIONS) super = DEFAULT_OPTIONS.dup .merge!() @ties_namespace = [:ties_namespace] end |
Instance Method Details
#change_score_for_member_in(leaderboard_name, member, delta, member_data = nil) ⇒ Object
Change the score for a member in the named leaderboard by a delta which can be positive or negative.
54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 |
# File 'lib/tie_ranking_leaderboard.rb', line 54 def change_score_for_member_in(leaderboard_name, member, delta, member_data = nil) previous_score = score_for(member) new_score = (previous_score || 0) + delta total_members_at_previous_score = @redis_connection.zrevrangebyscore(leaderboard_name, previous_score, previous_score) @redis_connection.multi do |transaction| transaction.zadd(leaderboard_name, new_score, member) transaction.zadd(ties_leaderboard_key(leaderboard_name), new_score, new_score.to_f.to_s) transaction.hset(member_data_key(leaderboard_name), member, member_data) if member_data end if total_members_at_previous_score.length == 1 @redis_connection.zrem(ties_leaderboard_key(leaderboard_name), previous_score.to_f.to_s) end end |
#delete_leaderboard_named(leaderboard_name) ⇒ Object
Delete the named leaderboard.
40 41 42 43 44 45 46 |
# File 'lib/tie_ranking_leaderboard.rb', line 40 def delete_leaderboard_named(leaderboard_name) @redis_connection.multi do |transaction| transaction.del(leaderboard_name) transaction.del(member_data_key(leaderboard_name)) transaction.del(ties_leaderboard_key(leaderboard_name)) end end |
#expire_leaderboard_at_for(leaderboard_name, timestamp) ⇒ Object
Expire the given leaderboard at a specific UNIX timestamp. Do not use this with leaderboards that utilize member data as there is no facility to cascade the expiration out to the keys for the member data.
203 204 205 206 207 208 209 |
# File 'lib/tie_ranking_leaderboard.rb', line 203 def expire_leaderboard_at_for(leaderboard_name, ) @redis_connection.multi do |transaction| transaction.expireat(leaderboard_name, ) transaction.expireat(ties_leaderboard_key(leaderboard_name), ) transaction.expireat(member_data_key(leaderboard_name), ) end end |
#expire_leaderboard_for(leaderboard_name, seconds) ⇒ Object
Expire the given leaderboard in a set number of seconds. Do not use this with leaderboards that utilize member data as there is no facility to cascade the expiration out to the keys for the member data.
189 190 191 192 193 194 195 |
# File 'lib/tie_ranking_leaderboard.rb', line 189 def expire_leaderboard_for(leaderboard_name, seconds) @redis_connection.multi do |transaction| transaction.expire(leaderboard_name, seconds) transaction.expire(ties_leaderboard_key(leaderboard_name), seconds) transaction.expire(member_data_key(leaderboard_name), seconds) end end |
#rank_for_in(leaderboard_name, member) ⇒ Object
Retrieve the rank for a member in the named leaderboard.
138 139 140 141 142 143 144 145 |
# File 'lib/tie_ranking_leaderboard.rb', line 138 def rank_for_in(leaderboard_name, member) member_score = score_for_in(leaderboard_name, member) if @reverse return @redis_connection.zrank(ties_leaderboard_key(leaderboard_name), member_score.to_f.to_s) + 1 rescue nil else return @redis_connection.zrevrank(ties_leaderboard_key(leaderboard_name), member_score.to_f.to_s) + 1 rescue nil end end |
#rank_member_across(leaderboards, member, score, member_data = nil) ⇒ Object
Rank a member across multiple leaderboards.
97 98 99 100 101 |
# File 'lib/tie_ranking_leaderboard.rb', line 97 def rank_member_across(leaderboards, member, score, member_data = nil) leaderboards.each do |leaderboard_name| rank_member_in(leaderboard_name, member, score, member_data) end end |
#rank_member_in(leaderboard_name, member, score, member_data = nil) ⇒ Object
Rank a member in the named leaderboard.
77 78 79 80 81 82 83 84 85 86 87 88 89 |
# File 'lib/tie_ranking_leaderboard.rb', line 77 def rank_member_in(leaderboard_name, member, score, member_data = nil) member_score = @redis_connection.zscore(leaderboard_name, member) || nil can_delete_score = member_score && members_from_score_range_in(leaderboard_name, member_score, member_score).length == 1 && member_score != score @redis_connection.multi do |transaction| transaction.zadd(leaderboard_name, score, member) transaction.zadd(ties_leaderboard_key(leaderboard_name), score, score.to_f.to_s) transaction.zrem(ties_leaderboard_key(leaderboard_name), member_score.to_f.to_s) if can_delete_score transaction.hset(member_data_key(leaderboard_name), member, member_data) if member_data end end |
#rank_members_in(leaderboard_name, *members_and_scores) ⇒ Object
Rank an array of members in the named leaderboard.
107 108 109 110 111 112 113 114 115 |
# File 'lib/tie_ranking_leaderboard.rb', line 107 def rank_members_in(leaderboard_name, *members_and_scores) if members_and_scores.is_a?(Array) members_and_scores.flatten! end members_and_scores.each_slice(2) do |member_and_score| rank_member_in(leaderboard_name, member_and_score[0], member_and_score[1]) end end |
#ranked_in_list_in(leaderboard_name, members, options = {}) ⇒ Object
Retrieve a page of leaders from the named leaderboard for a given list of members.
218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 |
# File 'lib/tie_ranking_leaderboard.rb', line 218 def ranked_in_list_in(leaderboard_name, members, = {}) = DEFAULT_LEADERBOARD_REQUEST_OPTIONS.dup .merge!() ranks_for_members = [] responses = @redis_connection.multi do |transaction| members.each do |member| if @reverse transaction.zrank(leaderboard_name, member) else transaction.zrevrank(leaderboard_name, member) end transaction.zscore(leaderboard_name, member) end end unless [:members_only] members.each_with_index do |member, index| data = {} data[@member_key] = member unless [:members_only] data[@score_key] = responses[index * 2 + 1].to_f if responses[index * 2 + 1] if @reverse data[@rank_key] = @redis_connection.zrank(ties_leaderboard_key(leaderboard_name), data[@score_key].to_s) + 1 rescue nil else data[@rank_key] = @redis_connection.zrevrank(ties_leaderboard_key(leaderboard_name), data[@score_key].to_s) + 1 rescue nil end if data[@rank_key] == nil next unless [:include_missing] end end ranks_for_members << data end if [:with_member_data] included_members = ranks_for_members.collect { |member| member[@member_key] } members_data_for_in(leaderboard_name, included_members).each_with_index do |member_data, index| ranks_for_members[index][@member_data_key] = member_data end end case [:sort_by] when :rank ranks_for_members = ranks_for_members.sort_by { |member| member[@rank_key] } when :score ranks_for_members = ranks_for_members.sort_by { |member| member[@score_key] } end ranks_for_members end |
#remove_member_from(leaderboard_name, member) ⇒ Object
Remove a member from the named leaderboard.
121 122 123 124 125 126 127 128 129 130 |
# File 'lib/tie_ranking_leaderboard.rb', line 121 def remove_member_from(leaderboard_name, member) member_score = @redis_connection.zscore(leaderboard_name, member) || nil can_delete_score = member_score && members_from_score_range_in(leaderboard_name, member_score, member_score).length == 1 @redis_connection.multi do |transaction| transaction.zrem(leaderboard_name, member) transaction.zrem(ties_leaderboard_key(leaderboard_name), member_score.to_f.to_s) if can_delete_score transaction.hdel(member_data_key(leaderboard_name), member) end end |
#remove_members_in_score_range_in(leaderboard_name, min_score, max_score) ⇒ Object
Remove members from the named leaderboard in a given score range.
176 177 178 179 180 181 |
# File 'lib/tie_ranking_leaderboard.rb', line 176 def remove_members_in_score_range_in(leaderboard_name, min_score, max_score) @redis_connection.multi do |transaction| transaction.zremrangebyscore(leaderboard_name, min_score, max_score) transaction.zremrangebyscore(ties_leaderboard_key(leaderboard_name), min_score, max_score) end end |
#score_and_rank_for_in(leaderboard_name, member) ⇒ Object
Retrieve the score and rank for a member in the named leaderboard.
153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 |
# File 'lib/tie_ranking_leaderboard.rb', line 153 def score_and_rank_for_in(leaderboard_name, member) member_score = @redis_connection.zscore(leaderboard_name, member) responses = @redis_connection.multi do |transaction| transaction.zscore(leaderboard_name, member) if @reverse transaction.zrank(ties_leaderboard_key(leaderboard_name), member_score.to_f.to_s) else transaction.zrevrank(ties_leaderboard_key(leaderboard_name), member_score.to_f.to_s) end end responses[0] = responses[0].to_f if responses[0] responses[1] = responses[1] + 1 rescue nil {@member_key => member, @score_key => responses[0], @rank_key => responses[1]} end |