Class: Leaderboard
- Inherits:
-
Object
- Object
- Leaderboard
- Defined in:
- lib/leaderboard.rb,
lib/leaderboard/version.rb
Direct Known Subclasses
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, :member_data_namespace => 'member_data', :global_member_data => false }
- 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.9.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.
-
#top(number, options = {}) ⇒ Object
Retrieve members from the leaderboard within a range from 1 to the number given.
-
#top_in(leaderboard_name, number, options = {}) ⇒ Object
Retrieve members from the named leaderboard within a range from 1 to the number given.
-
#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})
68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 |
# File 'lib/leaderboard.rb', line 68 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] @member_data_namespace = [:member_data_namespace] @global_member_data = [:global_member_data] @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.
48 49 50 |
# File 'lib/leaderboard.rb', line 48 def leaderboard_name @leaderboard_name end |
#page_size ⇒ Object
Page size to be used when paging through the leaderboard.
51 52 53 |
# File 'lib/leaderboard.rb', line 51 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)
56 57 58 |
# File 'lib/leaderboard.rb', line 56 def reverse @reverse end |
Instance Method Details
#all_leaders(options = {}) ⇒ Object Also known as: all_members
Retrieve all leaders from the leaderboard.
706 707 708 |
# File 'lib/leaderboard.rb', line 706 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.
718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 |
# File 'lib/leaderboard.rb', line 718 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.
875 876 877 |
# File 'lib/leaderboard.rb', line 875 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.
886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 |
# File 'lib/leaderboard.rb', line 886 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.
355 356 357 |
# File 'lib/leaderboard.rb', line 355 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.
364 365 366 |
# File 'lib/leaderboard.rb', line 364 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.
416 417 418 |
# File 'lib/leaderboard.rb', line 416 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.
426 427 428 |
# File 'lib/leaderboard.rb', line 426 def check_member_in?(leaderboard_name, member) !@redis_connection.zscore(leaderboard_name, member).nil? end |
#delete_leaderboard ⇒ Object
Delete the current leaderboard.
111 112 113 |
# File 'lib/leaderboard.rb', line 111 def delete_leaderboard delete_leaderboard_named(@leaderboard_name) end |
#delete_leaderboard_named(leaderboard_name) ⇒ Object
Delete the named leaderboard.
118 119 120 121 122 123 |
# File 'lib/leaderboard.rb', line 118 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.
106 107 108 |
# File 'lib/leaderboard.rb', line 106 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.
605 606 607 |
# File 'lib/leaderboard.rb', line 605 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.
627 628 629 |
# File 'lib/leaderboard.rb', line 627 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.
637 638 639 640 641 642 |
# File 'lib/leaderboard.rb', line 637 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.
615 616 617 618 619 620 |
# File 'lib/leaderboard.rb', line 615 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.
989 990 991 |
# File 'lib/leaderboard.rb', line 989 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.
650 651 652 |
# File 'lib/leaderboard.rb', line 650 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.
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 694 695 696 697 |
# File 'lib/leaderboard.rb', line 663 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.
845 846 847 |
# File 'lib/leaderboard.rb', line 845 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.
856 857 858 859 860 861 862 863 864 865 866 867 |
# File 'lib/leaderboard.rb', line 856 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.
207 208 209 |
# File 'lib/leaderboard.rb', line 207 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.
217 218 219 |
# File 'lib/leaderboard.rb', line 217 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.
778 779 780 |
# File 'lib/leaderboard.rb', line 778 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.
790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 |
# File 'lib/leaderboard.rb', line 790 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.
744 745 746 |
# File 'lib/leaderboard.rb', line 744 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.
756 757 758 759 760 761 762 763 764 765 766 767 768 769 |
# File 'lib/leaderboard.rb', line 756 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.
980 981 982 |
# File 'lib/leaderboard.rb', line 980 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.
575 576 577 |
# File 'lib/leaderboard.rb', line 575 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.
586 587 588 589 590 591 592 593 594 595 596 597 598 |
# File 'lib/leaderboard.rb', line 586 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.
504 505 506 |
# File 'lib/leaderboard.rb', line 504 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.
514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 |
# File 'lib/leaderboard.rb', line 514 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.
373 374 375 |
# File 'lib/leaderboard.rb', line 373 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.
383 384 385 386 387 388 389 |
# File 'lib/leaderboard.rb', line 383 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.
130 131 132 |
# File 'lib/leaderboard.rb', line 130 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.
153 154 155 156 157 158 159 160 |
# File 'lib/leaderboard.rb', line 153 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
175 176 177 |
# File 'lib/leaderboard.rb', line 175 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
193 194 195 196 197 198 199 200 |
# File 'lib/leaderboard.rb', line 193 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.
140 141 142 143 144 145 |
# File 'lib/leaderboard.rb', line 140 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.
256 257 258 |
# File 'lib/leaderboard.rb', line 256 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.
264 265 266 267 268 269 270 271 272 273 274 |
# File 'lib/leaderboard.rb', line 264 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.
922 923 924 |
# File 'lib/leaderboard.rb', line 922 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.
933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 |
# File 'lib/leaderboard.rb', line 933 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.
279 280 281 |
# File 'lib/leaderboard.rb', line 279 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.
241 242 243 |
# File 'lib/leaderboard.rb', line 241 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.
249 250 251 |
# File 'lib/leaderboard.rb', line 249 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.
287 288 289 290 291 292 |
# File 'lib/leaderboard.rb', line 287 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.
465 466 467 |
# File 'lib/leaderboard.rb', line 465 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.
474 475 476 |
# File 'lib/leaderboard.rb', line 474 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.
482 483 484 |
# File 'lib/leaderboard.rb', line 482 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.
491 492 493 494 495 496 497 |
# File 'lib/leaderboard.rb', line 491 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.
435 436 437 |
# File 'lib/leaderboard.rb', line 435 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.
445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 |
# File 'lib/leaderboard.rb', line 445 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.
396 397 398 |
# File 'lib/leaderboard.rb', line 396 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.
406 407 408 409 |
# File 'lib/leaderboard.rb', line 406 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.
533 534 535 |
# File 'lib/leaderboard.rb', line 533 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).
545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 |
# File 'lib/leaderboard.rb', line 545 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 |
#top(number, options = {}) ⇒ Object
Retrieve members from the leaderboard within a range from 1 to the number given.
823 824 825 |
# File 'lib/leaderboard.rb', line 823 def top(number, = {}) top_in(@leaderboard_name, number, ) end |
#top_in(leaderboard_name, number, options = {}) ⇒ Object
Retrieve members from the named leaderboard within a range from 1 to the number given.
835 836 837 |
# File 'lib/leaderboard.rb', line 835 def top_in(leaderboard_name, number, ={}) members_from_rank_range_in(leaderboard_name, 1, number, ) end |
#total_members ⇒ Object
Retrieve the total number of members in the leaderboard.
297 298 299 |
# File 'lib/leaderboard.rb', line 297 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.
306 307 308 |
# File 'lib/leaderboard.rb', line 306 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.
336 337 338 |
# File 'lib/leaderboard.rb', line 336 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.
347 348 349 |
# File 'lib/leaderboard.rb', line 347 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.
315 316 317 |
# File 'lib/leaderboard.rb', line 315 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.
325 326 327 328 |
# File 'lib/leaderboard.rb', line 325 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.
225 226 227 |
# File 'lib/leaderboard.rb', line 225 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.
234 235 236 |
# File 'lib/leaderboard.rb', line 234 def update_member_data_in(leaderboard_name, member, member_data) @redis_connection.hset(member_data_key(leaderboard_name), member, member_data) end |