Class: Leaderboard
- Inherits:
-
Object
- Object
- Leaderboard
- Defined in:
- lib/leaderboard.rb,
lib/leaderboard/version.rb
Constant Summary collapse
- DEFAULT_PAGE_SIZE =
Default page size: 25
25
- 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 }
- DEFAULT_REDIS_HOST =
Default Redis host: localhost
'localhost'
- DEFAULT_REDIS_PORT =
Default Redis post: 6379
6379
- DEFAULT_REDIS_OPTIONS =
Default Redis options when creating a connection to Redis. The
DEFAULT_REDIS_HOST
andDEFAULT_REDIS_PORT
will be passed. { :host => DEFAULT_REDIS_HOST, :port => DEFAULT_REDIS_PORT }
- DEFAULT_LEADERBOARD_REQUEST_OPTIONS =
Default options when requesting data from a leaderboard.
:with_member_data
false: Return member data along with the member names.:page_size
nil: The default page size will be used.:members_only
false: Only return the member name, not their score and rank.:sort_by
:none: The default sort for a call to ‘ranked_in_list`. { :with_member_data => false, :page_size => nil, :members_only => false, :sort_by => :none }
- VERSION =
'3.5.0'.freeze
Instance Attribute Summary collapse
-
#leaderboard_name ⇒ Object
readonly
Name of the leaderboard.
-
#page_size ⇒ Object
Page size to be used when paging through the leaderboard.
-
#reverse ⇒ Object
Determines whether or not various leaderboard methods return their data in highest-to-lowest (
:reverse
false) or lowest-to-highest (:reverse
true).
Instance Method Summary collapse
-
#all_leaders(options = {}) ⇒ Object
(also: #all_members)
Retrieve all leaders from the leaderboard.
-
#all_leaders_from(leaderboard_name, options = {}) ⇒ Object
(also: #all_members_from)
Retrieves all leaders from the named leaderboard.
-
#around_me(member, options = {}) ⇒ Object
Retrieve a page of leaders from the leaderboard around a given member.
-
#around_me_in(leaderboard_name, member, options = {}) ⇒ Object
Retrieve a page of leaders from the named leaderboard around a given member.
-
#change_score_for(member, delta) ⇒ Object
Change the score for a member in the leaderboard by a score delta which can be positive or negative.
-
#change_score_for_member_in(leaderboard_name, member, delta) ⇒ Object
Change the score for a member in the named leaderboard by a delta which can be positive or negative.
-
#check_member?(member) ⇒ Boolean
Check to see if a member exists in the leaderboard.
-
#check_member_in?(leaderboard_name, member) ⇒ Boolean
Check to see if a member exists in the named leaderboard.
-
#delete_leaderboard ⇒ Object
Delete the current leaderboard.
-
#delete_leaderboard_named(leaderboard_name) ⇒ Object
Delete the named leaderboard.
-
#disconnect ⇒ Object
Disconnect the Redis connection.
-
#expire_leaderboard(seconds) ⇒ Object
Expire the current leaderboard in a set number of seconds.
-
#expire_leaderboard_at(timestamp) ⇒ Object
Expire the current leaderboard at a specific UNIX timestamp.
-
#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) ⇒ Leaderboard
constructor
Create a new instance of a leaderboard.
-
#intersect_leaderboards(destination, keys, options = {:aggregate => :sum}) ⇒ Object
Intersect leaderboards given by keys with this leaderboard into a named destination leaderboard.
-
#leaders(current_page, options = {}) ⇒ Object
(also: #members)
Retrieve a page of leaders from the leaderboard.
-
#leaders_in(leaderboard_name, current_page, options = {}) ⇒ Object
(also: #members_in)
Retrieve a page of leaders from the named leaderboard.
-
#member_at(position, options = {}) ⇒ Object
Retrieve a member at the specified index from the leaderboard.
-
#member_at_in(leaderboard_name, position, options = {}) ⇒ Object
Retrieve a member at the specified index from the leaderboard.
-
#member_data_for(member) ⇒ Object
Retrieve the optional member data for a given member in the leaderboard.
-
#member_data_for_in(leaderboard_name, member) ⇒ Object
Retrieve the optional member data for a given member in the named leaderboard.
-
#members_from_rank_range(starting_rank, ending_rank, options = {}) ⇒ Object
Retrieve members from the leaderboard within a given rank range.
-
#members_from_rank_range_in(leaderboard_name, starting_rank, ending_rank, options = {}) ⇒ Object
Retrieve members from the named leaderboard within a given rank range.
-
#members_from_score_range(minimum_score, maximum_score, options = {}) ⇒ Object
Retrieve members from the leaderboard within a given score range.
-
#members_from_score_range_in(leaderboard_name, minimum_score, maximum_score, options = {}) ⇒ Object
Retrieve members from the named leaderboard within a given score range.
-
#merge_leaderboards(destination, keys, options = {:aggregate => :sum}) ⇒ Object
Merge leaderboards given by keys with this leaderboard into a named destination leaderboard.
-
#page_for(member, page_size = DEFAULT_PAGE_SIZE) ⇒ Object
Determine the page where a member falls in the leaderboard.
-
#page_for_in(leaderboard_name, member, page_size = DEFAULT_PAGE_SIZE) ⇒ Object
Determine the page where a member falls in the named leaderboard.
-
#percentile_for(member) ⇒ Object
Retrieve the percentile for a member in the leaderboard.
-
#percentile_for_in(leaderboard_name, member) ⇒ Object
Retrieve the percentile for a member in the named leaderboard.
-
#rank_for(member) ⇒ Object
Retrieve the rank for a member in the leaderboard.
-
#rank_for_in(leaderboard_name, member) ⇒ Object
Retrieve the rank for a member in the named leaderboard.
-
#rank_member(member, score, member_data = nil) ⇒ Object
Rank a member in the leaderboard.
-
#rank_member_across(leaderboards, member, score, member_data = nil) ⇒ Object
Rank a member across multiple leaderboards.
-
#rank_member_if(rank_conditional, member, score, member_data = nil) ⇒ Object
Rank a member in the leaderboard based on execution of the
rank_conditional
. -
#rank_member_if_in(leaderboard_name, rank_conditional, member, score, member_data = nil) ⇒ Object
Rank a member in the named leaderboard based on execution of the
rank_conditional
. -
#rank_member_in(leaderboard_name, member, score, member_data = nil) ⇒ Object
Rank a member in the named leaderboard.
-
#rank_members(*members_and_scores) ⇒ Object
Rank an array of members in the leaderboard.
-
#rank_members_in(leaderboard_name, *members_and_scores) ⇒ Object
Rank an array of members in the named leaderboard.
-
#ranked_in_list(members, options = {}) ⇒ Object
Retrieve a page of leaders from the leaderboard for a given list of members.
-
#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(member) ⇒ Object
Remove a member from the leaderboard.
-
#remove_member_data(member) ⇒ Object
Remove the optional member data for a given member in the leaderboard.
-
#remove_member_data_in(leaderboard_name, member) ⇒ Object
Remove the optional member data for a given member in the named leaderboard.
-
#remove_member_from(leaderboard_name, member) ⇒ Object
Remove a member from the named leaderboard.
-
#remove_members_in_score_range(min_score, max_score) ⇒ Object
Remove members from the leaderboard in a given score range.
-
#remove_members_in_score_range_in(leaderboard_name, min_score, max_score) ⇒ Object
Remove members from the named leaderboard in a given score range.
-
#remove_members_outside_rank(rank) ⇒ Object
Remove members from the leaderboard outside a given rank.
-
#remove_members_outside_rank_in(leaderboard_name, rank) ⇒ Object
Remove members from the leaderboard outside a given rank.
-
#score_and_rank_for(member) ⇒ Object
Retrieve the score and rank for a member in the leaderboard.
-
#score_and_rank_for_in(leaderboard_name, member) ⇒ Object
Retrieve the score and rank for a member in the named leaderboard.
-
#score_for(member) ⇒ Object
Retrieve the score for a member in the leaderboard.
-
#score_for_in(leaderboard_name, member) ⇒ Object
Retrieve the score for a member in the named leaderboard.
-
#score_for_percentile(percentile) ⇒ Object
Calculate the score for a given percentile value in the leaderboard.
-
#score_for_percentile_in(leaderboard_name, percentile) ⇒ Object
Calculate the score for a given percentile value in the named leaderboard.
-
#total_members ⇒ Object
Retrieve the total number of members in the leaderboard.
-
#total_members_in(leaderboard_name) ⇒ Object
Retrieve the total number of members in the named leaderboard.
-
#total_members_in_score_range(min_score, max_score) ⇒ Object
Retrieve the total members in a given score range from the leaderboard.
-
#total_members_in_score_range_in(leaderboard_name, min_score, max_score) ⇒ Object
Retrieve the total members in a given score range from the named leaderboard.
-
#total_pages(page_size = nil) ⇒ Object
Retrieve the total number of pages in the leaderboard.
-
#total_pages_in(leaderboard_name, page_size = nil) ⇒ Object
Retrieve the total number of pages in the named leaderboard.
-
#update_member_data(member, member_data) ⇒ Object
Update the optional member data for a given member in the leaderboard.
-
#update_member_data_in(leaderboard_name, member, member_data) ⇒ Object
Update the optional member data for a given member in the named leaderboard.
Constructor Details
#initialize(leaderboard_name, options = DEFAULT_OPTIONS, redis_options = DEFAULT_REDIS_OPTIONS) ⇒ Leaderboard
Create a new instance of a leaderboard.
Examples
leaderboard = Leaderboard.new('highscores')
leaderboard = Leaderboard.new('highscores', {:page_size => 10})
66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 |
# File 'lib/leaderboard.rb', line 66 def initialize(leaderboard_name, = DEFAULT_OPTIONS, = DEFAULT_REDIS_OPTIONS) = DEFAULT_OPTIONS.dup .merge!() @leaderboard_name = leaderboard_name @reverse = [:reverse] @page_size = [:page_size] if @page_size.nil? || @page_size < 1 @page_size = DEFAULT_PAGE_SIZE end @member_key = [:member_key] @rank_key = [:rank_key] @score_key = [:score_key] @member_data_key = [:member_data_key] @redis_connection = [:redis_connection] unless @redis_connection.nil? .delete(:redis_connection) end @redis_connection = Redis.new() if @redis_connection.nil? end |
Instance Attribute Details
#leaderboard_name ⇒ Object (readonly)
Name of the leaderboard.
46 47 48 |
# File 'lib/leaderboard.rb', line 46 def leaderboard_name @leaderboard_name end |
#page_size ⇒ Object
Page size to be used when paging through the leaderboard.
49 50 51 |
# File 'lib/leaderboard.rb', line 49 def page_size @page_size end |
#reverse ⇒ Object
Determines whether or not various leaderboard methods return their data in highest-to-lowest (:reverse
false) or lowest-to-highest (:reverse
true)
54 55 56 |
# File 'lib/leaderboard.rb', line 54 def reverse @reverse end |
Instance Method Details
#all_leaders(options = {}) ⇒ Object Also known as: all_members
Retrieve all leaders from the leaderboard.
702 703 704 |
# File 'lib/leaderboard.rb', line 702 def all_leaders( = {}) all_leaders_from(@leaderboard_name, ) end |
#all_leaders_from(leaderboard_name, options = {}) ⇒ Object Also known as: all_members_from
Retrieves all leaders from the named leaderboard.
714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 |
# File 'lib/leaderboard.rb', line 714 def all_leaders_from(leaderboard_name, = {}) = DEFAULT_LEADERBOARD_REQUEST_OPTIONS.dup .merge!() if @reverse raw_leader_data = @redis_connection.zrange(leaderboard_name, 0, -1, :with_scores => false) else raw_leader_data = @redis_connection.zrevrange(leaderboard_name, 0, -1, :with_scores => false) end if raw_leader_data return ranked_in_list_in(leaderboard_name, raw_leader_data, ) else return [] end end |
#around_me(member, options = {}) ⇒ Object
Retrieve a page of leaders from the leaderboard around a given member.
849 850 851 |
# File 'lib/leaderboard.rb', line 849 def around_me(member, = {}) around_me_in(@leaderboard_name, member, ) end |
#around_me_in(leaderboard_name, member, options = {}) ⇒ Object
Retrieve a page of leaders from the named leaderboard around a given member.
860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 |
# File 'lib/leaderboard.rb', line 860 def around_me_in(leaderboard_name, member, = {}) = DEFAULT_LEADERBOARD_REQUEST_OPTIONS.dup .merge!() reverse_rank_for_member = @reverse ? @redis_connection.zrank(leaderboard_name, member) : @redis_connection.zrevrank(leaderboard_name, member) return [] unless reverse_rank_for_member page_size = validate_page_size([:page_size]) || @page_size starting_offset = reverse_rank_for_member - (page_size / 2) if starting_offset < 0 starting_offset = 0 end ending_offset = (starting_offset + page_size) - 1 raw_leader_data = @reverse ? @redis_connection.zrange(leaderboard_name, starting_offset, ending_offset, :with_scores => false) : @redis_connection.zrevrange(leaderboard_name, starting_offset, ending_offset, :with_scores => false) if raw_leader_data return ranked_in_list_in(leaderboard_name, raw_leader_data, ) else return [] end end |
#change_score_for(member, delta) ⇒ Object
Change the score for a member in the leaderboard by a score delta which can be positive or negative.
351 352 353 |
# File 'lib/leaderboard.rb', line 351 def change_score_for(member, delta) change_score_for_member_in(@leaderboard_name, member, delta) end |
#change_score_for_member_in(leaderboard_name, member, delta) ⇒ Object
Change the score for a member in the named leaderboard by a delta which can be positive or negative.
360 361 362 |
# File 'lib/leaderboard.rb', line 360 def change_score_for_member_in(leaderboard_name, member, delta) @redis_connection.zincrby(leaderboard_name, delta, member) end |
#check_member?(member) ⇒ Boolean
Check to see if a member exists in the leaderboard.
412 413 414 |
# File 'lib/leaderboard.rb', line 412 def check_member?(member) check_member_in?(@leaderboard_name, member) end |
#check_member_in?(leaderboard_name, member) ⇒ Boolean
Check to see if a member exists in the named leaderboard.
422 423 424 |
# File 'lib/leaderboard.rb', line 422 def check_member_in?(leaderboard_name, member) !@redis_connection.zscore(leaderboard_name, member).nil? end |
#delete_leaderboard ⇒ Object
Delete the current leaderboard.
107 108 109 |
# File 'lib/leaderboard.rb', line 107 def delete_leaderboard delete_leaderboard_named(@leaderboard_name) end |
#delete_leaderboard_named(leaderboard_name) ⇒ Object
Delete the named leaderboard.
114 115 116 117 118 119 |
# File 'lib/leaderboard.rb', line 114 def delete_leaderboard_named(leaderboard_name) @redis_connection.multi do |transaction| transaction.del(leaderboard_name) transaction.del(member_data_key(leaderboard_name)) end end |
#disconnect ⇒ Object
Disconnect the Redis connection.
102 103 104 |
# File 'lib/leaderboard.rb', line 102 def disconnect @redis_connection.client.disconnect end |
#expire_leaderboard(seconds) ⇒ Object
Expire the current 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.
601 602 603 |
# File 'lib/leaderboard.rb', line 601 def expire_leaderboard(seconds) expire_leaderboard_for(@leaderboard_name, seconds) end |
#expire_leaderboard_at(timestamp) ⇒ Object
Expire the current 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.
623 624 625 |
# File 'lib/leaderboard.rb', line 623 def expire_leaderboard_at() expire_leaderboard_at_for(@leaderboard_name, ) 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.
633 634 635 636 637 638 |
# File 'lib/leaderboard.rb', line 633 def expire_leaderboard_at_for(leaderboard_name, ) @redis_connection.multi do |transaction| transaction.expireat(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.
611 612 613 614 615 616 |
# File 'lib/leaderboard.rb', line 611 def expire_leaderboard_for(leaderboard_name, seconds) @redis_connection.multi do |transaction| transaction.expire(leaderboard_name, seconds) transaction.expire(member_data_key(leaderboard_name), seconds) end end |
#intersect_leaderboards(destination, keys, options = {:aggregate => :sum}) ⇒ Object
Intersect leaderboards given by keys with this leaderboard into a named destination leaderboard.
963 964 965 |
# File 'lib/leaderboard.rb', line 963 def intersect_leaderboards(destination, keys, = {:aggregate => :sum}) @redis_connection.zinterstore(destination, keys.insert(0, @leaderboard_name), ) end |
#leaders(current_page, options = {}) ⇒ Object Also known as: members
Retrieve a page of leaders from the leaderboard.
646 647 648 |
# File 'lib/leaderboard.rb', line 646 def leaders(current_page, = {}) leaders_in(@leaderboard_name, current_page, ) end |
#leaders_in(leaderboard_name, current_page, options = {}) ⇒ Object Also known as: members_in
Retrieve a page of leaders from the named leaderboard.
659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 |
# File 'lib/leaderboard.rb', line 659 def leaders_in(leaderboard_name, current_page, = {}) = DEFAULT_LEADERBOARD_REQUEST_OPTIONS.dup .merge!() if current_page < 1 current_page = 1 end page_size = validate_page_size([:page_size]) || @page_size if current_page > total_pages_in(leaderboard_name, page_size) current_page = total_pages_in(leaderboard_name, page_size) end index_for_redis = current_page - 1 starting_offset = (index_for_redis * page_size) if starting_offset < 0 starting_offset = 0 end ending_offset = (starting_offset + page_size) - 1 if @reverse raw_leader_data = @redis_connection.zrange(leaderboard_name, starting_offset, ending_offset, :with_scores => false) else raw_leader_data = @redis_connection.zrevrange(leaderboard_name, starting_offset, ending_offset, :with_scores => false) end if raw_leader_data return ranked_in_list_in(leaderboard_name, raw_leader_data, ) else return [] end end |
#member_at(position, options = {}) ⇒ Object
Retrieve a member at the specified index from the leaderboard.
819 820 821 |
# File 'lib/leaderboard.rb', line 819 def member_at(position, = {}) member_at_in(@leaderboard_name, position, ) end |
#member_at_in(leaderboard_name, position, options = {}) ⇒ Object
Retrieve a member at the specified index from the leaderboard.
830 831 832 833 834 835 836 837 838 839 840 841 |
# File 'lib/leaderboard.rb', line 830 def member_at_in(leaderboard_name, position, = {}) if position <= total_members_in(leaderboard_name) = DEFAULT_LEADERBOARD_REQUEST_OPTIONS.dup .merge!() page_size = validate_page_size([:page_size]) || @page_size current_page = (position.to_f / page_size.to_f).ceil offset = (position - 1) % page_size leaders = leaders_in(leaderboard_name, current_page, ) leaders[offset] if leaders end end |
#member_data_for(member) ⇒ Object
Retrieve the optional member data for a given member in the leaderboard.
203 204 205 |
# File 'lib/leaderboard.rb', line 203 def member_data_for(member) member_data_for_in(@leaderboard_name, member) end |
#member_data_for_in(leaderboard_name, member) ⇒ Object
Retrieve the optional member data for a given member in the named leaderboard.
213 214 215 |
# File 'lib/leaderboard.rb', line 213 def member_data_for_in(leaderboard_name, member) @redis_connection.hget(member_data_key(leaderboard_name), member) end |
#members_from_rank_range(starting_rank, ending_rank, options = {}) ⇒ Object
Retrieve members from the leaderboard within a given rank range.
774 775 776 |
# File 'lib/leaderboard.rb', line 774 def members_from_rank_range(starting_rank, ending_rank, = {}) members_from_rank_range_in(@leaderboard_name, starting_rank, ending_rank, ) end |
#members_from_rank_range_in(leaderboard_name, starting_rank, ending_rank, options = {}) ⇒ Object
Retrieve members from the named leaderboard within a given rank range.
786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 |
# File 'lib/leaderboard.rb', line 786 def members_from_rank_range_in(leaderboard_name, starting_rank, ending_rank, = {}) = DEFAULT_LEADERBOARD_REQUEST_OPTIONS.dup .merge!() starting_rank -= 1 if starting_rank < 0 starting_rank = 0 end ending_rank -= 1 if ending_rank > total_members_in(leaderboard_name) ending_rank = total_members_in(leaderboard_name) - 1 end if @reverse raw_leader_data = @redis_connection.zrange(leaderboard_name, starting_rank, ending_rank, :with_scores => false) else raw_leader_data = @redis_connection.zrevrange(leaderboard_name, starting_rank, ending_rank, :with_scores => false) end if raw_leader_data return ranked_in_list_in(leaderboard_name, raw_leader_data, ) else return [] end end |
#members_from_score_range(minimum_score, maximum_score, options = {}) ⇒ Object
Retrieve members from the leaderboard within a given score range.
740 741 742 |
# File 'lib/leaderboard.rb', line 740 def members_from_score_range(minimum_score, maximum_score, = {}) members_from_score_range_in(@leaderboard_name, minimum_score, maximum_score, ) end |
#members_from_score_range_in(leaderboard_name, minimum_score, maximum_score, options = {}) ⇒ Object
Retrieve members from the named leaderboard within a given score range.
752 753 754 755 756 757 758 759 760 761 762 763 764 765 |
# File 'lib/leaderboard.rb', line 752 def members_from_score_range_in(leaderboard_name, minimum_score, maximum_score, = {}) = DEFAULT_LEADERBOARD_REQUEST_OPTIONS.dup .merge!() raw_leader_data = @reverse ? @redis_connection.zrangebyscore(leaderboard_name, minimum_score, maximum_score) : @redis_connection.zrevrangebyscore(leaderboard_name, maximum_score, minimum_score) if raw_leader_data return ranked_in_list_in(leaderboard_name, raw_leader_data, ) else return [] end end |
#merge_leaderboards(destination, keys, options = {:aggregate => :sum}) ⇒ Object
Merge leaderboards given by keys with this leaderboard into a named destination leaderboard.
954 955 956 |
# File 'lib/leaderboard.rb', line 954 def merge_leaderboards(destination, keys, = {:aggregate => :sum}) @redis_connection.zunionstore(destination, keys.insert(0, @leaderboard_name), ) end |
#page_for(member, page_size = DEFAULT_PAGE_SIZE) ⇒ Object
Determine the page where a member falls in the leaderboard.
571 572 573 |
# File 'lib/leaderboard.rb', line 571 def page_for(member, page_size = DEFAULT_PAGE_SIZE) page_for_in(@leaderboard_name, member, page_size) end |
#page_for_in(leaderboard_name, member, page_size = DEFAULT_PAGE_SIZE) ⇒ Object
Determine the page where a member falls in the named leaderboard.
582 583 584 585 586 587 588 589 590 591 592 593 594 |
# File 'lib/leaderboard.rb', line 582 def page_for_in(leaderboard_name, member, page_size = DEFAULT_PAGE_SIZE) rank_for_member = @reverse ? @redis_connection.zrank(leaderboard_name, member) : @redis_connection.zrevrank(leaderboard_name, member) if rank_for_member.nil? rank_for_member = 0 else rank_for_member += 1 end (rank_for_member.to_f / page_size.to_f).ceil end |
#percentile_for(member) ⇒ Object
Retrieve the percentile for a member in the leaderboard.
500 501 502 |
# File 'lib/leaderboard.rb', line 500 def percentile_for(member) percentile_for_in(@leaderboard_name, member) end |
#percentile_for_in(leaderboard_name, member) ⇒ Object
Retrieve the percentile for a member in the named leaderboard.
510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 |
# File 'lib/leaderboard.rb', line 510 def percentile_for_in(leaderboard_name, member) return nil unless check_member_in?(leaderboard_name, member) responses = @redis_connection.multi do |transaction| transaction.zcard(leaderboard_name) transaction.zrevrank(leaderboard_name, member) end percentile = ((responses[0] - responses[1] - 1).to_f / responses[0].to_f * 100).ceil if @reverse 100 - percentile else percentile end end |
#rank_for(member) ⇒ Object
Retrieve the rank for a member in the leaderboard.
369 370 371 |
# File 'lib/leaderboard.rb', line 369 def rank_for(member) rank_for_in(@leaderboard_name, member) end |
#rank_for_in(leaderboard_name, member) ⇒ Object
Retrieve the rank for a member in the named leaderboard.
379 380 381 382 383 384 385 |
# File 'lib/leaderboard.rb', line 379 def rank_for_in(leaderboard_name, member) if @reverse return @redis_connection.zrank(leaderboard_name, member) + 1 rescue nil else return @redis_connection.zrevrank(leaderboard_name, member) + 1 rescue nil end end |
#rank_member(member, score, member_data = nil) ⇒ Object
Rank a member in the leaderboard.
126 127 128 |
# File 'lib/leaderboard.rb', line 126 def rank_member(member, score, member_data = nil) rank_member_in(@leaderboard_name, member, score, member_data) end |
#rank_member_across(leaderboards, member, score, member_data = nil) ⇒ Object
Rank a member across multiple leaderboards.
149 150 151 152 153 154 155 156 |
# File 'lib/leaderboard.rb', line 149 def rank_member_across(leaderboards, member, score, member_data = nil) @redis_connection.multi do |transaction| leaderboards.each do |leaderboard_name| transaction.zadd(leaderboard_name, score, member) transaction.hset(member_data_key(leaderboard_name), member, member_data) if member_data end end end |
#rank_member_if(rank_conditional, member, score, member_data = nil) ⇒ Object
Rank a member in the leaderboard based on execution of the rank_conditional
.
The rank_conditional
is passed the following parameters:
member: Member name.
current_score: Current score for the member in the leaderboard.
score: Member score.
member_data: Optional member data.
leaderboard_options: Leaderboard options, e.g. :reverse => Value of reverse option
171 172 173 |
# File 'lib/leaderboard.rb', line 171 def rank_member_if(rank_conditional, member, score, member_data = nil) rank_member_if_in(@leaderboard_name, rank_conditional, member, score, member_data) end |
#rank_member_if_in(leaderboard_name, rank_conditional, member, score, member_data = nil) ⇒ Object
Rank a member in the named leaderboard based on execution of the rank_conditional
.
The rank_conditional
is passed the following parameters:
member: Member name.
current_score: Current score for the member in the leaderboard.
score: Member score.
member_data: Optional member data.
leaderboard_options: Leaderboard options, e.g. :reverse => Value of reverse option
189 190 191 192 193 194 195 196 |
# File 'lib/leaderboard.rb', line 189 def rank_member_if_in(leaderboard_name, rank_conditional, member, score, member_data = nil) current_score = @redis_connection.zscore(leaderboard_name, member) current_score = current_score.to_f if current_score if rank_conditional.call(member, current_score, score, member_data, {:reverse => @reverse}) 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.
136 137 138 139 140 141 |
# File 'lib/leaderboard.rb', line 136 def rank_member_in(leaderboard_name, member, score, member_data = nil) @redis_connection.multi do |transaction| transaction.zadd(leaderboard_name, score, member) transaction.hset(member_data_key(leaderboard_name), member, member_data) if member_data end end |
#rank_members(*members_and_scores) ⇒ Object
Rank an array of members in the leaderboard.
252 253 254 |
# File 'lib/leaderboard.rb', line 252 def rank_members(*members_and_scores) rank_members_in(@leaderboard_name, *members_and_scores) end |
#rank_members_in(leaderboard_name, *members_and_scores) ⇒ Object
Rank an array of members in the named leaderboard.
260 261 262 263 264 265 266 267 268 269 270 |
# File 'lib/leaderboard.rb', line 260 def rank_members_in(leaderboard_name, *members_and_scores) if members_and_scores.is_a?(Array) members_and_scores.flatten! end @redis_connection.multi do |transaction| members_and_scores.each_slice(2) do |member_and_score| transaction.zadd(leaderboard_name, member_and_score[1], member_and_score[0]) end end end |
#ranked_in_list(members, options = {}) ⇒ Object
Retrieve a page of leaders from the leaderboard for a given list of members.
896 897 898 |
# File 'lib/leaderboard.rb', line 896 def ranked_in_list(members, = {}) ranked_in_list_in(@leaderboard_name, members, ) 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.
907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 |
# File 'lib/leaderboard.rb', line 907 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[@rank_key] = responses[index * 2] + 1 rescue nil data[@score_key] = responses[index * 2 + 1].to_f if responses[index * 2 + 1] end if [:with_member_data] data[@member_data_key] = member_data_for_in(leaderboard_name, member) end ranks_for_members << data 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(member) ⇒ Object
Remove a member from the leaderboard.
275 276 277 |
# File 'lib/leaderboard.rb', line 275 def remove_member(member) remove_member_from(@leaderboard_name, member) end |
#remove_member_data(member) ⇒ Object
Remove the optional member data for a given member in the leaderboard.
237 238 239 |
# File 'lib/leaderboard.rb', line 237 def remove_member_data(member) remove_member_data_in(@leaderboard_name, member) end |
#remove_member_data_in(leaderboard_name, member) ⇒ Object
Remove the optional member data for a given member in the named leaderboard.
245 246 247 |
# File 'lib/leaderboard.rb', line 245 def remove_member_data_in(leaderboard_name, member) @redis_connection.hdel(member_data_key(leaderboard_name), member) end |
#remove_member_from(leaderboard_name, member) ⇒ Object
Remove a member from the named leaderboard.
283 284 285 286 287 288 |
# File 'lib/leaderboard.rb', line 283 def remove_member_from(leaderboard_name, member) @redis_connection.multi do |transaction| transaction.zrem(leaderboard_name, member) transaction.hdel(member_data_key(leaderboard_name), member) end end |
#remove_members_in_score_range(min_score, max_score) ⇒ Object
Remove members from the leaderboard in a given score range.
461 462 463 |
# File 'lib/leaderboard.rb', line 461 def remove_members_in_score_range(min_score, max_score) remove_members_in_score_range_in(@leaderboard_name, min_score, max_score) 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.
470 471 472 |
# File 'lib/leaderboard.rb', line 470 def remove_members_in_score_range_in(leaderboard_name, min_score, max_score) @redis_connection.zremrangebyscore(leaderboard_name, min_score, max_score) end |
#remove_members_outside_rank(rank) ⇒ Object
Remove members from the leaderboard outside a given rank.
478 479 480 |
# File 'lib/leaderboard.rb', line 478 def remove_members_outside_rank(rank) remove_members_outside_rank_in(@leaderboard_name, rank) end |
#remove_members_outside_rank_in(leaderboard_name, rank) ⇒ Object
Remove members from the leaderboard outside a given rank.
487 488 489 490 491 492 493 |
# File 'lib/leaderboard.rb', line 487 def remove_members_outside_rank_in(leaderboard_name, rank) if @reverse @redis_connection.zremrangebyrank(leaderboard_name, rank, -1) else @redis_connection.zremrangebyrank(leaderboard_name, 0, -(rank) - 1) end end |
#score_and_rank_for(member) ⇒ Object
Retrieve the score and rank for a member in the leaderboard.
431 432 433 |
# File 'lib/leaderboard.rb', line 431 def score_and_rank_for(member) score_and_rank_for_in(@leaderboard_name, member) end |
#score_and_rank_for_in(leaderboard_name, member) ⇒ Object
Retrieve the score and rank for a member in the named leaderboard.
441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 |
# File 'lib/leaderboard.rb', line 441 def score_and_rank_for_in(leaderboard_name, member) responses = @redis_connection.multi do |transaction| transaction.zscore(leaderboard_name, member) if @reverse transaction.zrank(leaderboard_name, member) else transaction.zrevrank(leaderboard_name, member) 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 |
#score_for(member) ⇒ Object
Retrieve the score for a member in the leaderboard.
392 393 394 |
# File 'lib/leaderboard.rb', line 392 def score_for(member) score_for_in(@leaderboard_name, member) end |
#score_for_in(leaderboard_name, member) ⇒ Object
Retrieve the score for a member in the named leaderboard.
402 403 404 405 |
# File 'lib/leaderboard.rb', line 402 def score_for_in(leaderboard_name, member) score = @redis_connection.zscore(leaderboard_name, member) score.to_f if score end |
#score_for_percentile(percentile) ⇒ Object
Calculate the score for a given percentile value in the leaderboard.
529 530 531 |
# File 'lib/leaderboard.rb', line 529 def score_for_percentile(percentile) score_for_percentile_in(@leaderboard_name, percentile) end |
#score_for_percentile_in(leaderboard_name, percentile) ⇒ Object
Calculate the score for a given percentile value in the named leaderboard.
See www.itl.nist.gov/div898/handbook/prc/section2/prc252.htm for implementation details (there are differing methods for calculating percentile scores that do not fall directly upon a ranked item; we are using the method specified by NIST, i.e. linear interpolation).
541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 |
# File 'lib/leaderboard.rb', line 541 def score_for_percentile_in(leaderboard_name, percentile) return nil unless percentile.between?(0, 100) total_members = total_members_in(leaderboard_name) return nil if total_members < 1 if @reverse percentile = 100 - percentile end index = (total_members - 1) * (percentile / 100.0) scores = @redis_connection.zrange( leaderboard_name, index.floor, index.ceil, :with_scores => true ).map{ |pair| pair.last } if index == index.floor scores[0] else interpolate_fraction = index - index.floor scores[0] + interpolate_fraction * (scores[1] - scores[0]) end end |
#total_members ⇒ Object
Retrieve the total number of members in the leaderboard.
293 294 295 |
# File 'lib/leaderboard.rb', line 293 def total_members total_members_in(@leaderboard_name) end |
#total_members_in(leaderboard_name) ⇒ Object
Retrieve the total number of members in the named leaderboard.
302 303 304 |
# File 'lib/leaderboard.rb', line 302 def total_members_in(leaderboard_name) @redis_connection.zcard(leaderboard_name) end |
#total_members_in_score_range(min_score, max_score) ⇒ Object
Retrieve the total members in a given score range from the leaderboard.
332 333 334 |
# File 'lib/leaderboard.rb', line 332 def total_members_in_score_range(min_score, max_score) total_members_in_score_range_in(@leaderboard_name, min_score, max_score) end |
#total_members_in_score_range_in(leaderboard_name, min_score, max_score) ⇒ Object
Retrieve the total members in a given score range from the named leaderboard.
343 344 345 |
# File 'lib/leaderboard.rb', line 343 def total_members_in_score_range_in(leaderboard_name, min_score, max_score) @redis_connection.zcount(leaderboard_name, min_score, max_score) end |
#total_pages(page_size = nil) ⇒ Object
Retrieve the total number of pages in the leaderboard.
311 312 313 |
# File 'lib/leaderboard.rb', line 311 def total_pages(page_size = nil) total_pages_in(@leaderboard_name, page_size) end |
#total_pages_in(leaderboard_name, page_size = nil) ⇒ Object
Retrieve the total number of pages in the named leaderboard.
321 322 323 324 |
# File 'lib/leaderboard.rb', line 321 def total_pages_in(leaderboard_name, page_size = nil) page_size ||= @page_size.to_f (total_members_in(leaderboard_name) / page_size.to_f).ceil end |
#update_member_data(member, member_data) ⇒ Object
Update the optional member data for a given member in the leaderboard.
221 222 223 |
# File 'lib/leaderboard.rb', line 221 def update_member_data(member, member_data) update_member_data_in(@leaderboard_name, member, member_data) end |
#update_member_data_in(leaderboard_name, member, member_data) ⇒ Object
Update the optional member data for a given member in the named leaderboard.
230 231 232 |
# File 'lib/leaderboard.rb', line 230 def update_member_data_in(leaderboard_name, member, member_data) @redis_connection.hset(member_data_key(leaderboard_name), member, member_data) end |