diff --git a/CHANGELOG.markdown b/CHANGELOG.markdown index 15bdcaf..c08a317 100644 --- a/CHANGELOG.markdown +++ b/CHANGELOG.markdown @@ -1,5 +1,11 @@ # CHANGELOG +## leaderboard 2.2.0 (in progress) + +* Added `members_from_score_range` and `members_from_score_range_in` methods. These will retrieve members from the leaderboard that fall within a given score range. +* Add `member_at` and `member_at_in` methods. These will retrieve a given member from the leaderboard at the specified position. +* `members` and `members_in` are now aliases for the `leaders` and `leaders_in` methods. + ## leaderboard 2.1.0 (2012-06-11) * Added ability to store optional member data alongside the leaderboard data. diff --git a/README.markdown b/README.markdown index ea733f8..4ea5ae8 100644 --- a/README.markdown +++ b/README.markdown @@ -174,6 +174,8 @@ Below is an example of retrieving the first page in the leaderboard without scor => [{:member=>"member_10"}, {:member=>"member_9"}, {:member=>"member_8"}, {:member=>"member_7"}, {:member=>"member_6"}, {:member=>"member_5"}, {:member=>"member_4"}, {:member=>"member_3"}, {:member=>"member_2"}, {:member=>"member_1"}] ``` +`members` and `members_in` are aliases for the `leaders` and `leaders_in` methods. + Add more members to your leaderboard: ```ruby @@ -202,10 +204,17 @@ Get rank and score for an arbitrary list of members (e.g. friends) from the lead Retrieve members from the leaderboard in a given score range: ```ruby -leaders = highscore_lb.leaders_from_score_range(4, 19) +members = highscore_lb.members_from_score_range(4, 19) => [{:member=>"member_10", :rank=>47, :score=>10.0}, {:member=>"member_9", :rank=>48, :score=>9.0}, {:member=>"member_8", :rank=>49, :score=>8.0}, {:member=>"member_7", :rank=>50, :score=>7.0}, {:member=>"member_6", :rank=>51, :score=>6.0}, {:member=>"member_5", :rank=>52, :score=>5.0}, {:member=>"member_4", :rank=>53, :score=>4.0}] ``` +Retrieve a single member from the leaderboard at a given position: + +```ruby +members = highscore_lb.member_at(4) + => {:member=>"member_92", :rank=>4, :score=>92.0} +``` + ### Ranking multiple members in a leaderboard at once Insert multiple data items for members and their associated scores: diff --git a/lib/leaderboard.rb b/lib/leaderboard.rb index e24d4aa..d8a3303 100644 --- a/lib/leaderboard.rb +++ b/lib/leaderboard.rb @@ -489,6 +489,8 @@ def leaders(current_page, options = {}) leaders_in(@leaderboard_name, current_page, options) end + alias_method :members, :leaders + # Retrieve a page of leaders from the named leaderboard. # # @param leaderboard_name [String] Name of the leaderboard. @@ -532,26 +534,28 @@ def leaders_in(leaderboard_name, current_page, options = {}) end end - # Retrieve leaders from the leaderboard within a given score range. + alias_method :members_in, :leaders_in + + # 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 leaders from the leaderboard that fall within the given score range. - def leaders_from_score_range(minimum_score, maximum_score, options = {}) - leaders_from_score_range_in(@leaderboard_name, minimum_score, maximum_score, options) + # @return members from the leaderboard that fall within the given score range. + def members_from_score_range(minimum_score, maximum_score, options = {}) + members_from_score_range_in(@leaderboard_name, minimum_score, maximum_score, options) end - # Retrieve leaders from the named leaderboard within a given score range. + # 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 leaders from the leaderboard that fall within the given score range. - def leaders_from_score_range_in(leaderboard_name, minimum_score, maximum_score, options = {}) + # @return members from the leaderboard that fall within the given score range. + def members_from_score_range_in(leaderboard_name, minimum_score, maximum_score, options = {}) leaderboard_options = DEFAULT_LEADERBOARD_REQUEST_OPTIONS.dup leaderboard_options.merge!(options) @@ -565,6 +569,36 @@ def leaders_from_score_range_in(leaderboard_name, minimum_score, maximum_score, return [] end end + + # 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. + def member_at(position, options = {}) + member_at_in(@leaderboard_name, position, options) + end + + # 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. + def member_at_in(leaderboard_name, position, options = {}) + if 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 # Retrieve a page of leaders from the leaderboard around a given member. # diff --git a/spec/leaderboard_spec.rb b/spec/leaderboard_spec.rb index 4c740ab..9dbd94e 100644 --- a/spec/leaderboard_spec.rb +++ b/spec/leaderboard_spec.rb @@ -102,6 +102,20 @@ leaders[-1][:score].to_i.should be(1) end + it 'should return the correct list when calling members' do + rank_members_in_leaderboard(25) + + @leaderboard.total_members.should be(25) + + members = @leaderboard.members(1) + + members.size.should be(25) + members[0][:member].should == 'member_25' + members[-2][:member].should == 'member_2' + members[-1][:member].should == 'member_1' + members[-1][:score].to_i.should be(1) + end + it 'should return the correct number of members when calling leaders with multiple pages' do rank_members_in_leaderboard(Leaderboard::DEFAULT_PAGE_SIZE * 3 + 1) @@ -126,24 +140,24 @@ leaders.size.should be(1) end - it 'should allow you to retrieve leaders in a given score range' do + it 'should allow you to retrieve members in a given score range' do rank_members_in_leaderboard(Leaderboard::DEFAULT_PAGE_SIZE) - leaders = @leaderboard.leaders_from_score_range(10, 15, {:with_scores => false, :with_rank => false}) + members = @leaderboard.members_from_score_range(10, 15, {:with_scores => false, :with_rank => false}) member_15 = {:member => 'member_15'} - leaders[0].should == member_15 + members[0].should == member_15 member_10 = {:member => 'member_10'} - leaders[5].should == member_10 + members[5].should == member_10 - leaders = @leaderboard.leaders_from_score_range(10, 15, {:with_scores => true, :with_rank => true, :with_member_data => true}) + members = @leaderboard.members_from_score_range(10, 15, {:with_scores => true, :with_rank => true, :with_member_data => true}) member_15 = {:member => 'member_15', :rank => 11, :score => 15.0, :member_data => {'member_name' => 'Leaderboard member 15'}} - leaders[0].should == member_15 + members[0].should == member_15 member_10 = {:member => 'member_10', :rank => 16, :score => 10.0, :member_data => {'member_name' => 'Leaderboard member 10'}} - leaders[5].should == member_10 + members[5].should == member_10 end it 'should allow you to retrieve leaders without scores and ranks' do @@ -230,6 +244,17 @@ leaders[0].should == member_26 end + it 'should return a single member when calling member_at' do + rank_members_in_leaderboard(50) + @leaderboard.member_at(1)[:rank].should == 1 + @leaderboard.member_at(1)[:score].should == 50.0 + @leaderboard.member_at(26)[:rank].should == 26 + @leaderboard.member_at(50)[:rank].should == 50 + @leaderboard.member_at(51).should be_nil + @leaderboard.member_at(1, :with_member_data => true)[:member_data].should == {'member_name' => 'Leaderboard member 50'} + @leaderboard.member_at(1, :use_zero_index_for_rank => true)[:rank].should == 0 + end + it 'should return the correct information when calling around_me' do rank_members_in_leaderboard(Leaderboard::DEFAULT_PAGE_SIZE * 3 + 1) diff --git a/spec/reverse_leaderboard_spec.rb b/spec/reverse_leaderboard_spec.rb index 25d333b..eea9fd8 100644 --- a/spec/reverse_leaderboard_spec.rb +++ b/spec/reverse_leaderboard_spec.rb @@ -33,24 +33,38 @@ leaders[-1][:score].to_i.should be(25) end - it 'should allow you to retrieve leaders in a given score range' do + it 'should return the correct list when calling members' do + rank_members_in_leaderboard(25) + + @leaderboard.total_members.should be(25) + + members = @leaderboard.members(1) + + members.size.should be(25) + members[0][:member].should == 'member_1' + members[-2][:member].should == 'member_24' + members[-1][:member].should == 'member_25' + members[-1][:score].to_i.should be(25) + end + + it 'should allow you to retrieve members in a given score range' do rank_members_in_leaderboard(Leaderboard::DEFAULT_PAGE_SIZE) - leaders = @leaderboard.leaders_from_score_range(10, 15, {:with_scores => false, :with_rank => false}) + members = @leaderboard.members_from_score_range(10, 15, {:with_scores => false, :with_rank => false}) member_10 = {:member => 'member_10'} - leaders[0].should == member_10 + members[0].should == member_10 member_15 = {:member => 'member_15'} - leaders[5].should == member_15 + members[5].should == member_15 - leaders = @leaderboard.leaders_from_score_range(10, 15, {:with_scores => true, :with_rank => true, :with_member_data => true}) + members = @leaderboard.members_from_score_range(10, 15, {:with_scores => true, :with_rank => true, :with_member_data => true}) member_10 = {:member => 'member_10', :rank => 10, :score => 10.0, :member_data => {'member_name' => 'Leaderboard member 10'}} - leaders[0].should == member_10 + members[0].should == member_10 member_15 = {:member => 'member_15', :rank => 15, :score => 15.0, :member_data => {'member_name' => 'Leaderboard member 15'}} - leaders[5].should == member_15 + members[5].should == member_15 end it 'should allow you to retrieve leaders without scores and ranks' do @@ -101,6 +115,17 @@ leaders[0].should == member_1 end + it 'should return a single member when calling member_at' do + rank_members_in_leaderboard(50) + @leaderboard.member_at(1)[:rank].should == 1 + @leaderboard.member_at(1)[:score].should == 1.0 + @leaderboard.member_at(26)[:rank].should == 26 + @leaderboard.member_at(50)[:rank].should == 50 + @leaderboard.member_at(51).should be_nil + @leaderboard.member_at(1, :with_member_data => true)[:member_data].should == {'member_name' => 'Leaderboard member 1'} + @leaderboard.member_at(1, :use_zero_index_for_rank => true)[:rank].should == 0 + end + it 'should return the correct information when calling around_me' do rank_members_in_leaderboard(Leaderboard::DEFAULT_PAGE_SIZE * 3 + 1)