Permalink
Browse files

Merge branch 'version-3-proposal-store-member-data-in-a-single-hash' …

…into version-3
  • Loading branch information...
2 parents 78d3a4c + 3307a2b commit 520ed66532b1c4be52c3047b6b36d43c30ae790a David Czarnecki committed Nov 8, 2012
Showing with 52 additions and 46 deletions.
  1. +13 −9 README.markdown
  2. +13 −13 lib/leaderboard.rb
  3. +20 −18 spec/leaderboard_spec.rb
  4. +6 −6 spec/reverse_leaderboard_spec.rb
View
@@ -119,30 +119,34 @@ Get some information about your leaderboard:
=> 1
```
-The `rank_member` call will also accept an optional hash of member data that could
-be used to store other information about a given member in the leaderboard. This
-may be useful in situations where you are storing member IDs in the leaderboard and
-you want to be able to store a member name for display. Example:
+The `rank_member` call will also accept an optional string member data that could
+be used to store other information about a given member in the leaderboard. This
+may be useful in situations where you are storing member IDs in the leaderboard and
+you want to be able to store a member name for display. You could use JSON to
+encode a Hash of member data. Example:
```ruby
-highscore_lb.rank_member('84849292', 1, {'username' => 'member_name'})
+require 'json'
+highscore_lb.rank_member('84849292', 1, JSON.generate({'username' => 'member_name'})
```
You can retrieve, update and remove the optional member data using the
`member_data_for`, `update_member_data` and `remove_member_data` calls. Example:
```ruby
-highscore_lb.member_data_for('84849292')
+JSON.parse(highscore_lb.member_data_for('84849292'))
=> {"username"=>"member_name"}
-highscore_lb.update_member_data('84849292', {'last_updated' => Time.now, 'username' => 'updated_member_name'})
- => "OK"
-highscore_lb.member_data_for('84849292')
+highscore_lb.update_member_data('84849292', JSON.generate({'last_updated' => Time.now, 'username' => 'updated_member_name'}))
+ => "OK"
+JSON.parse(highscore_lb.member_data_for('84849292'))
=> {"username"=>"updated_member_name", "last_updated"=>"2012-06-09 09:11:06 -0400"}
highscore_lb.remove_member_data('84849292')
```
+If you delete the leaderboard, ALL of the member data is deleted as well.
+
Get some information about a specific member(s) in the leaderboard:
```ruby
View
@@ -103,7 +103,10 @@ def delete_leaderboard
#
# @param leaderboard_name [String] Name of the leaderboard.
def delete_leaderboard_named(leaderboard_name)
- @redis_connection.del(leaderboard_name)
+ @redis_connection.multi do |transaction|
+ transaction.del(leaderboard_name)
+ transaction.del(member_data_key(leaderboard_name))
+ end
end
# Rank a member in the leaderboard.
@@ -124,9 +127,7 @@ def rank_member(member, score, member_data = nil)
def rank_member_in(leaderboard_name, member, score, member_data)
@redis_connection.multi do |transaction|
transaction.zadd(leaderboard_name, score, member)
- if member_data
- transaction.hmset(member_data_key(leaderboard_name, member), *member_data.to_a.flatten)
- end
+ transaction.hset(member_data_key(leaderboard_name), member, member_data) if member_data
end
end
@@ -146,7 +147,7 @@ def member_data_for(member)
#
# @return Hash of optional member data.
def member_data_for_in(leaderboard_name, member)
- @redis_connection.hgetall(member_data_key(leaderboard_name, member))
+ @redis_connection.hget(member_data_key(leaderboard_name), member)
end
# Update the optional member data for a given member in the leaderboard.
@@ -163,7 +164,7 @@ def update_member_data(member, member_data)
# @param member [String] Member name.
# @param member_data [Hash] Optional member data.
def update_member_data_in(leaderboard_name, member, member_data)
- @redis_connection.hmset(member_data_key(leaderboard_name, member), *member_data.to_a.flatten)
+ @redis_connection.hset(member_data_key(leaderboard_name), member, member_data)
end
# Remove the optional member data for a given member in the leaderboard.
@@ -178,7 +179,7 @@ def remove_member_data(member)
# @param leaderboard_name [String] Name of the leaderboard.
# @param member [String] Member name.
def remove_member_data_in(leaderboard_name, member)
- @redis_connection.del(member_data_key(leaderboard_name, member))
+ @redis_connection.hdel(member_data_key(leaderboard_name), member)
end
# Rank an array of members in the leaderboard.
@@ -218,7 +219,7 @@ def remove_member(member)
def remove_member_from(leaderboard_name, member)
@redis_connection.multi do |transaction|
transaction.zrem(leaderboard_name, member)
- transaction.del(member_data_key(leaderboard_name, member))
+ transaction.del(member_data_key(leaderboard_name), member)
end
end
@@ -861,11 +862,10 @@ def intersect_leaderboards(destination, keys, options = {:aggregate => :sum})
# Key for retrieving optional member data.
#
# @param leaderboard_name [String] Name of the leaderboard.
- # @param member [String] Member name.
- #
- # @return a key in the form of +leaderboard_name:data:member+
- def member_data_key(leaderboard_name, member)
- "#{leaderboard_name}:member_data:#{member}"
+ #
+ # @return a key in the form of +leaderboard_name:member_data+
+ def member_data_key(leaderboard_name)
+ "#{leaderboard_name}:member_data"
end
# Validate and return the page size. Returns the +DEFAULT_PAGE_SIZE+ if the page size is less than 1.
View
@@ -40,8 +40,10 @@
rank_members_in_leaderboard
@redis_connection.exists('name').should be_true
+ @redis_connection.exists('name:member_data').should be_true
@leaderboard.delete_leaderboard
@redis_connection.exists('name').should be_false
+ @redis_connection.exists('name:member_data').should be_false
end
it 'should allow you to pass in an existing redis connection in the initializer' do
@@ -170,11 +172,11 @@
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'}}
- members[0].should eql(member_15)
+ member_15 = {:member => 'member_15', :rank => 11, :score => 15.0, :member_data => {:member_name => 'Leaderboard member 15'}.to_s}
+ members[0].should == member_15
- member_10 = {:member => 'member_10', :rank => 16, :score => 10.0, :member_data => {'member_name' => 'Leaderboard member 10'}}
- members[5].should eql(member_10)
+ member_10 = {:member => 'member_10', :rank => 16, :score => 10.0, :member_data => {:member_name => 'Leaderboard member 10'}.to_s}
+ members[5].should == member_10
end
it 'should allow you to retrieve leaders without scores and ranks' do
@@ -196,34 +198,34 @@
@leaderboard.total_members.should be(Leaderboard::DEFAULT_PAGE_SIZE)
leaders = @leaderboard.leaders(1, {:with_scores => false, :with_rank => false, :with_member_data => true})
- member_25 = {:member => 'member_25', :member_data => { "member_name" => "Leaderboard member 25" }}
- leaders[0].should eql(member_25)
-
- member_1 = {:member => 'member_1', :member_data => { "member_name" => "Leaderboard member 1" }}
- leaders[24].should eql(member_1)
+ member_25 = {:member => 'member_25', :member_data => { :member_name => "Leaderboard member 25" }.to_s }
+ leaders[0].should == member_25
+
+ member_1 = {:member => 'member_1', :member_data => { :member_name => "Leaderboard member 1" }.to_s }
+ leaders[24].should == member_1
end
it 'should allow you to retrieve optional member data' do
@leaderboard.rank_member('member_id', 1, {'username' => 'member_name', 'other_data_key' => 'other_data_value'})
- @leaderboard.member_data_for('unknown_member').should eql({})
- @leaderboard.member_data_for('member_id').should eql({'username' => 'member_name', 'other_data_key' => 'other_data_value'})
+ @leaderboard.member_data_for('unknown_member').should be_nil
+ @leaderboard.member_data_for('member_id').should == {'username' => 'member_name', 'other_data_key' => 'other_data_value'}.to_s
end
it 'should allow you to update optional member data' do
@leaderboard.rank_member('member_id', 1, {'username' => 'member_name'})
- @leaderboard.member_data_for('member_id').should eql({'username' => 'member_name'})
- @leaderboard.update_member_data('member_id', {'other_data_key' => 'other_data_value'})
- @leaderboard.member_data_for('member_id').should eql({'username' => 'member_name', 'other_data_key' => 'other_data_value'})
+ @leaderboard.member_data_for('member_id').should == {'username' => 'member_name'}.to_s
+ @leaderboard.update_member_data('member_id', {'username' => 'member_name', 'other_data_key' => 'other_data_value'})
+ @leaderboard.member_data_for('member_id').should == {'username' => 'member_name', 'other_data_key' => 'other_data_value'}.to_s
end
it 'should allow you to remove optional member data' do
@leaderboard.rank_member('member_id', 1, {'username' => 'member_name'})
- @leaderboard.member_data_for('member_id').should eql({'username' => 'member_name'})
+ @leaderboard.member_data_for('member_id').should == {'username' => 'member_name'}.to_s
@leaderboard.remove_member_data('member_id')
- @leaderboard.member_data_for('member_id').should eql({})
+ @leaderboard.member_data_for('member_id').should be_nil
end
it 'should allow you to call leaders with various options that respect the defaults for the options not passed in' do
@@ -268,8 +270,8 @@
@leaderboard.member_at(26)[:rank].should eql(26)
@leaderboard.member_at(50)[:rank].should eql(50)
@leaderboard.member_at(51).should be_nil
- @leaderboard.member_at(1, :with_member_data => true)[:member_data].should eql({'member_name' => 'Leaderboard member 50'})
- @leaderboard.member_at(1, :use_zero_index_for_rank => true)[:rank].should eql(0)
+ @leaderboard.member_at(1, :with_member_data => true)[:member_data].should == {:member_name => 'Leaderboard member 50'}.to_s
+ @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
@@ -60,11 +60,11 @@
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'}}
- members[0].should eql(member_10)
+ member_10 = {:member => 'member_10', :rank => 10, :score => 10.0, :member_data => {:member_name => 'Leaderboard member 10'}.to_s}
+ members[0].should == member_10
- member_15 = {:member => 'member_15', :rank => 15, :score => 15.0, :member_data => {'member_name' => 'Leaderboard member 15'}}
- members[5].should eql(member_15)
+ member_15 = {:member => 'member_15', :rank => 15, :score => 15.0, :member_data => {:member_name => 'Leaderboard member 15'}.to_s}
+ members[5].should == member_15
end
it 'should allow you to retrieve leaders without scores and ranks' do
@@ -122,8 +122,8 @@
@leaderboard.member_at(26)[:rank].should eql(26)
@leaderboard.member_at(50)[:rank].should eql(50)
@leaderboard.member_at(51).should be_nil
- @leaderboard.member_at(1, :with_member_data => true)[:member_data].should eql({'member_name' => 'Leaderboard member 1'})
- @leaderboard.member_at(1, :use_zero_index_for_rank => true)[:rank].should eql(0)
+ @leaderboard.member_at(1, :with_member_data => true)[:member_data].should == {:member_name => 'Leaderboard member 1'}.to_s
+ @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

0 comments on commit 520ed66

Please sign in to comment.