leaderboard 1.0.5 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.rvmrc +2 -1
- data/CHANGELOG.markdown +14 -0
- data/Gemfile +1 -1
- data/README.rdoc +103 -78
- data/Rakefile +2 -2
- data/VERSION +1 -1
- data/leaderboard.gemspec +9 -10
- data/lib/leaderboard.rb +108 -65
- data/test/test_leaderboard.rb +128 -53
- metadata +51 -84
data/.rvmrc
CHANGED
@@ -1 +1,2 @@
|
|
1
|
-
rvm 1.8.7
|
1
|
+
rvm --create 1.8.7@leaderboard_gem
|
2
|
+
rvm --create 1.9.2@leaderboard_gem
|
data/CHANGELOG.markdown
CHANGED
@@ -1,3 +1,17 @@
|
|
1
|
+
# leaderboard 2.0.0 (2011-08-05)
|
2
|
+
|
3
|
+
* Change `add_member` to `rank_member` - https://github.com/agoragames/leaderboard/issues/3
|
4
|
+
* Added `delete_leaderboard` and `delete_leaderboard_named` - https://github.com/agoragames/leaderboard/issues/2
|
5
|
+
* Ability to pass in an existing Redis connection in initializer - https://github.com/agoragames/leaderboard/issues/1
|
6
|
+
* Added transaction support for `score_and_rank_for`, `leaders`, `around_me` and `ranked_in_list`
|
7
|
+
* Updated initializer to take a leaderboard name, `options` hash and `redis_options` hash
|
8
|
+
* Simplified `leaders`, `around_me` and `ranked_in_list` to use an `options` hash with defaults for the previously individual parameters
|
9
|
+
|
10
|
+
# leaderboard 1.0.6 (unreleased)
|
11
|
+
|
12
|
+
* Added `disconnect` method
|
13
|
+
* Check for invalid page size when changing
|
14
|
+
|
1
15
|
# leaderboard 1.0.5 (2011-05-04)
|
2
16
|
|
3
17
|
* Updated Rakefile to run tests under ruby 1.8.7 and ruby 1.9.2
|
data/Gemfile
CHANGED
data/README.rdoc
CHANGED
@@ -8,7 +8,7 @@ Builds off ideas proposed in http://blog.agoragames.com/2011/01/01/creating-high
|
|
8
8
|
|
9
9
|
Install the gem:
|
10
10
|
|
11
|
-
|
11
|
+
gem "leaderboard", "~> 2.0.0"
|
12
12
|
|
13
13
|
Make sure your redis server is running! Redis configuration is outside the scope of this README, but
|
14
14
|
check out the Redis documentation, http://redis.io/documentation.
|
@@ -21,138 +21,163 @@ The gem has been built and tested under Ruby 1.8.7 and Ruby 1.9.2
|
|
21
21
|
|
22
22
|
Create a new leaderboard or attach to an existing leaderboard named 'highscores':
|
23
23
|
|
24
|
-
ruby-1.
|
25
|
-
=> #<Leaderboard:
|
26
|
-
|
27
|
-
If you need to pass in options for Redis, you can do this
|
24
|
+
ruby-1.9.2-p180 :002 > highscore_lb = Leaderboard.new('highscores')
|
25
|
+
=> #<Leaderboard:0x0000010307b530 @leaderboard_name="highscores", @page_size=25, @redis_connection=#<Redis client v2.2.2 connected to redis://localhost:6379/0 (Redis v2.2.5)>>
|
26
|
+
|
27
|
+
If you need to pass in options for Redis, you can do this in the initializer:
|
28
|
+
|
29
|
+
ruby-1.9.2-p180 :007 > redis_options = {:host => 'localhost', :port => 6379, :db => 1}
|
30
|
+
=> {:host=>"localhost", :port=>6379, :db=>1}
|
31
|
+
ruby-1.9.2-p180 :008 > highscore_lb = Leaderboard.new('highscores', Leaderboard::DEFAULT_OPTIONS, redis_options)
|
32
|
+
=> #<Leaderboard:0x00000103095200 @leaderboard_name="highscores", @page_size=25, @redis_connection=#<Redis client v2.2.2 connected to redis://localhost:6379/1 (Redis v2.2.5)>>
|
28
33
|
|
29
|
-
|
30
|
-
highscore_lb = Leaderboard.new('highscores', redis_options[:host], redis_options[:port], Leaderboard::DEFAULT_PAGE_SIZE, redis_options))
|
34
|
+
You can pass in an existing connection to Redis using :redis_connection in the Redis options hash:
|
31
35
|
|
36
|
+
ruby-1.9.2-p180 :009 > redis = Redis.new
|
37
|
+
=> #<Redis client v2.2.2 connected to redis://127.0.0.1:6379/0 (Redis v2.2.5)>
|
38
|
+
ruby-1.9.2-p180 :010 > redis_options = {:redis_connection => redis}
|
39
|
+
=> {:redis_connection=>#<Redis client v2.2.2 connected to redis://127.0.0.1:6379/0 (Redis v2.2.5)>}
|
40
|
+
ruby-1.9.2-p180 :011 > highscore_lb = Leaderboard.new('highscores', Leaderboard::DEFAULT_OPTIONS, redis_options)
|
41
|
+
=> #<Leaderboard:0x000001028791e8 @leaderboard_name="highscores", @page_size=25, @redis_connection=#<Redis client v2.2.2 connected to redis://127.0.0.1:6379/0 (Redis v2.2.5)>>
|
42
|
+
|
32
43
|
You can set the page size to something other than the default page size (25):
|
33
44
|
|
34
|
-
ruby-1.
|
45
|
+
ruby-1.9.2-p180 :012 > highscore_lb.page_size = 5
|
35
46
|
=> 5
|
36
|
-
ruby-1.
|
37
|
-
=> #<Leaderboard:
|
47
|
+
ruby-1.9.2-p180 :013 > highscore_lb
|
48
|
+
=> #<Leaderboard:0x000001028791e8 @leaderboard_name="highscores", @page_size=5, @redis_connection=#<Redis client v2.2.2 connected to redis://127.0.0.1:6379/0 (Redis v2.2.5)>>
|
38
49
|
|
39
|
-
Add members to your leaderboard:
|
50
|
+
Add members to your leaderboard using rank_member:
|
40
51
|
|
41
|
-
ruby-1.
|
42
|
-
ruby-1.
|
43
|
-
ruby-1.
|
52
|
+
ruby-1.9.2-p180 :014 > 1.upto(10) do |index|
|
53
|
+
ruby-1.9.2-p180 :015 > highscore_lb.rank_member("member_#{index}", index)
|
54
|
+
ruby-1.9.2-p180 :016?> end
|
44
55
|
=> 1
|
45
|
-
|
56
|
+
|
57
|
+
You can call rank_member with the same member and the leaderboard will be updated automatically.
|
58
|
+
|
46
59
|
Get some information about your leaderboard:
|
47
60
|
|
48
|
-
ruby-1.
|
61
|
+
ruby-1.9.2-p180 :020 > highscore_lb.total_members
|
49
62
|
=> 10
|
50
|
-
ruby-1.
|
63
|
+
ruby-1.9.2-p180 :021 > highscore_lb.total_pages
|
51
64
|
=> 1
|
52
65
|
|
53
66
|
Get some information about a specific member(s) in the leaderboard:
|
54
67
|
|
55
|
-
ruby-1.
|
68
|
+
ruby-1.9.2-p180 :022 > highscore_lb.score_for('member_4')
|
56
69
|
=> 4.0
|
57
|
-
ruby-1.
|
70
|
+
ruby-1.9.2-p180 :023 > highscore_lb.rank_for('member_4')
|
58
71
|
=> 7
|
59
|
-
ruby-1.
|
72
|
+
ruby-1.9.2-p180 :024 > highscore_lb.rank_for('member_10')
|
60
73
|
=> 1
|
61
74
|
|
62
75
|
Get page 1 in the leaderboard:
|
63
76
|
|
64
|
-
ruby-1.
|
65
|
-
|
77
|
+
ruby-1.9.2-p180 :025 > highscore_lb.leaders(1)
|
78
|
+
=> [{:member=>"member_10", :rank=>1, :score=>10.0}, {:member=>"member_9", :rank=>2, :score=>9.0}, {:member=>"member_8", :rank=>3, :score=>8.0}, {:member=>"member_7", :rank=>4, :score=>7.0}, {:member=>"member_6", :rank=>5, :score=>6.0}, {:member=>"member_5", :rank=>6, :score=>5.0}, {:member=>"member_4", :rank=>7, :score=>4.0}, {:member=>"member_3", :rank=>8, :score=>3.0}, {:member=>"member_2", :rank=>9, :score=>2.0}, {:member=>"member_1", :rank=>10, :score=>1.0}]
|
66
79
|
|
80
|
+
You can pass various options to the calls `leaders`, `around_me` and `ranked_in_list`. Valid options are :with_scores, :with_rank, :use_zero_index_for_rank and :page_size.
|
81
|
+
Below is an example of retrieving the first page in the leaderboard without ranks:
|
82
|
+
|
83
|
+
ruby-1.9.2-p180 :026 > highscore_lb.leaders(1, :with_scores => true, :with_rank => false, :use_zero_index_for_rank => false)
|
84
|
+
=> [{:member=>"member_10", :score=>9.0}, {:member=>"member_9", :score=>7.0}, {:member=>"member_8", :score=>5.0}, {:member=>"member_7", :score=>3.0}, {:member=>"member_6", :score=>1.0}, {:member=>"member_5", :score=>0.0}, {:member=>"member_4", :score=>0.0}, {:member=>"member_3", :score=>0.0}, {:member=>"member_2", :score=>0.0}, {:member=>"member_1", :score=>0.0}]
|
85
|
+
|
86
|
+
Below is an example of retrieving the first page in the leaderboard without scores or ranks:
|
87
|
+
|
88
|
+
ruby-1.9.2-p180 :028 > highscore_lb.leaders(1, :with_scores => false, :with_rank => false)
|
89
|
+
=> [{: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"}]
|
90
|
+
|
67
91
|
Add more members to your leaderboard:
|
68
92
|
|
69
|
-
ruby-1.
|
70
|
-
ruby-1.
|
71
|
-
ruby-1.
|
93
|
+
ruby-1.9.2-p180 :029 > 50.upto(95) do |index|
|
94
|
+
ruby-1.9.2-p180 :030 > highscore_lb.rank_member("member_#{index}", index)
|
95
|
+
ruby-1.9.2-p180 :031?> end
|
72
96
|
=> 50
|
73
|
-
ruby-1.
|
97
|
+
ruby-1.9.2-p180 :032 > highscore_lb.total_pages
|
74
98
|
=> 3
|
75
99
|
|
76
100
|
Get an "Around Me" leaderboard for a member:
|
77
101
|
|
78
|
-
ruby-1.
|
79
|
-
|
102
|
+
ruby-1.9.2-p180 :033 > highscore_lb.around_me('member_53')
|
103
|
+
=> [{:member=>"member_65", :rank=>31, :score=>65.0}, {:member=>"member_64", :rank=>32, :score=>64.0}, {:member=>"member_63", :rank=>33, :score=>63.0}, {:member=>"member_62", :rank=>34, :score=>62.0}, {:member=>"member_61", :rank=>35, :score=>61.0}, {:member=>"member_60", :rank=>36, :score=>60.0}, {:member=>"member_59", :rank=>37, :score=>59.0}, {:member=>"member_58", :rank=>38, :score=>58.0}, {:member=>"member_57", :rank=>39, :score=>57.0}, {:member=>"member_56", :rank=>40, :score=>56.0}, {:member=>"member_55", :rank=>41, :score=>55.0}, {:member=>"member_54", :rank=>42, :score=>54.0}, {:member=>"member_53", :rank=>43, :score=>53.0}, {:member=>"member_52", :rank=>44, :score=>52.0}, {:member=>"member_51", :rank=>45, :score=>51.0}, {:member=>"member_50", :rank=>46, :score=>50.0}, {: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}, {:member=>"member_3", :rank=>54, :score=>3.0}, {:member=>"member_2", :rank=>55, :score=>2.0}]
|
80
104
|
|
81
105
|
Get rank and score for an arbitrary list of members (e.g. friends):
|
82
106
|
|
83
|
-
ruby-1.
|
84
|
-
=> [{:
|
85
|
-
|
107
|
+
ruby-1.9.2-p180 :034 > highscore_lb.ranked_in_list(['member_1', 'member_62', 'member_67'])
|
108
|
+
=> [{:member=>"member_1", :rank=>56, :score=>1.0}, {:member=>"member_62", :rank=>34, :score=>62.0}, {:member=>"member_67", :rank=>29, :score=>67.0}]
|
109
|
+
|
86
110
|
=== Other useful methods
|
87
111
|
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
112
|
+
delete_leaderboard: Delete the current leaderboard
|
113
|
+
remove_member(member): Remove a member from the leaderboard
|
114
|
+
total_members: Total # of members in the leaderboard
|
115
|
+
total_pages: Total # of pages in the leaderboard given the leaderboard's page_size
|
116
|
+
total_members_in_score_range(min_score, max_score): Count the number of members within a score range in the leaderboard
|
117
|
+
change_score_for(member, delta): Change the score for a member by some amount delta (delta could be positive or negative)
|
118
|
+
rank_for(member): Retrieve the rank for a given member in the leaderboard
|
119
|
+
score_for(member): Retrieve the score for a given member in the leaderboard
|
120
|
+
check_member?(member): Check to see whether member is in the leaderboard
|
121
|
+
score_and_rank_for(member): Retrieve the score and rank for a member in a single call
|
122
|
+
remove_members_in_score_range(min_score, max_score): Remove members from the leaderboard within a score range
|
123
|
+
merge_leaderboards(destination, keys, options = {:aggregate => :min}): Merge leaderboards given by keys with this leaderboard into destination
|
124
|
+
intersect_leaderboards(destination, keys, options = {:aggregate => :min}): Intersect leaderboards given by keys with this leaderboard into destination
|
125
|
+
|
126
|
+
Check the online documentation for more detail, http://rubydoc.info/gems/leaderboard/
|
96
127
|
|
97
128
|
== Performance Metrics
|
98
129
|
|
99
130
|
10 million sequential scores insert:
|
100
131
|
|
101
|
-
ruby-1.
|
102
|
-
|
103
|
-
ruby-1.
|
104
|
-
ruby-1.
|
105
|
-
ruby-1.
|
106
|
-
|
132
|
+
ruby-1.9.2-p180 :003 > highscore_lb = Leaderboard.new('highscores')
|
133
|
+
=> #<Leaderboard:0x0000010205fc50 @leaderboard_name="highscores", @page_size=25, @redis_connection=#<Redis client v2.2.2 connected to redis://localhost:6379/0 (Redis v2.2.5)>>
|
134
|
+
ruby-1.9.2-p180 :004 > insert_time = Benchmark.measure do
|
135
|
+
ruby-1.9.2-p180 :005 > 1.upto(10000000) do |index|
|
136
|
+
ruby-1.9.2-p180 :006 > highscore_lb.rank_member("member_#{index}", index)
|
137
|
+
ruby-1.9.2-p180 :007?> end
|
138
|
+
ruby-1.9.2-p180 :008?> end
|
139
|
+
=> 323.070000 148.560000 471.630000 (942.068307)
|
107
140
|
|
108
141
|
Average time to request an arbitrary page from the leaderboard:
|
109
142
|
|
110
|
-
ruby-1.
|
143
|
+
ruby-1.9.2-p180 :009 > requests_to_make = 50000
|
111
144
|
=> 50000
|
112
|
-
ruby-1.
|
145
|
+
ruby-1.9.2-p180 :010 > lb_request_time = 0
|
113
146
|
=> 0
|
114
|
-
ruby-1.
|
115
|
-
ruby-1.
|
116
|
-
ruby-1.
|
117
|
-
ruby-1.
|
118
|
-
ruby-1.
|
147
|
+
ruby-1.9.2-p180 :011 > 1.upto(requests_to_make) do
|
148
|
+
ruby-1.9.2-p180 :012 > lb_request_time += Benchmark.measure do
|
149
|
+
ruby-1.9.2-p180 :013 > highscore_lb.leaders(rand(highscore_lb.total_pages))
|
150
|
+
ruby-1.9.2-p180 :014?> end.total
|
151
|
+
ruby-1.9.2-p180 :015?> end
|
119
152
|
=> 1
|
120
|
-
ruby-1.
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
153
|
+
ruby-1.9.2-p180 :016 > p lb_request_time / requests_to_make
|
154
|
+
0.001513999999999998
|
155
|
+
=> 0.001513999999999998
|
156
|
+
|
125
157
|
10 million random scores insert:
|
126
158
|
|
127
|
-
ruby-1.
|
128
|
-
ruby-1.
|
129
|
-
ruby-1.
|
130
|
-
ruby-1.
|
131
|
-
ruby-1.
|
132
|
-
=>
|
159
|
+
ruby-1.9.2-p180 :018 > insert_time = Benchmark.measure do
|
160
|
+
ruby-1.9.2-p180 :019 > 1.upto(10000000) do |index|
|
161
|
+
ruby-1.9.2-p180 :020 > highscore_lb.rank_member("member_#{index}", rand(50000000))
|
162
|
+
ruby-1.9.2-p180 :021?> end
|
163
|
+
ruby-1.9.2-p180 :022?> end
|
164
|
+
=> 338.480000 155.200000 493.680000 (2188.702475)
|
133
165
|
|
134
166
|
Average time to request an arbitrary page from the leaderboard:
|
135
167
|
|
136
|
-
ruby-1.
|
137
|
-
|
138
|
-
ruby-1.
|
139
|
-
|
140
|
-
ruby-1.
|
141
|
-
ruby-1.8.7-p302 > lb_request_time += Benchmark.measure do
|
142
|
-
ruby-1.8.7-p302 > highscore_lb.leaders(rand(highscore_lb.total_pages))
|
143
|
-
ruby-1.8.7-p302 ?> end.total
|
144
|
-
ruby-1.8.7-p302 ?> end
|
168
|
+
ruby-1.9.2-p180 :007 > 1.upto(requests_to_make) do
|
169
|
+
ruby-1.9.2-p180 :008 > lb_request_time += Benchmark.measure do
|
170
|
+
ruby-1.9.2-p180 :009 > highscore_lb.leaders(rand(highscore_lb.total_pages))
|
171
|
+
ruby-1.9.2-p180 :010?> end.total
|
172
|
+
ruby-1.9.2-p180 :011?> end
|
145
173
|
=> 1
|
146
|
-
ruby-1.
|
147
|
-
|
148
|
-
|
149
|
-
=> nil
|
174
|
+
ruby-1.9.2-p180 :012 > p lb_request_time / requests_to_make
|
175
|
+
0.0014615999999999531
|
176
|
+
=> 0.0014615999999999531
|
150
177
|
|
151
178
|
== Future Ideas
|
152
179
|
|
153
180
|
* Bulk insert
|
154
|
-
* Atomicity for various operations?
|
155
|
-
* Is nil? OK to return if Redis returns no data or should it be []?
|
156
181
|
|
157
182
|
== Contributing to leaderboard
|
158
183
|
|
data/Rakefile
CHANGED
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
|
1
|
+
2.0.0
|
data/leaderboard.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{leaderboard}
|
8
|
-
s.version = "
|
8
|
+
s.version = "2.0.0"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
-
s.authors = [
|
12
|
-
s.date = %q{2011-
|
11
|
+
s.authors = [%q{David Czarnecki}]
|
12
|
+
s.date = %q{2011-08-17}
|
13
13
|
s.description = %q{Leaderboards backed by Redis in Ruby}
|
14
14
|
s.email = %q{dczarnecki@agoragames.com}
|
15
15
|
s.extra_rdoc_files = [
|
@@ -33,9 +33,9 @@ Gem::Specification.new do |s|
|
|
33
33
|
"test/test_leaderboard.rb"
|
34
34
|
]
|
35
35
|
s.homepage = %q{http://github.com/agoragames/leaderboard}
|
36
|
-
s.licenses = [
|
37
|
-
s.require_paths = [
|
38
|
-
s.rubygems_version = %q{1.
|
36
|
+
s.licenses = [%q{MIT}]
|
37
|
+
s.require_paths = [%q{lib}]
|
38
|
+
s.rubygems_version = %q{1.8.6}
|
39
39
|
s.summary = %q{Leaderboards backed by Redis in Ruby}
|
40
40
|
s.test_files = [
|
41
41
|
"test/helper.rb",
|
@@ -43,22 +43,21 @@ Gem::Specification.new do |s|
|
|
43
43
|
]
|
44
44
|
|
45
45
|
if s.respond_to? :specification_version then
|
46
|
-
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
47
46
|
s.specification_version = 3
|
48
47
|
|
49
48
|
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
50
|
-
s.add_runtime_dependency(%q<redis>, ["~> 2.
|
49
|
+
s.add_runtime_dependency(%q<redis>, ["~> 2.2.0"])
|
51
50
|
s.add_development_dependency(%q<bundler>, ["~> 1.0.0"])
|
52
51
|
s.add_development_dependency(%q<jeweler>, ["~> 1.5.2"])
|
53
52
|
s.add_development_dependency(%q<rcov>, [">= 0"])
|
54
53
|
else
|
55
|
-
s.add_dependency(%q<redis>, ["~> 2.
|
54
|
+
s.add_dependency(%q<redis>, ["~> 2.2.0"])
|
56
55
|
s.add_dependency(%q<bundler>, ["~> 1.0.0"])
|
57
56
|
s.add_dependency(%q<jeweler>, ["~> 1.5.2"])
|
58
57
|
s.add_dependency(%q<rcov>, [">= 0"])
|
59
58
|
end
|
60
59
|
else
|
61
|
-
s.add_dependency(%q<redis>, ["~> 2.
|
60
|
+
s.add_dependency(%q<redis>, ["~> 2.2.0"])
|
62
61
|
s.add_dependency(%q<bundler>, ["~> 1.0.0"])
|
63
62
|
s.add_dependency(%q<jeweler>, ["~> 1.5.2"])
|
64
63
|
s.add_dependency(%q<rcov>, [">= 0"])
|
data/lib/leaderboard.rb
CHANGED
@@ -1,42 +1,69 @@
|
|
1
1
|
require 'redis'
|
2
2
|
|
3
3
|
class Leaderboard
|
4
|
-
VERSION = '
|
4
|
+
VERSION = '2.0.0'.freeze
|
5
5
|
|
6
6
|
DEFAULT_PAGE_SIZE = 25
|
7
|
+
DEFAULT_OPTIONS = {
|
8
|
+
:page_size => DEFAULT_PAGE_SIZE
|
9
|
+
}
|
10
|
+
|
7
11
|
DEFAULT_REDIS_HOST = 'localhost'
|
8
|
-
DEFAULT_REDIS_PORT = 6379
|
12
|
+
DEFAULT_REDIS_PORT = 6379
|
13
|
+
DEFAULT_REDIS_OPTIONS = {
|
14
|
+
:host => DEFAULT_REDIS_HOST,
|
15
|
+
:port => DEFAULT_REDIS_PORT
|
16
|
+
}
|
17
|
+
|
18
|
+
DEFAULT_LEADERBOARD_REQUEST_OPTIONS = {
|
19
|
+
:with_scores => true,
|
20
|
+
:with_rank => true,
|
21
|
+
:use_zero_index_for_rank => false,
|
22
|
+
:page_size => nil
|
23
|
+
}
|
9
24
|
|
10
|
-
attr_reader :host
|
11
|
-
attr_reader :port
|
12
25
|
attr_reader :leaderboard_name
|
13
26
|
attr_accessor :page_size
|
14
27
|
|
15
|
-
def initialize(leaderboard_name,
|
28
|
+
def initialize(leaderboard_name, options = DEFAULT_OPTIONS, redis_options = DEFAULT_REDIS_OPTIONS)
|
16
29
|
@leaderboard_name = leaderboard_name
|
17
|
-
@host = host
|
18
|
-
@port = port
|
19
30
|
|
20
|
-
|
21
|
-
|
31
|
+
@page_size = options[:page_size]
|
32
|
+
if @page_size < 1
|
33
|
+
@page_size = DEFAULT_PAGE_SIZE
|
22
34
|
end
|
23
35
|
|
36
|
+
@redis_connection = redis_options[:redis_connection]
|
37
|
+
unless @redis_connection.nil?
|
38
|
+
redis_options.delete(:redis_connection)
|
39
|
+
end
|
40
|
+
|
41
|
+
@redis_connection = Redis.new(redis_options) if @redis_connection.nil?
|
42
|
+
end
|
43
|
+
|
44
|
+
def page_size=(page_size)
|
45
|
+
page_size = DEFAULT_PAGE_SIZE if page_size < 1
|
46
|
+
|
24
47
|
@page_size = page_size
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
48
|
+
end
|
49
|
+
|
50
|
+
def disconnect
|
51
|
+
@redis_connection.client.disconnect
|
52
|
+
end
|
53
|
+
|
54
|
+
def delete_leaderboard
|
55
|
+
delete_leaderboard_named(@leaderboard_name)
|
56
|
+
end
|
57
|
+
|
58
|
+
def delete_leaderboard_named(leaderboard_name)
|
59
|
+
@redis_connection.del(leaderboard_name)
|
33
60
|
end
|
34
61
|
|
35
|
-
def
|
36
|
-
|
62
|
+
def rank_member(member, score)
|
63
|
+
rank_member_in(@leaderboard_name, member, score)
|
37
64
|
end
|
38
65
|
|
39
|
-
def
|
66
|
+
def rank_member_in(leaderboard_name, member, score)
|
40
67
|
@redis_connection.zadd(leaderboard_name, score, member)
|
41
68
|
end
|
42
69
|
|
@@ -114,7 +141,17 @@ class Leaderboard
|
|
114
141
|
end
|
115
142
|
|
116
143
|
def score_and_rank_for_in(leaderboard_name, member, use_zero_index_for_rank = false)
|
117
|
-
|
144
|
+
responses = @redis_connection.multi do |transaction|
|
145
|
+
transaction.zscore(leaderboard_name, member)
|
146
|
+
transaction.zrevrank(leaderboard_name, member)
|
147
|
+
end
|
148
|
+
|
149
|
+
responses[0] = responses[0].to_f
|
150
|
+
if !use_zero_index_for_rank
|
151
|
+
responses[1] = responses[1] + 1 rescue nil
|
152
|
+
end
|
153
|
+
|
154
|
+
{:member => member, :score => responses[0], :rank => responses[1]}
|
118
155
|
end
|
119
156
|
|
120
157
|
def remove_members_in_score_range(min_score, max_score)
|
@@ -125,17 +162,17 @@ class Leaderboard
|
|
125
162
|
@redis_connection.zremrangebyscore(leaderboard_name, min_score, max_score)
|
126
163
|
end
|
127
164
|
|
128
|
-
def leaders(current_page,
|
129
|
-
leaders_in(@leaderboard_name, current_page,
|
165
|
+
def leaders(current_page, options = DEFAULT_LEADERBOARD_REQUEST_OPTIONS)
|
166
|
+
leaders_in(@leaderboard_name, current_page, options)
|
130
167
|
end
|
131
168
|
|
132
|
-
def leaders_in(leaderboard_name, current_page,
|
169
|
+
def leaders_in(leaderboard_name, current_page, options = DEFAULT_LEADERBOARD_REQUEST_OPTIONS)
|
133
170
|
if current_page < 1
|
134
171
|
current_page = 1
|
135
172
|
end
|
173
|
+
|
174
|
+
page_size = validate_page_size(options[:page_size]) || @page_size
|
136
175
|
|
137
|
-
page_size ||= @page_size
|
138
|
-
|
139
176
|
if current_page > total_pages_in(leaderboard_name, page_size)
|
140
177
|
current_page = total_pages_in(leaderboard_name, page_size)
|
141
178
|
end
|
@@ -148,23 +185,23 @@ class Leaderboard
|
|
148
185
|
end
|
149
186
|
|
150
187
|
ending_offset = (starting_offset + page_size) - 1
|
151
|
-
|
152
|
-
raw_leader_data = @redis_connection.zrevrange(leaderboard_name, starting_offset, ending_offset, :with_scores =>
|
188
|
+
|
189
|
+
raw_leader_data = @redis_connection.zrevrange(leaderboard_name, starting_offset, ending_offset, :with_scores => false)
|
153
190
|
if raw_leader_data
|
154
|
-
|
191
|
+
return ranked_in_list_in(leaderboard_name, raw_leader_data, options)
|
155
192
|
else
|
156
|
-
return
|
193
|
+
return []
|
157
194
|
end
|
158
195
|
end
|
159
196
|
|
160
|
-
def around_me(member,
|
161
|
-
around_me_in(@leaderboard_name, member,
|
197
|
+
def around_me(member, options = DEFAULT_LEADERBOARD_REQUEST_OPTIONS)
|
198
|
+
around_me_in(@leaderboard_name, member, options)
|
162
199
|
end
|
163
200
|
|
164
|
-
def around_me_in(leaderboard_name, member,
|
201
|
+
def around_me_in(leaderboard_name, member, options = DEFAULT_LEADERBOARD_REQUEST_OPTIONS)
|
165
202
|
reverse_rank_for_member = @redis_connection.zrevrank(leaderboard_name, member)
|
166
203
|
|
167
|
-
page_size
|
204
|
+
page_size = validate_page_size(options[:page_size]) || @page_size
|
168
205
|
|
169
206
|
starting_offset = reverse_rank_for_member - (page_size / 2)
|
170
207
|
if starting_offset < 0
|
@@ -173,26 +210,50 @@ class Leaderboard
|
|
173
210
|
|
174
211
|
ending_offset = (starting_offset + page_size) - 1
|
175
212
|
|
176
|
-
raw_leader_data = @redis_connection.zrevrange(leaderboard_name, starting_offset, ending_offset, :with_scores =>
|
213
|
+
raw_leader_data = @redis_connection.zrevrange(leaderboard_name, starting_offset, ending_offset, :with_scores => false)
|
177
214
|
if raw_leader_data
|
178
|
-
|
215
|
+
return ranked_in_list_in(leaderboard_name, raw_leader_data, options)
|
179
216
|
else
|
180
|
-
return
|
217
|
+
return []
|
181
218
|
end
|
182
219
|
end
|
183
220
|
|
184
|
-
def ranked_in_list(members,
|
185
|
-
ranked_in_list_in(@leaderboard_name, members,
|
221
|
+
def ranked_in_list(members, options = DEFAULT_LEADERBOARD_REQUEST_OPTIONS)
|
222
|
+
ranked_in_list_in(@leaderboard_name, members, options)
|
186
223
|
end
|
187
224
|
|
188
|
-
def ranked_in_list_in(leaderboard_name, members,
|
225
|
+
def ranked_in_list_in(leaderboard_name, members, options = DEFAULT_LEADERBOARD_REQUEST_OPTIONS)
|
189
226
|
ranks_for_members = []
|
190
227
|
|
191
|
-
|
228
|
+
responses = @redis_connection.multi do |transaction|
|
229
|
+
members.each do |member|
|
230
|
+
transaction.zrevrank(leaderboard_name, member) if options[:with_rank]
|
231
|
+
transaction.zscore(leaderboard_name, member) if options[:with_scores]
|
232
|
+
end
|
233
|
+
end
|
234
|
+
|
235
|
+
members.each_with_index do |member, index|
|
192
236
|
data = {}
|
193
237
|
data[:member] = member
|
194
|
-
|
195
|
-
|
238
|
+
if options[:with_scores]
|
239
|
+
if options[:with_rank]
|
240
|
+
if options[:use_zero_index_for_rank]
|
241
|
+
data[:rank] = responses[index * 2]
|
242
|
+
else
|
243
|
+
data[:rank] = responses[index * 2] + 1
|
244
|
+
end
|
245
|
+
end
|
246
|
+
|
247
|
+
data[:score] = responses[index * 2 + 1].to_f
|
248
|
+
else
|
249
|
+
if options[:with_rank]
|
250
|
+
if options[:use_zero_index_for_rank]
|
251
|
+
data[:rank] = responses[index]
|
252
|
+
else
|
253
|
+
data[:rank] = responses[index] + 1
|
254
|
+
end
|
255
|
+
end
|
256
|
+
end
|
196
257
|
|
197
258
|
ranks_for_members << data
|
198
259
|
end
|
@@ -212,29 +273,11 @@ class Leaderboard
|
|
212
273
|
|
213
274
|
private
|
214
275
|
|
215
|
-
def
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
data = {}
|
220
|
-
leaders.each do |leader_data_item|
|
221
|
-
if member_attribute
|
222
|
-
data[:member] = leader_data_item
|
223
|
-
else
|
224
|
-
data[:score] = leader_data_item.to_f
|
225
|
-
data[:rank] = rank_for_in(leaderboard_name, data[:member], use_zero_index_for_rank) if with_rank
|
226
|
-
leader_data << data
|
227
|
-
data = {}
|
228
|
-
end
|
229
|
-
|
230
|
-
if with_scores
|
231
|
-
member_attribute = !member_attribute
|
232
|
-
else
|
233
|
-
leader_data << data
|
234
|
-
data = {}
|
235
|
-
end
|
276
|
+
def validate_page_size(page_size)
|
277
|
+
if page_size && page_size < 1
|
278
|
+
page_size = DEFAULT_PAGE_SIZE
|
236
279
|
end
|
237
280
|
|
238
|
-
|
281
|
+
page_size
|
239
282
|
end
|
240
283
|
end
|
data/test/test_leaderboard.rb
CHANGED
@@ -8,64 +8,92 @@ class TestLeaderboard < Test::Unit::TestCase
|
|
8
8
|
|
9
9
|
def teardown
|
10
10
|
@redis_connection.flushdb
|
11
|
+
@leaderboard.disconnect
|
12
|
+
@redis_connection.client.disconnect
|
11
13
|
end
|
12
14
|
|
13
15
|
def test_version
|
14
|
-
assert_equal '
|
16
|
+
assert_equal '2.0.0', Leaderboard::VERSION
|
15
17
|
end
|
16
18
|
|
17
19
|
def test_initialize_with_defaults
|
18
20
|
assert_equal 'name', @leaderboard.leaderboard_name
|
19
|
-
assert_equal 'localhost', @leaderboard.host
|
20
|
-
assert_equal 6379, @leaderboard.port
|
21
21
|
assert_equal Leaderboard::DEFAULT_PAGE_SIZE, @leaderboard.page_size
|
22
22
|
end
|
23
23
|
|
24
|
+
def test_disconnect
|
25
|
+
assert_equal nil, @leaderboard.disconnect
|
26
|
+
end
|
27
|
+
|
28
|
+
def test_will_automatically_reconnect_after_a_disconnect
|
29
|
+
assert_equal 0, @leaderboard.total_members
|
30
|
+
rank_members_in_leaderboard(5)
|
31
|
+
assert_equal 5, @leaderboard.total_members
|
32
|
+
assert_equal nil, @leaderboard.disconnect
|
33
|
+
assert_equal 5, @leaderboard.total_members
|
34
|
+
end
|
35
|
+
|
24
36
|
def test_page_size_is_default_page_size_if_set_to_invalid_value
|
25
|
-
|
37
|
+
some_leaderboard = Leaderboard.new('name', {:page_size => 0})
|
26
38
|
|
27
|
-
assert_equal Leaderboard::DEFAULT_PAGE_SIZE,
|
39
|
+
assert_equal Leaderboard::DEFAULT_PAGE_SIZE, some_leaderboard.page_size
|
40
|
+
some_leaderboard.disconnect
|
28
41
|
end
|
29
42
|
|
30
|
-
def
|
31
|
-
|
43
|
+
def test_delete_leaderboard
|
44
|
+
rank_members_in_leaderboard
|
45
|
+
|
46
|
+
assert_equal true, @redis_connection.exists('name')
|
47
|
+
@leaderboard.delete_leaderboard
|
48
|
+
assert_equal false, @redis_connection.exists('name')
|
49
|
+
end
|
50
|
+
|
51
|
+
def test_can_pass_existing_redis_connection_to_initializer
|
52
|
+
@leaderboard = Leaderboard.new('name', Leaderboard::DEFAULT_OPTIONS, {:redis_connection => @redis_connection})
|
53
|
+
rank_members_in_leaderboard
|
54
|
+
|
55
|
+
assert_equal 1, @redis_connection.info["connected_clients"].to_i
|
56
|
+
end
|
57
|
+
|
58
|
+
def test_rank_member_and_total_members
|
59
|
+
@leaderboard.rank_member('member', 1)
|
32
60
|
|
33
61
|
assert_equal 1, @leaderboard.total_members
|
34
62
|
end
|
35
63
|
|
36
64
|
def test_total_members_in_score_range
|
37
|
-
|
65
|
+
rank_members_in_leaderboard(5)
|
38
66
|
|
39
67
|
assert_equal 3, @leaderboard.total_members_in_score_range(2, 4)
|
40
68
|
end
|
41
69
|
|
42
70
|
def test_rank_for
|
43
|
-
|
71
|
+
rank_members_in_leaderboard(5)
|
44
72
|
|
45
73
|
assert_equal 2, @leaderboard.rank_for('member_4')
|
46
74
|
assert_equal 1, @leaderboard.rank_for('member_4', true)
|
47
75
|
end
|
48
76
|
|
49
77
|
def test_score_for
|
50
|
-
|
78
|
+
rank_members_in_leaderboard(5)
|
51
79
|
|
52
80
|
assert_equal 4, @leaderboard.score_for('member_4')
|
53
81
|
end
|
54
82
|
|
55
83
|
def test_total_pages
|
56
|
-
|
84
|
+
rank_members_in_leaderboard(10)
|
57
85
|
|
58
86
|
assert_equal 1, @leaderboard.total_pages
|
59
87
|
|
60
88
|
@redis_connection.flushdb
|
61
89
|
|
62
|
-
|
90
|
+
rank_members_in_leaderboard(Leaderboard::DEFAULT_PAGE_SIZE + 1)
|
63
91
|
|
64
92
|
assert_equal 2, @leaderboard.total_pages
|
65
93
|
end
|
66
94
|
|
67
95
|
def test_leaders
|
68
|
-
|
96
|
+
rank_members_in_leaderboard(25)
|
69
97
|
|
70
98
|
assert_equal 25, @leaderboard.total_members
|
71
99
|
|
@@ -79,7 +107,7 @@ class TestLeaderboard < Test::Unit::TestCase
|
|
79
107
|
end
|
80
108
|
|
81
109
|
def test_leaders_with_multiple_pages
|
82
|
-
|
110
|
+
rank_members_in_leaderboard(Leaderboard::DEFAULT_PAGE_SIZE * 3 + 1)
|
83
111
|
|
84
112
|
assert_equal Leaderboard::DEFAULT_PAGE_SIZE * 3 + 1, @leaderboard.total_members
|
85
113
|
|
@@ -102,8 +130,21 @@ class TestLeaderboard < Test::Unit::TestCase
|
|
102
130
|
assert_equal 1, leaders.size
|
103
131
|
end
|
104
132
|
|
133
|
+
def test_leaders_without_retrieving_scores_and_ranks
|
134
|
+
rank_members_in_leaderboard(Leaderboard::DEFAULT_PAGE_SIZE)
|
135
|
+
|
136
|
+
assert_equal Leaderboard::DEFAULT_PAGE_SIZE, @leaderboard.total_members
|
137
|
+
leaders = @leaderboard.leaders(1, {:with_scores => false, :with_ranks => false})
|
138
|
+
|
139
|
+
member_25 = {:member => 'member_25'}
|
140
|
+
assert_equal member_25, leaders[0]
|
141
|
+
|
142
|
+
member_1 = {:member => 'member_1'}
|
143
|
+
assert_equal member_1, leaders[24]
|
144
|
+
end
|
145
|
+
|
105
146
|
def test_around_me
|
106
|
-
|
147
|
+
rank_members_in_leaderboard(Leaderboard::DEFAULT_PAGE_SIZE * 3 + 1)
|
107
148
|
|
108
149
|
assert_equal Leaderboard::DEFAULT_PAGE_SIZE * 3 + 1, @leaderboard.total_members
|
109
150
|
|
@@ -118,12 +159,12 @@ class TestLeaderboard < Test::Unit::TestCase
|
|
118
159
|
end
|
119
160
|
|
120
161
|
def test_ranked_in_list
|
121
|
-
|
162
|
+
rank_members_in_leaderboard(Leaderboard::DEFAULT_PAGE_SIZE)
|
122
163
|
|
123
164
|
assert_equal Leaderboard::DEFAULT_PAGE_SIZE, @leaderboard.total_members
|
124
165
|
|
125
166
|
members = ['member_1', 'member_5', 'member_10']
|
126
|
-
ranked_members = @leaderboard.ranked_in_list(members,
|
167
|
+
ranked_members = @leaderboard.ranked_in_list(members, Leaderboard::DEFAULT_LEADERBOARD_REQUEST_OPTIONS)
|
127
168
|
|
128
169
|
assert_equal 3, ranked_members.size
|
129
170
|
|
@@ -137,8 +178,25 @@ class TestLeaderboard < Test::Unit::TestCase
|
|
137
178
|
assert_equal 10, ranked_members[2][:score]
|
138
179
|
end
|
139
180
|
|
181
|
+
def test_ranked_in_list_without_scores
|
182
|
+
rank_members_in_leaderboard(Leaderboard::DEFAULT_PAGE_SIZE)
|
183
|
+
|
184
|
+
assert_equal Leaderboard::DEFAULT_PAGE_SIZE, @leaderboard.total_members
|
185
|
+
|
186
|
+
members = ['member_1', 'member_5', 'member_10']
|
187
|
+
ranked_members = @leaderboard.ranked_in_list(members, {:with_scores => false, :with_rank => true, :use_zero_index_for_rank => false})
|
188
|
+
|
189
|
+
assert_equal 3, ranked_members.size
|
190
|
+
|
191
|
+
assert_equal 25, ranked_members[0][:rank]
|
192
|
+
|
193
|
+
assert_equal 21, ranked_members[1][:rank]
|
194
|
+
|
195
|
+
assert_equal 16, ranked_members[2][:rank]
|
196
|
+
end
|
197
|
+
|
140
198
|
def test_remove_member
|
141
|
-
|
199
|
+
rank_members_in_leaderboard(Leaderboard::DEFAULT_PAGE_SIZE)
|
142
200
|
|
143
201
|
assert_equal Leaderboard::DEFAULT_PAGE_SIZE, @leaderboard.total_members
|
144
202
|
|
@@ -149,7 +207,7 @@ class TestLeaderboard < Test::Unit::TestCase
|
|
149
207
|
end
|
150
208
|
|
151
209
|
def test_change_score_for
|
152
|
-
@leaderboard.
|
210
|
+
@leaderboard.rank_member('member_1', 5)
|
153
211
|
assert_equal 5, @leaderboard.score_for('member_1')
|
154
212
|
|
155
213
|
@leaderboard.change_score_for('member_1', 5)
|
@@ -160,22 +218,31 @@ class TestLeaderboard < Test::Unit::TestCase
|
|
160
218
|
end
|
161
219
|
|
162
220
|
def test_check_member
|
163
|
-
@leaderboard.
|
221
|
+
@leaderboard.rank_member('member_1', 10)
|
164
222
|
|
165
223
|
assert_equal true, @leaderboard.check_member?('member_1')
|
166
224
|
assert_equal false, @leaderboard.check_member?('member_2')
|
167
225
|
end
|
168
226
|
|
169
227
|
def test_can_change_page_size_and_have_it_reflected_in_size_of_result_set
|
170
|
-
|
228
|
+
rank_members_in_leaderboard(Leaderboard::DEFAULT_PAGE_SIZE)
|
171
229
|
|
172
230
|
@leaderboard.page_size = 5
|
231
|
+
|
173
232
|
assert_equal 5, @leaderboard.total_pages
|
174
233
|
assert_equal 5, @leaderboard.leaders(1).size
|
175
234
|
end
|
176
235
|
|
236
|
+
def test_cannot_set_page_size_to_invalid_page_size
|
237
|
+
rank_members_in_leaderboard(Leaderboard::DEFAULT_PAGE_SIZE)
|
238
|
+
|
239
|
+
@leaderboard.page_size = 0
|
240
|
+
assert_equal 1, @leaderboard.total_pages
|
241
|
+
assert_equal Leaderboard::DEFAULT_PAGE_SIZE, @leaderboard.leaders(1).size
|
242
|
+
end
|
243
|
+
|
177
244
|
def test_score_and_rank_for
|
178
|
-
|
245
|
+
rank_members_in_leaderboard
|
179
246
|
|
180
247
|
data = @leaderboard.score_and_rank_for('member_1')
|
181
248
|
assert_equal 'member_1', data[:member]
|
@@ -184,13 +251,13 @@ class TestLeaderboard < Test::Unit::TestCase
|
|
184
251
|
end
|
185
252
|
|
186
253
|
def test_remove_members_in_score_range
|
187
|
-
|
254
|
+
rank_members_in_leaderboard
|
188
255
|
|
189
256
|
assert_equal 5, @leaderboard.total_members
|
190
257
|
|
191
|
-
@leaderboard.
|
192
|
-
@leaderboard.
|
193
|
-
@leaderboard.
|
258
|
+
@leaderboard.rank_member('cheater_1', 100)
|
259
|
+
@leaderboard.rank_member('cheater_2', 101)
|
260
|
+
@leaderboard.rank_member('cheater_3', 102)
|
194
261
|
|
195
262
|
assert_equal 8, @leaderboard.total_members
|
196
263
|
|
@@ -205,14 +272,14 @@ class TestLeaderboard < Test::Unit::TestCase
|
|
205
272
|
end
|
206
273
|
|
207
274
|
def test_merge_leaderboards
|
208
|
-
foo = Leaderboard.new('foo')
|
275
|
+
foo = Leaderboard.new('foo')
|
209
276
|
bar = Leaderboard.new('bar')
|
210
277
|
|
211
|
-
foo.
|
212
|
-
foo.
|
213
|
-
bar.
|
214
|
-
bar.
|
215
|
-
bar.
|
278
|
+
foo.rank_member('foo_1', 1)
|
279
|
+
foo.rank_member('foo_2', 2)
|
280
|
+
bar.rank_member('bar_1', 3)
|
281
|
+
bar.rank_member('bar_2', 4)
|
282
|
+
bar.rank_member('bar_3', 5)
|
216
283
|
|
217
284
|
foobar_keys = foo.merge_leaderboards('foobar', ['bar'])
|
218
285
|
assert_equal 5, foobar_keys
|
@@ -224,18 +291,22 @@ class TestLeaderboard < Test::Unit::TestCase
|
|
224
291
|
assert_equal 1, first_leader_in_foobar[:rank]
|
225
292
|
assert_equal 'bar_3', first_leader_in_foobar[:member]
|
226
293
|
assert_equal 5, first_leader_in_foobar[:score]
|
294
|
+
|
295
|
+
foo.disconnect
|
296
|
+
bar.disconnect
|
297
|
+
foobar.disconnect
|
227
298
|
end
|
228
299
|
|
229
300
|
def test_intersect_leaderboards
|
230
301
|
foo = Leaderboard.new('foo')
|
231
302
|
bar = Leaderboard.new('bar')
|
232
303
|
|
233
|
-
foo.
|
234
|
-
foo.
|
235
|
-
foo.
|
236
|
-
bar.
|
237
|
-
bar.
|
238
|
-
bar.
|
304
|
+
foo.rank_member('foo_1', 1)
|
305
|
+
foo.rank_member('foo_2', 2)
|
306
|
+
foo.rank_member('bar_3', 6)
|
307
|
+
bar.rank_member('bar_1', 3)
|
308
|
+
bar.rank_member('foo_1', 4)
|
309
|
+
bar.rank_member('bar_3', 5)
|
239
310
|
|
240
311
|
foobar_keys = foo.intersect_leaderboards('foobar', ['bar'], {:aggregate => :max})
|
241
312
|
assert_equal 2, foobar_keys
|
@@ -247,53 +318,57 @@ class TestLeaderboard < Test::Unit::TestCase
|
|
247
318
|
assert_equal 1, first_leader_in_foobar[:rank]
|
248
319
|
assert_equal 'bar_3', first_leader_in_foobar[:member]
|
249
320
|
assert_equal 6, first_leader_in_foobar[:score]
|
321
|
+
|
322
|
+
foo.disconnect
|
323
|
+
bar.disconnect
|
324
|
+
foobar.disconnect
|
250
325
|
end
|
251
326
|
|
252
327
|
def test_massage_leader_data_respects_with_scores
|
253
|
-
|
328
|
+
rank_members_in_leaderboard(25)
|
254
329
|
|
255
330
|
assert_equal 25, @leaderboard.total_members
|
256
331
|
|
257
|
-
leaders = @leaderboard.leaders(1,
|
332
|
+
leaders = @leaderboard.leaders(1, {:with_scores => false, :with_rank => false})
|
258
333
|
assert_not_nil leaders[0][:member]
|
259
334
|
assert_nil leaders[0][:score]
|
260
335
|
assert_nil leaders[0][:rank]
|
261
336
|
|
262
337
|
@leaderboard.page_size = 25
|
263
|
-
leaders = @leaderboard.leaders(1,
|
338
|
+
leaders = @leaderboard.leaders(1, {:with_scores => false, :with_rank => false})
|
264
339
|
assert_equal 25, leaders.size
|
265
340
|
|
266
341
|
@leaderboard.page_size = Leaderboard::DEFAULT_PAGE_SIZE
|
267
|
-
leaders = @leaderboard.leaders(1,
|
342
|
+
leaders = @leaderboard.leaders(1, Leaderboard::DEFAULT_LEADERBOARD_REQUEST_OPTIONS)
|
268
343
|
assert_not_nil leaders[0][:member]
|
269
344
|
assert_not_nil leaders[0][:score]
|
270
345
|
assert_not_nil leaders[0][:rank]
|
271
346
|
|
272
347
|
@leaderboard.page_size = 25
|
273
|
-
leaders = @leaderboard.leaders(1,
|
348
|
+
leaders = @leaderboard.leaders(1, Leaderboard::DEFAULT_LEADERBOARD_REQUEST_OPTIONS)
|
274
349
|
assert_equal 25, leaders.size
|
275
350
|
end
|
276
351
|
|
277
352
|
def test_total_pages_in_with_new_page_size
|
278
|
-
|
353
|
+
rank_members_in_leaderboard(25)
|
279
354
|
|
280
355
|
assert_equal 1, @leaderboard.total_pages_in(@leaderboard.leaderboard_name)
|
281
356
|
assert_equal 5, @leaderboard.total_pages_in(@leaderboard.leaderboard_name, 5)
|
282
357
|
end
|
283
358
|
|
284
359
|
def test_leaders_call_with_new_page_size
|
285
|
-
|
360
|
+
rank_members_in_leaderboard(25)
|
286
361
|
|
287
|
-
assert_equal 5, @leaderboard.leaders(1,
|
288
|
-
assert_equal 10, @leaderboard.leaders(1,
|
289
|
-
assert_equal 10, @leaderboard.leaders(2,
|
290
|
-
assert_equal 5, @leaderboard.leaders(3,
|
362
|
+
assert_equal 5, @leaderboard.leaders(1, Leaderboard::DEFAULT_LEADERBOARD_REQUEST_OPTIONS.merge({:page_size => 5})).size
|
363
|
+
assert_equal 10, @leaderboard.leaders(1, Leaderboard::DEFAULT_LEADERBOARD_REQUEST_OPTIONS.merge({:page_size => 10})).size
|
364
|
+
assert_equal 10, @leaderboard.leaders(2, Leaderboard::DEFAULT_LEADERBOARD_REQUEST_OPTIONS.merge({:page_size => 10})).size
|
365
|
+
assert_equal 5, @leaderboard.leaders(3, Leaderboard::DEFAULT_LEADERBOARD_REQUEST_OPTIONS.merge({:page_size => 10})).size
|
291
366
|
end
|
292
367
|
|
293
368
|
def test_around_me_call_with_new_page_size
|
294
|
-
|
369
|
+
rank_members_in_leaderboard(Leaderboard::DEFAULT_PAGE_SIZE * 3 + 1)
|
295
370
|
|
296
|
-
leaders_around_me = @leaderboard.around_me('member_30',
|
371
|
+
leaders_around_me = @leaderboard.around_me('member_30', Leaderboard::DEFAULT_LEADERBOARD_REQUEST_OPTIONS.merge({:page_size => 3}))
|
297
372
|
assert_equal 3, leaders_around_me.size
|
298
373
|
assert_equal 'member_31', leaders_around_me[0][:member]
|
299
374
|
assert_equal 'member_29', leaders_around_me[2][:member]
|
@@ -301,9 +376,9 @@ class TestLeaderboard < Test::Unit::TestCase
|
|
301
376
|
|
302
377
|
private
|
303
378
|
|
304
|
-
def
|
379
|
+
def rank_members_in_leaderboard(members_to_add = 5)
|
305
380
|
1.upto(members_to_add) do |index|
|
306
|
-
@leaderboard.
|
381
|
+
@leaderboard.rank_member("member_#{index}", index)
|
307
382
|
end
|
308
383
|
end
|
309
384
|
end
|
metadata
CHANGED
@@ -1,95 +1,68 @@
|
|
1
|
-
--- !ruby/object:Gem::Specification
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
2
|
name: leaderboard
|
3
|
-
version: !ruby/object:Gem::Version
|
4
|
-
|
5
|
-
prerelease:
|
6
|
-
segments:
|
7
|
-
- 1
|
8
|
-
- 0
|
9
|
-
- 5
|
10
|
-
version: 1.0.5
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 2.0.0
|
5
|
+
prerelease:
|
11
6
|
platform: ruby
|
12
|
-
authors:
|
7
|
+
authors:
|
13
8
|
- David Czarnecki
|
14
9
|
autorequire:
|
15
10
|
bindir: bin
|
16
11
|
cert_chain: []
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
dependencies:
|
21
|
-
- !ruby/object:Gem::Dependency
|
22
|
-
type: :runtime
|
23
|
-
prerelease: false
|
12
|
+
date: 2011-08-17 00:00:00.000000000Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
24
15
|
name: redis
|
25
|
-
|
16
|
+
requirement: &70114074547140 !ruby/object:Gem::Requirement
|
26
17
|
none: false
|
27
|
-
requirements:
|
18
|
+
requirements:
|
28
19
|
- - ~>
|
29
|
-
- !ruby/object:Gem::Version
|
30
|
-
|
31
|
-
|
32
|
-
- 2
|
33
|
-
- 1
|
34
|
-
- 1
|
35
|
-
version: 2.1.1
|
36
|
-
requirement: *id001
|
37
|
-
- !ruby/object:Gem::Dependency
|
38
|
-
type: :development
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: 2.2.0
|
22
|
+
type: :runtime
|
39
23
|
prerelease: false
|
24
|
+
version_requirements: *70114074547140
|
25
|
+
- !ruby/object:Gem::Dependency
|
40
26
|
name: bundler
|
41
|
-
|
27
|
+
requirement: &70114074545640 !ruby/object:Gem::Requirement
|
42
28
|
none: false
|
43
|
-
requirements:
|
29
|
+
requirements:
|
44
30
|
- - ~>
|
45
|
-
- !ruby/object:Gem::Version
|
46
|
-
hash: 23
|
47
|
-
segments:
|
48
|
-
- 1
|
49
|
-
- 0
|
50
|
-
- 0
|
31
|
+
- !ruby/object:Gem::Version
|
51
32
|
version: 1.0.0
|
52
|
-
requirement: *id002
|
53
|
-
- !ruby/object:Gem::Dependency
|
54
33
|
type: :development
|
55
34
|
prerelease: false
|
35
|
+
version_requirements: *70114074545640
|
36
|
+
- !ruby/object:Gem::Dependency
|
56
37
|
name: jeweler
|
57
|
-
|
38
|
+
requirement: &70114074543920 !ruby/object:Gem::Requirement
|
58
39
|
none: false
|
59
|
-
requirements:
|
40
|
+
requirements:
|
60
41
|
- - ~>
|
61
|
-
- !ruby/object:Gem::Version
|
62
|
-
hash: 7
|
63
|
-
segments:
|
64
|
-
- 1
|
65
|
-
- 5
|
66
|
-
- 2
|
42
|
+
- !ruby/object:Gem::Version
|
67
43
|
version: 1.5.2
|
68
|
-
requirement: *id003
|
69
|
-
- !ruby/object:Gem::Dependency
|
70
44
|
type: :development
|
71
45
|
prerelease: false
|
46
|
+
version_requirements: *70114074543920
|
47
|
+
- !ruby/object:Gem::Dependency
|
72
48
|
name: rcov
|
73
|
-
|
49
|
+
requirement: &70114074539440 !ruby/object:Gem::Requirement
|
74
50
|
none: false
|
75
|
-
requirements:
|
76
|
-
- -
|
77
|
-
- !ruby/object:Gem::Version
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
requirement: *id004
|
51
|
+
requirements:
|
52
|
+
- - ! '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
type: :development
|
56
|
+
prerelease: false
|
57
|
+
version_requirements: *70114074539440
|
83
58
|
description: Leaderboards backed by Redis in Ruby
|
84
59
|
email: dczarnecki@agoragames.com
|
85
60
|
executables: []
|
86
|
-
|
87
61
|
extensions: []
|
88
|
-
|
89
|
-
extra_rdoc_files:
|
62
|
+
extra_rdoc_files:
|
90
63
|
- LICENSE.txt
|
91
64
|
- README.rdoc
|
92
|
-
files:
|
65
|
+
files:
|
93
66
|
- .document
|
94
67
|
- .rvmrc
|
95
68
|
- CHANGELOG.markdown
|
@@ -104,40 +77,34 @@ files:
|
|
104
77
|
- test/helper.rb
|
105
78
|
- test/test.conf
|
106
79
|
- test/test_leaderboard.rb
|
107
|
-
has_rdoc: true
|
108
80
|
homepage: http://github.com/agoragames/leaderboard
|
109
|
-
licenses:
|
81
|
+
licenses:
|
110
82
|
- MIT
|
111
83
|
post_install_message:
|
112
84
|
rdoc_options: []
|
113
|
-
|
114
|
-
require_paths:
|
85
|
+
require_paths:
|
115
86
|
- lib
|
116
|
-
required_ruby_version: !ruby/object:Gem::Requirement
|
87
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
117
88
|
none: false
|
118
|
-
requirements:
|
119
|
-
- -
|
120
|
-
- !ruby/object:Gem::Version
|
121
|
-
|
122
|
-
segments:
|
89
|
+
requirements:
|
90
|
+
- - ! '>='
|
91
|
+
- !ruby/object:Gem::Version
|
92
|
+
version: '0'
|
93
|
+
segments:
|
123
94
|
- 0
|
124
|
-
|
125
|
-
required_rubygems_version: !ruby/object:Gem::Requirement
|
95
|
+
hash: -2495258638232902776
|
96
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
126
97
|
none: false
|
127
|
-
requirements:
|
128
|
-
- -
|
129
|
-
- !ruby/object:Gem::Version
|
130
|
-
|
131
|
-
segments:
|
132
|
-
- 0
|
133
|
-
version: "0"
|
98
|
+
requirements:
|
99
|
+
- - ! '>='
|
100
|
+
- !ruby/object:Gem::Version
|
101
|
+
version: '0'
|
134
102
|
requirements: []
|
135
|
-
|
136
103
|
rubyforge_project:
|
137
|
-
rubygems_version: 1.
|
104
|
+
rubygems_version: 1.8.6
|
138
105
|
signing_key:
|
139
106
|
specification_version: 3
|
140
107
|
summary: Leaderboards backed by Redis in Ruby
|
141
|
-
test_files:
|
108
|
+
test_files:
|
142
109
|
- test/helper.rb
|
143
110
|
- test/test_leaderboard.rb
|