class Leaderboard

Constants

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`.

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.

DEFAULT_PAGE_SIZE

Default page size: 25

DEFAULT_REDIS_HOST

Default Redis host: localhost

DEFAULT_REDIS_OPTIONS

Default Redis options when creating a connection to Redis. The DEFAULT_REDIS_HOST and DEFAULT_REDIS_PORT will be passed.

DEFAULT_REDIS_PORT

Default Redis post: 6379

VERSION

Attributes

leaderboard_name[R]

Name of the leaderboard.

page_size[R]

Page size to be used when paging through the leaderboard.

reverse[RW]

Determines whether or not various leaderboard methods return their data in highest-to-lowest (:reverse false) or lowest-to-highest (:reverse true)

Public Class Methods

new(leaderboard_name, options = DEFAULT_OPTIONS, redis_options = DEFAULT_REDIS_OPTIONS) click to toggle source

Create a new instance of a leaderboard.

@param leaderboard [String] Name of the leaderboard. @param options [Hash] Options for the leaderboard such as :page_size. @param redis_options [Hash] Options for configuring Redis.

Examples

leaderboard = Leaderboard.new('highscores')
leaderboard = Leaderboard.new('highscores', {:page_size => 10})
# File lib/leaderboard.rb, line 69
def initialize(leaderboard_name, options = DEFAULT_OPTIONS, redis_options = DEFAULT_REDIS_OPTIONS)
  leaderboard_options = DEFAULT_OPTIONS.dup
  leaderboard_options.merge!(options)

  @leaderboard_name = leaderboard_name

  @reverse   = leaderboard_options[:reverse]
  @page_size = leaderboard_options[:page_size]
  if @page_size.nil? || @page_size < 1
    @page_size = DEFAULT_PAGE_SIZE
  end
  @member_key = leaderboard_options[:member_key]
  @rank_key = leaderboard_options[:rank_key]
  @score_key = leaderboard_options[:score_key]
  @member_data_key = leaderboard_options[:member_data_key]
  @member_data_namespace = leaderboard_options[:member_data_namespace]
  @global_member_data = leaderboard_options[:global_member_data]

  @redis_connection = redis_options[:redis_connection]
  unless @redis_connection.nil?
    redis_options.delete(:redis_connection)
  end

  @redis_connection = Redis.new(redis_options) if @redis_connection.nil?
end

Public Instance Methods

all_leaders(options = {}) click to toggle source

Retrieve all leaders from the leaderboard.

@param options [Hash] Options to be used when retrieving the leaders from the leaderboard.

@return the leaders from the leaderboard.

# File lib/leaderboard.rb, line 746
def all_leaders(options = {})
  all_leaders_from(@leaderboard_name, options)
end
Also aliased as: all_members
all_leaders_from(leaderboard_name, options = {}) click to toggle source

Retrieves all leaders from the named leaderboard.

@param leaderboard_name [String] Name of the leaderboard. @param options [Hash] Options to be used when retrieving the leaders from the named leaderboard.

@return the named leaderboard.

# File lib/leaderboard.rb, line 758
def all_leaders_from(leaderboard_name, options = {})
  leaderboard_options = DEFAULT_LEADERBOARD_REQUEST_OPTIONS.dup
  leaderboard_options.merge!(options)

  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, leaderboard_options)
  else
    return []
  end
end
Also aliased as: all_members_from
all_members(options = {})
Alias for: all_leaders
all_members_from(leaderboard_name, options = {})
Alias for: all_leaders_from
around_me(member, options = {}) click to toggle source

Retrieve a page of leaders from the leaderboard around a given member.

@param member [String] Member name. @param options [Hash] Options to be used when retrieving the page from the leaderboard.

@return a page of leaders from the leaderboard around a given member.

# File lib/leaderboard.rb, line 915
def around_me(member, options = {})
  around_me_in(@leaderboard_name, member, options)
end
around_me_in(leaderboard_name, member, options = {}) click to toggle source

Retrieve a page of leaders from the named leaderboard around a given member.

@param leaderboard_name [String] Name of the leaderboard. @param member [String] Member name. @param options [Hash] Options to be used when retrieving the page from the named leaderboard.

@return a page of leaders from the named leaderboard around a given member. Returns an empty array for a non-existent member.

# File lib/leaderboard.rb, line 926
def around_me_in(leaderboard_name, member, options = {})
  leaderboard_options = DEFAULT_LEADERBOARD_REQUEST_OPTIONS.dup
  leaderboard_options.merge!(options)

  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(leaderboard_options[: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, leaderboard_options)
  else
    return []
  end
end
change_score_for(member, delta, member_data = nil) click to toggle source

Change the score for a member in the leaderboard by a score delta which can be positive or negative.

@param member [String] Member name. @param delta [float] Score change. @param member_data [String] Optional member data.

# File lib/leaderboard.rb, line 391
def change_score_for(member, delta, member_data = nil)
  change_score_for_member_in(@leaderboard_name, member, delta, member_data)
end
change_score_for_member_in(leaderboard_name, member, delta, member_data) click to toggle source

Change the score for a member in the named leaderboard by a delta which can be positive or negative.

@param leaderboard_name [String] Name of the leaderboard. @param member [String] Member name. @param delta [float] Score change. @param member_data [String] Optional member data.

# File lib/leaderboard.rb, line 401
def change_score_for_member_in(leaderboard_name, member, delta, member_data)
  @redis_connection.multi do |transaction|
    transaction.zincrby(leaderboard_name, delta, member)
    transaction.hset(member_data_key(leaderboard_name), member, member_data) if member_data
  end
end
check_member?(member) click to toggle source

Check to see if a member exists in the leaderboard.

@param member [String] Member name.

@return true if the member exists in the leaderboard, false otherwise.

# File lib/leaderboard.rb, line 456
def check_member?(member)
  check_member_in?(@leaderboard_name, member)
end
check_member_in?(leaderboard_name, member) click to toggle source

Check to see if a member exists in the named leaderboard.

@param leaderboard_name [String] Name of the leaderboard. @param member [String] Member name.

@return true if the member exists in the named leaderboard, false otherwise.

# File lib/leaderboard.rb, line 466
def check_member_in?(leaderboard_name, member)
  !@redis_connection.zscore(leaderboard_name, member).nil?
end
delete_leaderboard() click to toggle source

Delete the current leaderboard.

# File lib/leaderboard.rb, line 112
def delete_leaderboard
  delete_leaderboard_named(@leaderboard_name)
end
delete_leaderboard_named(leaderboard_name) click to toggle source

Delete the named leaderboard.

@param leaderboard_name [String] Name of the leaderboard.

# File lib/leaderboard.rb, line 119
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() click to toggle source

Disconnect the Redis connection.

# File lib/leaderboard.rb, line 107
def disconnect
  @redis_connection.client.disconnect
end
expire_leaderboard(seconds) click to toggle source

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.

@param seconds [int] Number of seconds after which the leaderboard will be expired.

# File lib/leaderboard.rb, line 645
def expire_leaderboard(seconds)
  expire_leaderboard_for(@leaderboard_name, seconds)
end
expire_leaderboard_at(timestamp) click to toggle source

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.

@param timestamp [int] UNIX timestamp at which the leaderboard will be expired.

# File lib/leaderboard.rb, line 667
def expire_leaderboard_at(timestamp)
  expire_leaderboard_at_for(@leaderboard_name, timestamp)
end
expire_leaderboard_at_for(leaderboard_name, timestamp) click to toggle source

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.

@param leaderboard_name [String] Name of the leaderboard. @param timestamp [int] UNIX timestamp at which the leaderboard will be expired.

# File lib/leaderboard.rb, line 677
def expire_leaderboard_at_for(leaderboard_name, timestamp)
  @redis_connection.multi do |transaction|
    transaction.expireat(leaderboard_name, timestamp)
    transaction.expireat(member_data_key(leaderboard_name), timestamp)
  end
end
expire_leaderboard_for(leaderboard_name, seconds) click to toggle source

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.

@param leaderboard_name [String] Name of the leaderboard. @param seconds [int] Number of seconds after which the leaderboard will be expired.

# File lib/leaderboard.rb, line 655
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}) click to toggle source

Intersect leaderboards given by keys with this leaderboard into a named destination leaderboard.

@param destination [String] Destination leaderboard name. @param keys [Array] Leaderboards to be merged with the current leaderboard. @param options [Hash] Options for intersecting the leaderboards.

# File lib/leaderboard.rb, line 1035
def intersect_leaderboards(destination, keys, options = {:aggregate => :sum})
  @redis_connection.zinterstore(destination, keys.insert(0, @leaderboard_name), options)
end
leaders(current_page, options = {}) click to toggle source

Retrieve a page of leaders from the leaderboard.

@param current_page [int] Page to retrieve from the leaderboard. @param options [Hash] Options to be used when retrieving the page from the leaderboard.

@return a page of leaders from the leaderboard.

# File lib/leaderboard.rb, line 690
def leaders(current_page, options = {})
  leaders_in(@leaderboard_name, current_page, options)
end
Also aliased as: members
leaders_in(leaderboard_name, current_page, options = {}) click to toggle source

Retrieve a page of leaders from the named leaderboard.

@param leaderboard_name [String] Name of the leaderboard. @param current_page [int] Page to retrieve from the named leaderboard. @param options [Hash] Options to be used when retrieving the page from the named leaderboard.

@return a page of leaders from the named leaderboard.

# File lib/leaderboard.rb, line 703
def leaders_in(leaderboard_name, current_page, options = {})
  leaderboard_options = DEFAULT_LEADERBOARD_REQUEST_OPTIONS.dup
  leaderboard_options.merge!(options)

  if current_page < 1
    current_page = 1
  end

  page_size = validate_page_size(leaderboard_options[: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, leaderboard_options)
  else
    return []
  end
end
Also aliased as: members_in
member_at(position, options = {}) click to toggle source

Retrieve a member at the specified index from the leaderboard.

@param position [int] Position in leaderboard. @param options [Hash] Options to be used when retrieving the member from the leaderboard.

@return a member from the leaderboard.

# File lib/leaderboard.rb, line 885
def member_at(position, options = {})
  member_at_in(@leaderboard_name, position, options)
end
member_at_in(leaderboard_name, position, options = {}) click to toggle source

Retrieve a member at the specified index from the leaderboard.

@param leaderboard_name [String] Name of the leaderboard. @param position [int] Position in named leaderboard. @param options [Hash] Options to be used when retrieving the member from the named leaderboard.

@return a page of leaders from the named leaderboard.

# File lib/leaderboard.rb, line 896
def member_at_in(leaderboard_name, position, options = {})
  if position > 0 && position <= total_members_in(leaderboard_name)
    leaderboard_options = DEFAULT_LEADERBOARD_REQUEST_OPTIONS.dup
    leaderboard_options.merge!(options)
    page_size = validate_page_size(leaderboard_options[: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, options)
    leaders[offset] if leaders
  end
end
member_data_for(member) click to toggle source

Retrieve the optional member data for a given member in the leaderboard.

@param member [String] Member name.

@return String of optional member data.

# File lib/leaderboard.rb, line 208
def member_data_for(member)
  member_data_for_in(@leaderboard_name, member)
end
member_data_for_in(leaderboard_name, member) click to toggle source

Retrieve the optional member data for a given member in the named leaderboard.

@param leaderboard_name [String] Name of the leaderboard. @param member [String] Member name.

@return String of optional member data.

# File lib/leaderboard.rb, line 218
def member_data_for_in(leaderboard_name, member)
  @redis_connection.hget(member_data_key(leaderboard_name), member)
end
members(current_page, options = {})
Alias for: leaders
members_data_for(members) click to toggle source

Retrieve the optional member data for the given members in the leaderboard.

@param members [Array] Member names.

@return array of strings of optional member data.

# File lib/leaderboard.rb, line 238
def members_data_for(members)
  members_data_for_in(@leaderboard_name, members)
end
members_data_for_in(leaderboard_name, members) click to toggle source

Retrieve the optional member data for a given member in the named leaderboard.

@param leaderboard_name [String] Name of the leaderboard. @param members [Array] Member names.

@return array of strings of optional member data.

# File lib/leaderboard.rb, line 228
def members_data_for_in(leaderboard_name, members)
  return [] unless members.size > 0
  @redis_connection.hmget(member_data_key(leaderboard_name), *members)
end
members_from_rank_range(starting_rank, ending_rank, options = {}) click to toggle source

Retrieve members from the leaderboard within a given rank range.

@param starting_rank [int] Starting rank (inclusive). @param ending_rank [int] Ending rank (inclusive). @param options [Hash] Options to be used when retrieving the data from the leaderboard.

@return members from the leaderboard that fall within the given rank range.

# File lib/leaderboard.rb, line 818
def members_from_rank_range(starting_rank, ending_rank, options = {})
  members_from_rank_range_in(@leaderboard_name, starting_rank, ending_rank, options)
end
members_from_rank_range_in(leaderboard_name, starting_rank, ending_rank, options = {}) click to toggle source

Retrieve members from the named leaderboard within a given rank range.

@param leaderboard_name [String] Name of the leaderboard. @param starting_rank [int] Starting rank (inclusive). @param ending_rank [int] Ending rank (inclusive). @param options [Hash] Options to be used when retrieving the data from the leaderboard.

@return members from the leaderboard that fall within the given rank range.

# File lib/leaderboard.rb, line 830
def members_from_rank_range_in(leaderboard_name, starting_rank, ending_rank, options = {})
  leaderboard_options = DEFAULT_LEADERBOARD_REQUEST_OPTIONS.dup
  leaderboard_options.merge!(options)

  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, leaderboard_options)
  else
    return []
  end
end
members_from_score_range(minimum_score, maximum_score, options = {}) click to toggle source

Retrieve members from the leaderboard within a given score range.

@param minimum_score [float] Minimum score (inclusive). @param maximum_score [float] Maximum score (inclusive). @param options [Hash] Options to be used when retrieving the data from the leaderboard.

@return members from the leaderboard that fall within the given score range.

# File lib/leaderboard.rb, line 784
def members_from_score_range(minimum_score, maximum_score, options = {})
  members_from_score_range_in(@leaderboard_name, minimum_score, maximum_score, options)
end
members_from_score_range_in(leaderboard_name, minimum_score, maximum_score, options = {}) click to toggle source

Retrieve members from the named leaderboard within a given score range.

@param leaderboard_name [String] Name of the leaderboard. @param minimum_score [float] Minimum score (inclusive). @param maximum_score [float] Maximum score (inclusive). @param options [Hash] Options to be used when retrieving the data from the leaderboard.

@return members from the leaderboard that fall within the given score range.

# File lib/leaderboard.rb, line 796
def members_from_score_range_in(leaderboard_name, minimum_score, maximum_score, options = {})
  leaderboard_options = DEFAULT_LEADERBOARD_REQUEST_OPTIONS.dup
  leaderboard_options.merge!(options)

  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, leaderboard_options)
  else
    return []
  end
end
members_in(leaderboard_name, current_page, options = {})
Alias for: leaders_in
merge_leaderboards(destination, keys, options = {:aggregate => :sum}) click to toggle source

Merge leaderboards given by keys with this leaderboard into a named destination leaderboard.

@param destination [String] Destination leaderboard name. @param keys [Array] Leaderboards to be merged with the current leaderboard. @param options [Hash] Options for merging the leaderboards.

# File lib/leaderboard.rb, line 1026
def merge_leaderboards(destination, keys, options = {:aggregate => :sum})
  @redis_connection.zunionstore(destination, keys.insert(0, @leaderboard_name), options)
end
page_for(member, page_size = DEFAULT_PAGE_SIZE) click to toggle source

Determine the page where a member falls in the leaderboard.

@param member [String] Member name. @param page_size [int] Page size to be used in determining page location.

@return the page where a member falls in the leaderboard.

# File lib/leaderboard.rb, line 615
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) click to toggle source

Determine the page where a member falls in the named leaderboard.

@param leaderboard [String] Name of the leaderboard. @param member [String] Member name. @param page_size [int] Page size to be used in determining page location.

@return the page where a member falls in the leaderboard.

# File lib/leaderboard.rb, line 626
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
page_size=(page_size) click to toggle source

Set the page size to be used when paging through the leaderboard. This method also has the side effect of setting the page size to the DEFAULT_PAGE_SIZE if the page size is less than 1.

@param page_size [int] Page size.

# File lib/leaderboard.rb, line 100
def page_size=(page_size)
  page_size = DEFAULT_PAGE_SIZE if page_size < 1

  @page_size = page_size
end
percentile_for(member) click to toggle source

Retrieve the percentile for a member in the leaderboard.

@param member [String] Member name.

@return the percentile for a member in the leaderboard. Return nil for a non-existent member.

# File lib/leaderboard.rb, line 544
def percentile_for(member)
  percentile_for_in(@leaderboard_name, member)
end
percentile_for_in(leaderboard_name, member) click to toggle source

Retrieve the percentile for a member in the named leaderboard.

@param leaderboard_name [String] Name of the leaderboard. @param member [String] Member name.

@return the percentile for a member in the named leaderboard.

# File lib/leaderboard.rb, line 554
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) click to toggle source

Retrieve the rank for a member in the leaderboard.

@param member [String] Member name.

@return the rank for a member in the leaderboard.

# File lib/leaderboard.rb, line 413
def rank_for(member)
  rank_for_in(@leaderboard_name, member)
end
rank_for_in(leaderboard_name, member) click to toggle source

Retrieve the rank for a member in the named leaderboard.

@param leaderboard_name [String] Name of the leaderboard. @param member [String] Member name.

@return the rank for a member in the leaderboard.

# File lib/leaderboard.rb, line 423
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) click to toggle source

Rank a member in the leaderboard.

@param member [String] Member name. @param score [float] Member score. @param member_data [String] Optional member data.

# File lib/leaderboard.rb, line 131
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) click to toggle source

Rank a member across multiple leaderboards.

@param leaderboards [Array] Leaderboard names. @param member [String] Member name. @param score [float] Member score. @param member_data [String] Optional member data.

# File lib/leaderboard.rb, line 154
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) click to toggle source

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

@param rank_conditional [lambda] Lambda which must return true or false that controls whether or not the member is ranked in the leaderboard. @param member [String] Member name. @param score [float] Member score. @param member_data [String] Optional member_data.

# File lib/leaderboard.rb, line 176
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) click to toggle source

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

@param leaderboard_name [String] Name of the leaderboard. @param rank_conditional [lambda] Lambda which must return true or false that controls whether or not the member is ranked in the leaderboard. @param member [String] Member name. @param score [float] Member score. @param member_data [String] Optional member_data.

# File lib/leaderboard.rb, line 194
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) click to toggle source

Rank a member in the named leaderboard.

@param leaderboard_name [String] Name of the leaderboard. @param member [String] Member name. @param score [float] Member score. @param member_data [String] Optional member data.

# File lib/leaderboard.rb, line 141
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) click to toggle source

Rank an array of members in the leaderboard.

@param members_and_scores [Splat or Array] Variable list of members and scores

# File lib/leaderboard.rb, line 277
def rank_members(*members_and_scores)
  rank_members_in(@leaderboard_name, *members_and_scores)
end
rank_members_in(leaderboard_name, *members_and_scores) click to toggle source

Rank an array of members in the named leaderboard.

@param leaderboard_name [String] Name of the leaderboard. @param members_and_scores [Splat or Array] Variable list of members and scores

# File lib/leaderboard.rb, line 285
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 = {}) click to toggle source

Retrieve a page of leaders from the leaderboard for a given list of members.

@param members [Array] Member names. @param options [Hash] Options to be used when retrieving the page from the leaderboard.

@return a page of leaders from the leaderboard for a given list of members.

# File lib/leaderboard.rb, line 962
def ranked_in_list(members, options = {})
  ranked_in_list_in(@leaderboard_name, members, options)
end
ranked_in_list_in(leaderboard_name, members, options = {}) click to toggle source

Retrieve a page of leaders from the named leaderboard for a given list of members.

@param leaderboard_name [String] Name of the leaderboard. @param members [Array] Member names. @param options [Hash] Options to be used when retrieving the page from the named leaderboard.

@return a page of leaders from the named leaderboard for a given list of members.

# File lib/leaderboard.rb, line 973
def ranked_in_list_in(leaderboard_name, members, options = {})
  leaderboard_options = DEFAULT_LEADERBOARD_REQUEST_OPTIONS.dup
  leaderboard_options.merge!(options)

  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 leaderboard_options[:members_only]

  members.each_with_index do |member, index|
    data = {}
    data[@member_key] = member
    unless leaderboard_options[:members_only]
      data[@rank_key] = responses[index * 2] + 1 rescue nil
      if data[@rank_key] == nil
        next unless leaderboard_options[:include_missing]
      end
      data[@score_key] = responses[index * 2 + 1].to_f if responses[index * 2 + 1]
    end

    ranks_for_members << data
  end

  if leaderboard_options[:with_member_data]
    included_members = ranks_for_members.collect { |member| member[@member_key] }
    members_data_for_in(leaderboard_name, included_members).each_with_index do |member_data, index|
      ranks_for_members[index][@member_data_key] = member_data
    end
  end

  case leaderboard_options[: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) click to toggle source

Remove a member from the leaderboard.

@param member [String] Member name.

# File lib/leaderboard.rb, line 300
def remove_member(member)
  remove_member_from(@leaderboard_name, member)
end
remove_member_data(member) click to toggle source

Remove the optional member data for a given member in the leaderboard.

@param member [String] Member name.

# File lib/leaderboard.rb, line 262
def remove_member_data(member)
  remove_member_data_in(@leaderboard_name, member)
end
remove_member_data_in(leaderboard_name, member) click to toggle source

Remove the optional member data for a given member in the named leaderboard.

@param leaderboard_name [String] Name of the leaderboard. @param member [String] Member name.

# File lib/leaderboard.rb, line 270
def remove_member_data_in(leaderboard_name, member)
  @redis_connection.hdel(member_data_key(leaderboard_name), member)
end
remove_member_from(leaderboard_name, member) click to toggle source

Remove a member from the named leaderboard.

@param leaderboard_name [String] Name of the leaderboard. @param member [String] Member name.

# File lib/leaderboard.rb, line 308
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) click to toggle source

Remove members from the leaderboard in a given score range.

@param min_score [float] Minimum score. @param max_score [float] Maximum score.

# File lib/leaderboard.rb, line 505
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) click to toggle source

Remove members from the named leaderboard in a given score range.

@param leaderboard_name [String] Name of the leaderboard. @param min_score [float] Minimum score. @param max_score [float] Maximum score.

# File lib/leaderboard.rb, line 514
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) click to toggle source

Remove members from the leaderboard outside a given rank.

@param rank [int] The rank (inclusive) which we should keep. @return the total number of members removed.

# File lib/leaderboard.rb, line 522
def remove_members_outside_rank(rank)
  remove_members_outside_rank_in(@leaderboard_name, rank)
end
remove_members_outside_rank_in(leaderboard_name, rank) click to toggle source

Remove members from the leaderboard outside a given rank.

@param leaderboard_name [String] Name of the leaderboard. @param rank [int] The rank (inclusive) which we should keep. @return the total number of members removed.

# File lib/leaderboard.rb, line 531
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) click to toggle source

Retrieve the score and rank for a member in the leaderboard.

@param member [String] Member name.

@return the score and rank for a member in the leaderboard as a Hash.

# File lib/leaderboard.rb, line 475
def score_and_rank_for(member)
  score_and_rank_for_in(@leaderboard_name, member)
end
score_and_rank_for_in(leaderboard_name, member) click to toggle source

Retrieve the score and rank for a member in the named leaderboard.

@param leaderboard_name [String]Name of the leaderboard. @param member [String] Member name.

@return the score and rank for a member in the named leaderboard as a Hash.

# File lib/leaderboard.rb, line 485
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) click to toggle source

Retrieve the score for a member in the leaderboard.

@param member Member name.

@return the score for a member in the leaderboard or nil if the member is not in the leaderboard.

# File lib/leaderboard.rb, line 436
def score_for(member)
  score_for_in(@leaderboard_name, member)
end
score_for_in(leaderboard_name, member) click to toggle source

Retrieve the score for a member in the named leaderboard.

@param leaderboard_name Name of the leaderboard. @param member [String] Member name.

@return the score for a member in the leaderboard or nil if the member is not in the leaderboard.

# File lib/leaderboard.rb, line 446
def score_for_in(leaderboard_name, member)
  score = @redis_connection.zscore(leaderboard_name, member)
  score.to_f if score
end
score_for_percentile(percentile) click to toggle source

Calculate the score for a given percentile value in the leaderboard.

@param percentile [float] Percentile value (0.0 to 100.0 inclusive)

# File lib/leaderboard.rb, line 573
def score_for_percentile(percentile)
  score_for_percentile_in(@leaderboard_name, percentile)
end
score_for_percentile_in(leaderboard_name, percentile) click to toggle source

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).

@param percentile [float] Percentile value (0.0 to 100.0 inclusive)

# File lib/leaderboard.rb, line 585
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 = {}) click to toggle source

Retrieve members from the leaderboard within a range from 1 to the number given.

@param ending_rank [int] Ending rank (inclusive). @param options [Hash] Options to be used when retrieving the data from the leaderboard.

@return number from the leaderboard that fall within the given rank range.

# File lib/leaderboard.rb, line 863
def top(number, options = {})
  top_in(@leaderboard_name, number, options)
end
top_in(leaderboard_name, number, options={}) click to toggle source

Retrieve members from the named leaderboard within a range from 1 to the number given.

@param leaderboard_name [String] Name of the leaderboard. @param starting_rank [int] Starting rank (inclusive). @param ending_rank [int] Ending rank (inclusive). @param options [Hash] Options to be used when retrieving the data from the leaderboard.

@return members from the leaderboard that fall within the given rank range.

# File lib/leaderboard.rb, line 875
def top_in(leaderboard_name, number, options={})
  members_from_rank_range_in(leaderboard_name, 1, number, options)
end
total_members() click to toggle source

Retrieve the total number of members in the leaderboard.

@return total number of members in the leaderboard.

# File lib/leaderboard.rb, line 318
def total_members
  total_members_in(@leaderboard_name)
end
total_members_in(leaderboard_name) click to toggle source

Retrieve the total number of members in the named leaderboard.

@param leaderboard_name [String] Name of the leaderboard.

@return the total number of members in the named leaderboard.

# File lib/leaderboard.rb, line 327
def total_members_in(leaderboard_name)
  @redis_connection.zcard(leaderboard_name)
end
total_members_in_score_range(min_score, max_score) click to toggle source

Retrieve the total members in a given score range from the leaderboard.

@param min_score [float] Minimum score. @param max_score [float] Maximum score.

@return the total members in a given score range from the leaderboard.

# File lib/leaderboard.rb, line 357
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) click to toggle source

Retrieve the total members in a given score range from the named leaderboard.

@param leaderboard_name Name of the leaderboard. @param min_score [float] Minimum score. @param max_score [float] Maximum score.

@return the total members in a given score range from the named leaderboard.

# File lib/leaderboard.rb, line 368
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) click to toggle source

Retrieve the total number of pages in the leaderboard.

@param page_size [int, nil] Page size to be used when calculating the total number of pages.

@return the total number of pages in the leaderboard.

# File lib/leaderboard.rb, line 336
def total_pages(page_size = nil)
  total_pages_in(@leaderboard_name, page_size)
end
total_pages_in(leaderboard_name, page_size = nil) click to toggle source

Retrieve the total number of pages in the named leaderboard.

@param leaderboard_name [String] Name of the leaderboard. @param page_size [int, nil] Page size to be used when calculating the total number of pages.

@return the total number of pages in the named leaderboard.

# File lib/leaderboard.rb, line 346
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
total_scores() click to toggle source

Sum of scores for all members in leaderboard

@return Sum of scores for all members in leaderboard

# File lib/leaderboard.rb, line 375
def total_scores
  total_scores_in(@leaderboard_name)
end
total_scores_in(leaderboard_name) click to toggle source

Sum of scores for all members in the named leaderboard

@return Sum of scores for all members in named leaderboard

# File lib/leaderboard.rb, line 382
def total_scores_in(leaderboard_name)
  all_leaders_from(leaderboard_name).map{|hash| hash[:score] }.inject(0, :+)
end
update_member_data(member, member_data) click to toggle source

Update the optional member data for a given member in the leaderboard.

@param member [String] Member name. @param member_data [String] Optional member data.

# File lib/leaderboard.rb, line 246
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) click to toggle source

Update the optional member data for a given member in the named leaderboard.

@param leaderboard_name [String] Name of the leaderboard. @param member [String] Member name. @param member_data [String] Optional member data.

# File lib/leaderboard.rb, line 255
def update_member_data_in(leaderboard_name, member, member_data)
  @redis_connection.hset(member_data_key(leaderboard_name), member, member_data)
end

Protected Instance Methods

member_data_key(leaderboard_name) click to toggle source

Key for retrieving optional member data.

@param leaderboard_name [String] Name of the leaderboard.

@return a key in the form of leaderboard_name:member_data

# File lib/leaderboard.rb, line 1046
def member_data_key(leaderboard_name)
  @global_member_data == false ? "#{leaderboard_name}:#{@member_data_namespace}" : @member_data_namespace
end
validate_page_size(page_size) click to toggle source

Validate and return the page size. Returns the DEFAULT_PAGE_SIZE if the page size is less than 1.

@param page_size [int] Page size.

@return the page size. Returns the DEFAULT_PAGE_SIZE if the page size is less than 1.

# File lib/leaderboard.rb, line 1055
def validate_page_size(page_size)
  if page_size && page_size < 1
    page_size = DEFAULT_PAGE_SIZE
  end

  page_size
end