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 }
- 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.4.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})
62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 |
# File 'lib/leaderboard.rb', line 62 def initialize(leaderboard_name, = DEFAULT_OPTIONS, = DEFAULT_REDIS_OPTIONS) @leaderboard_name = leaderboard_name @reverse = [:reverse] @page_size = [:page_size] if @page_size.nil? || @page_size < 1 @page_size = DEFAULT_PAGE_SIZE end @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.
42 43 44 |
# File 'lib/leaderboard.rb', line 42 def leaderboard_name @leaderboard_name end |
#page_size ⇒ Object
Page size to be used when paging through the leaderboard.
45 46 47 |
# File 'lib/leaderboard.rb', line 45 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)
50 51 52 |
# File 'lib/leaderboard.rb', line 50 def reverse @reverse end |
Instance Method Details
#all_leaders(options = {}) ⇒ Object Also known as: all_members
Retrieve all leaders from the leaderboard.
691 692 693 |
# File 'lib/leaderboard.rb', line 691 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.
703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 |
# File 'lib/leaderboard.rb', line 703 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.
838 839 840 |
# File 'lib/leaderboard.rb', line 838 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.
849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 |
# File 'lib/leaderboard.rb', line 849 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.
340 341 342 |
# File 'lib/leaderboard.rb', line 340 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.
349 350 351 |
# File 'lib/leaderboard.rb', line 349 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.
401 402 403 |
# File 'lib/leaderboard.rb', line 401 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.
411 412 413 |
# File 'lib/leaderboard.rb', line 411 def check_member_in?(leaderboard_name, member) !@redis_connection.zscore(leaderboard_name, member).nil? end |
#delete_leaderboard ⇒ Object
Delete the current leaderboard.
96 97 98 |
# File 'lib/leaderboard.rb', line 96 def delete_leaderboard delete_leaderboard_named(@leaderboard_name) end |
#delete_leaderboard_named(leaderboard_name) ⇒ Object
Delete the named leaderboard.
103 104 105 106 107 108 |
# File 'lib/leaderboard.rb', line 103 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.
91 92 93 |
# File 'lib/leaderboard.rb', line 91 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.
590 591 592 |
# File 'lib/leaderboard.rb', line 590 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.
612 613 614 |
# File 'lib/leaderboard.rb', line 612 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.
622 623 624 625 626 627 |
# File 'lib/leaderboard.rb', line 622 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.
600 601 602 603 604 605 |
# File 'lib/leaderboard.rb', line 600 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.
952 953 954 |
# File 'lib/leaderboard.rb', line 952 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.
635 636 637 |
# File 'lib/leaderboard.rb', line 635 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.
648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 |
# File 'lib/leaderboard.rb', line 648 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.
808 809 810 |
# File 'lib/leaderboard.rb', line 808 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.
819 820 821 822 823 824 825 826 827 828 829 830 |
# File 'lib/leaderboard.rb', line 819 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.
192 193 194 |
# File 'lib/leaderboard.rb', line 192 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.
202 203 204 |
# File 'lib/leaderboard.rb', line 202 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.
763 764 765 |
# File 'lib/leaderboard.rb', line 763 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.
775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 |
# File 'lib/leaderboard.rb', line 775 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.
729 730 731 |
# File 'lib/leaderboard.rb', line 729 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.
741 742 743 744 745 746 747 748 749 750 751 752 753 754 |
# File 'lib/leaderboard.rb', line 741 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.
943 944 945 |
# File 'lib/leaderboard.rb', line 943 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.
560 561 562 |
# File 'lib/leaderboard.rb', line 560 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.
571 572 573 574 575 576 577 578 579 580 581 582 583 |
# File 'lib/leaderboard.rb', line 571 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.
489 490 491 |
# File 'lib/leaderboard.rb', line 489 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.
499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 |
# File 'lib/leaderboard.rb', line 499 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.
358 359 360 |
# File 'lib/leaderboard.rb', line 358 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.
368 369 370 371 372 373 374 |
# File 'lib/leaderboard.rb', line 368 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.
115 116 117 |
# File 'lib/leaderboard.rb', line 115 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.
138 139 140 141 142 143 144 145 |
# File 'lib/leaderboard.rb', line 138 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
160 161 162 |
# File 'lib/leaderboard.rb', line 160 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
178 179 180 181 182 183 184 185 |
# File 'lib/leaderboard.rb', line 178 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.
125 126 127 128 129 130 |
# File 'lib/leaderboard.rb', line 125 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.
241 242 243 |
# File 'lib/leaderboard.rb', line 241 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.
249 250 251 252 253 254 255 256 257 258 259 |
# File 'lib/leaderboard.rb', line 249 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.
885 886 887 |
# File 'lib/leaderboard.rb', line 885 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.
896 897 898 899 900 901 902 903 904 905 906 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 |
# File 'lib/leaderboard.rb', line 896 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] = member unless [:members_only] data[:rank] = responses[index * 2] + 1 rescue nil data[:score] = responses[index * 2 + 1].to_f if responses[index * 2 + 1] end if [:with_member_data] data[:member_data] = 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] } when :score ranks_for_members = ranks_for_members.sort_by { |member| member[:score] } end ranks_for_members end |
#remove_member(member) ⇒ Object
Remove a member from the leaderboard.
264 265 266 |
# File 'lib/leaderboard.rb', line 264 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.
226 227 228 |
# File 'lib/leaderboard.rb', line 226 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.
234 235 236 |
# File 'lib/leaderboard.rb', line 234 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.
272 273 274 275 276 277 |
# File 'lib/leaderboard.rb', line 272 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.
450 451 452 |
# File 'lib/leaderboard.rb', line 450 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.
459 460 461 |
# File 'lib/leaderboard.rb', line 459 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.
467 468 469 |
# File 'lib/leaderboard.rb', line 467 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.
476 477 478 479 480 481 482 |
# File 'lib/leaderboard.rb', line 476 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.
420 421 422 |
# File 'lib/leaderboard.rb', line 420 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.
430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 |
# File 'lib/leaderboard.rb', line 430 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 => member, :score => responses[0], :rank => responses[1]} end |
#score_for(member) ⇒ Object
Retrieve the score for a member in the leaderboard.
381 382 383 |
# File 'lib/leaderboard.rb', line 381 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.
391 392 393 394 |
# File 'lib/leaderboard.rb', line 391 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.
518 519 520 |
# File 'lib/leaderboard.rb', line 518 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).
530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 |
# File 'lib/leaderboard.rb', line 530 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.
282 283 284 |
# File 'lib/leaderboard.rb', line 282 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.
291 292 293 |
# File 'lib/leaderboard.rb', line 291 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.
321 322 323 |
# File 'lib/leaderboard.rb', line 321 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.
332 333 334 |
# File 'lib/leaderboard.rb', line 332 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.
300 301 302 |
# File 'lib/leaderboard.rb', line 300 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.
310 311 312 313 |
# File 'lib/leaderboard.rb', line 310 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.
210 211 212 |
# File 'lib/leaderboard.rb', line 210 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.
219 220 221 |
# File 'lib/leaderboard.rb', line 219 def update_member_data_in(leaderboard_name, member, member_data) @redis_connection.hset(member_data_key(leaderboard_name), member, member_data) end |