leaderboard 3.3.0 → 3.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +15 -0
- data/CHANGELOG.markdown +4 -0
- data/README.markdown +1 -0
- data/lib/leaderboard.rb +39 -0
- data/lib/leaderboard/version.rb +1 -1
- data/spec/leaderboard_spec.rb +18 -8
- data/spec/reverse_leaderboard_spec.rb +17 -7
- data/spec/version_spec.rb +1 -1
- metadata +5 -19
checksums.yaml
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
---
|
2
|
+
!binary "U0hBMQ==":
|
3
|
+
metadata.gz: !binary |-
|
4
|
+
ZDg1OTQ1OTc4MzkzY2I4Mzc5ZjEwZWVlZTU3M2QzMTdlZDc2MmM4MQ==
|
5
|
+
data.tar.gz: !binary |-
|
6
|
+
YjEwOWE0Mzk3NjA1YjA5NzlmYzQ0OWQ0ODliN2E1NjFjYzE4MTkzMA==
|
7
|
+
SHA512:
|
8
|
+
metadata.gz: !binary |-
|
9
|
+
MWNmY2NjNmU5NGJkMzM0ZGViZGNiZTE5MGU4ZTZjYTIxZGYwNGJiNzU3N2Uz
|
10
|
+
YjBjOTlhZmJiYjIyNTk5NTE3NDdhYTE0Mjc5OWQ5YWI5MWEwNDQyM2U4ODQ3
|
11
|
+
MTUzMzJhYWEwN2YwNTBkNjUxZTI5OTcyMDNiYjQ5M2IyOTUzNjQ=
|
12
|
+
data.tar.gz: !binary |-
|
13
|
+
MzlmOTczZDJkMDNhNWM0ZDdmYzNlNzE5Y2VmOTcwMmI4MTVlMWY0ZjUwMWIw
|
14
|
+
ZTIxYTYwODgyMWJjYThlZjY1Yzg4YjhlNjcwMzI5NjljZmYwZjI4YzljNDgy
|
15
|
+
ZWY4NGI3ZWMzZDc0MzJiYjAwOGYyNmM2NzA0ZDVjZGJkNWQ0ZDY=
|
data/CHANGELOG.markdown
CHANGED
@@ -1,5 +1,9 @@
|
|
1
1
|
# CHANGELOG
|
2
2
|
|
3
|
+
## 3.4.0 (2013-11-12)
|
4
|
+
|
5
|
+
* Added `score_for_percentile` method to be able to calculate the score for a given percentile value in the leaderboard.
|
6
|
+
|
3
7
|
## 3.3.0 (2013-07-17)
|
4
8
|
|
5
9
|
* Added `rank_member_across` method to be able to rank a member across multiple leaderboards at once.
|
data/README.markdown
CHANGED
@@ -319,6 +319,7 @@ highscore_lb.rank_member_across(['highscores', 'more_highscores'], 'david', 5000
|
|
319
319
|
remove_members_in_score_range(min_score, max_score): Remove members from the leaderboard within a score range
|
320
320
|
remove_members_outside_rank(rank): Remove members from the leaderboard outside a given rank
|
321
321
|
percentile_for(member): Calculate the percentile for a given member
|
322
|
+
score_for_percentile(percentile): Calculate the score for a given percentile value in the leaderboard
|
322
323
|
page_for(member, page_size): Determine the page where a member falls in the leaderboard
|
323
324
|
expire_leaderboard(seconds): Expire the leaderboard in a set number of seconds.
|
324
325
|
expire_leaderboard_at(timestamp): Expire the leaderboard at a specific UNIX timestamp.
|
data/lib/leaderboard.rb
CHANGED
@@ -512,6 +512,45 @@ class Leaderboard
|
|
512
512
|
end
|
513
513
|
end
|
514
514
|
|
515
|
+
# Calculate the score for a given percentile value in the leaderboard.
|
516
|
+
#
|
517
|
+
# @param percentile [float] Percentile value (0.0 to 100.0 inclusive)
|
518
|
+
def score_for_percentile(percentile)
|
519
|
+
score_for_percentile_in(@leaderboard_name, percentile)
|
520
|
+
end
|
521
|
+
|
522
|
+
# Calculate the score for a given percentile value in the named leaderboard.
|
523
|
+
#
|
524
|
+
# See http://www.itl.nist.gov/div898/handbook/prc/section2/prc252.htm for
|
525
|
+
# implementation details (there are differing methods for calculating
|
526
|
+
# percentile scores that do not fall directly upon a ranked item; we are
|
527
|
+
# using the method specified by NIST, i.e. linear interpolation).
|
528
|
+
#
|
529
|
+
# @param percentile [float] Percentile value (0.0 to 100.0 inclusive)
|
530
|
+
def score_for_percentile_in(leaderboard_name, percentile)
|
531
|
+
return nil unless percentile.between?(0, 100)
|
532
|
+
|
533
|
+
total_members = total_members_in(leaderboard_name)
|
534
|
+
return nil if total_members < 1
|
535
|
+
|
536
|
+
if @reverse
|
537
|
+
percentile = 100 - percentile
|
538
|
+
end
|
539
|
+
|
540
|
+
index = (total_members - 1) * (percentile / 100.0)
|
541
|
+
|
542
|
+
scores = @redis_connection.zrange(
|
543
|
+
leaderboard_name, index.floor, index.ceil, :with_scores => true
|
544
|
+
).map{ |pair| pair.last }
|
545
|
+
|
546
|
+
if index == index.floor
|
547
|
+
scores[0]
|
548
|
+
else
|
549
|
+
interpolate_fraction = index - index.floor
|
550
|
+
scores[0] + interpolate_fraction * (scores[1] - scores[0])
|
551
|
+
end
|
552
|
+
end
|
553
|
+
|
515
554
|
# Determine the page where a member falls in the leaderboard.
|
516
555
|
#
|
517
556
|
# @param member [String] Member name.
|
data/lib/leaderboard/version.rb
CHANGED
data/spec/leaderboard_spec.rb
CHANGED
@@ -3,7 +3,7 @@ require 'spec_helper'
|
|
3
3
|
describe 'Leaderboard' do
|
4
4
|
before(:each) do
|
5
5
|
@redis_connection = Redis.new(:host => "127.0.0.1", :db => 15)
|
6
|
-
@leaderboard = Leaderboard.new('name', Leaderboard::
|
6
|
+
@leaderboard = Leaderboard.new('name', Leaderboard::DEFAULT_OPTIONS, {:host => "127.0.0.1", :db => 15})
|
7
7
|
end
|
8
8
|
|
9
9
|
after(:each) do
|
@@ -30,7 +30,7 @@ describe 'Leaderboard' do
|
|
30
30
|
end
|
31
31
|
|
32
32
|
it 'should set the page size to the default page size if passed an invalid value' do
|
33
|
-
some_leaderboard = Leaderboard.new('name', {:page_size => 0})
|
33
|
+
some_leaderboard = Leaderboard.new('name', {:page_size => 0}, {:host => "127.0.0.1", :db => 15})
|
34
34
|
|
35
35
|
some_leaderboard.page_size.should be(Leaderboard::DEFAULT_PAGE_SIZE)
|
36
36
|
some_leaderboard.disconnect
|
@@ -371,8 +371,8 @@ describe 'Leaderboard' do
|
|
371
371
|
end
|
372
372
|
|
373
373
|
it 'should allow you to merge leaderboards' do
|
374
|
-
foo = Leaderboard.new('foo', Leaderboard::
|
375
|
-
bar = Leaderboard.new('bar', Leaderboard::
|
374
|
+
foo = Leaderboard.new('foo', Leaderboard::DEFAULT_OPTIONS, {:host => "127.0.0.1", :db => 15})
|
375
|
+
bar = Leaderboard.new('bar', Leaderboard::DEFAULT_OPTIONS, {:host => "127.0.0.1", :db => 15})
|
376
376
|
|
377
377
|
foo.rank_member('foo_1', 1)
|
378
378
|
foo.rank_member('foo_2', 2)
|
@@ -383,7 +383,7 @@ describe 'Leaderboard' do
|
|
383
383
|
foobar_keys = foo.merge_leaderboards('foobar', ['bar'])
|
384
384
|
foobar_keys.should be(5)
|
385
385
|
|
386
|
-
foobar = Leaderboard.new('foobar', Leaderboard::
|
386
|
+
foobar = Leaderboard.new('foobar', Leaderboard::DEFAULT_OPTIONS, {:host => "127.0.0.1", :db => 15})
|
387
387
|
foobar.total_members.should be(5)
|
388
388
|
|
389
389
|
first_leader_in_foobar = foobar.leaders(1).first
|
@@ -397,8 +397,8 @@ describe 'Leaderboard' do
|
|
397
397
|
end
|
398
398
|
|
399
399
|
it 'should allow you to intersect leaderboards' do
|
400
|
-
foo = Leaderboard.new('foo', Leaderboard::
|
401
|
-
bar = Leaderboard.new('bar', Leaderboard::
|
400
|
+
foo = Leaderboard.new('foo', Leaderboard::DEFAULT_OPTIONS, {:host => "127.0.0.1", :db => 15})
|
401
|
+
bar = Leaderboard.new('bar', Leaderboard::DEFAULT_OPTIONS, {:host => "127.0.0.1", :db => 15})
|
402
402
|
|
403
403
|
foo.rank_member('foo_1', 1)
|
404
404
|
foo.rank_member('foo_2', 2)
|
@@ -410,7 +410,7 @@ describe 'Leaderboard' do
|
|
410
410
|
foobar_keys = foo.intersect_leaderboards('foobar', ['bar'], {:aggregate => :max})
|
411
411
|
foobar_keys.should be(2)
|
412
412
|
|
413
|
-
foobar = Leaderboard.new('foobar', Leaderboard::
|
413
|
+
foobar = Leaderboard.new('foobar', Leaderboard::DEFAULT_OPTIONS, {:host => "127.0.0.1", :db => 15})
|
414
414
|
foobar.total_members.should be(2)
|
415
415
|
|
416
416
|
first_leader_in_foobar = foobar.leaders(1).first
|
@@ -479,6 +479,16 @@ describe 'Leaderboard' do
|
|
479
479
|
@leaderboard.percentile_for('member_12').should eql(92)
|
480
480
|
end
|
481
481
|
|
482
|
+
it 'should return the correct information when calling score_for_percentile' do
|
483
|
+
rank_members_in_leaderboard(5)
|
484
|
+
|
485
|
+
@leaderboard.score_for_percentile(0).should eql(1.0)
|
486
|
+
@leaderboard.score_for_percentile(75).should eql(4.0)
|
487
|
+
@leaderboard.score_for_percentile(87.5).should eql(4.5)
|
488
|
+
@leaderboard.score_for_percentile(93.75).should eql(4.75)
|
489
|
+
@leaderboard.score_for_percentile(100).should eql(5.0)
|
490
|
+
end
|
491
|
+
|
482
492
|
it 'should not throw an exception when calling around_me with a member not in the leaderboard' do
|
483
493
|
rank_members_in_leaderboard(Leaderboard::DEFAULT_PAGE_SIZE * 3 + 1)
|
484
494
|
|
@@ -3,7 +3,7 @@ require 'spec_helper'
|
|
3
3
|
describe 'Leaderboard (reverse option)' do
|
4
4
|
before(:each) do
|
5
5
|
@redis_connection = Redis.new(:host => "127.0.0.1", :db => 15)
|
6
|
-
@leaderboard = Leaderboard.new('name', Leaderboard::
|
6
|
+
@leaderboard = Leaderboard.new('name', Leaderboard::DEFAULT_OPTIONS.merge({:reverse => true}), {:host => "127.0.0.1", :db => 15})
|
7
7
|
end
|
8
8
|
|
9
9
|
after(:each) do
|
@@ -186,8 +186,8 @@ describe 'Leaderboard (reverse option)' do
|
|
186
186
|
end
|
187
187
|
|
188
188
|
it 'should allow you to merge leaderboards' do
|
189
|
-
foo = Leaderboard.new('foo', Leaderboard::
|
190
|
-
bar = Leaderboard.new('bar', Leaderboard::
|
189
|
+
foo = Leaderboard.new('foo', Leaderboard::DEFAULT_OPTIONS, {:host => "127.0.0.1", :db => 15})
|
190
|
+
bar = Leaderboard.new('bar', Leaderboard::DEFAULT_OPTIONS, {:host => "127.0.0.1", :db => 15})
|
191
191
|
|
192
192
|
foo.rank_member('foo_1', 1)
|
193
193
|
foo.rank_member('foo_2', 2)
|
@@ -198,7 +198,7 @@ describe 'Leaderboard (reverse option)' do
|
|
198
198
|
foobar_keys = foo.merge_leaderboards('foobar', ['bar'])
|
199
199
|
foobar_keys.should be(5)
|
200
200
|
|
201
|
-
foobar = Leaderboard.new('foobar', Leaderboard::
|
201
|
+
foobar = Leaderboard.new('foobar', Leaderboard::DEFAULT_OPTIONS, {:host => "127.0.0.1", :db => 15})
|
202
202
|
foobar.total_members.should be(5)
|
203
203
|
|
204
204
|
first_leader_in_foobar = foobar.leaders(1).first
|
@@ -212,8 +212,8 @@ describe 'Leaderboard (reverse option)' do
|
|
212
212
|
end
|
213
213
|
|
214
214
|
it 'should allow you to intersect leaderboards' do
|
215
|
-
foo = Leaderboard.new('foo', Leaderboard::
|
216
|
-
bar = Leaderboard.new('bar', Leaderboard::
|
215
|
+
foo = Leaderboard.new('foo', Leaderboard::DEFAULT_OPTIONS, {:host => "127.0.0.1", :db => 15})
|
216
|
+
bar = Leaderboard.new('bar', Leaderboard::DEFAULT_OPTIONS, {:host => "127.0.0.1", :db => 15})
|
217
217
|
|
218
218
|
foo.rank_member('foo_1', 1)
|
219
219
|
foo.rank_member('foo_2', 2)
|
@@ -225,7 +225,7 @@ describe 'Leaderboard (reverse option)' do
|
|
225
225
|
foobar_keys = foo.intersect_leaderboards('foobar', ['bar'], {:aggregate => :max})
|
226
226
|
foobar_keys.should be(2)
|
227
227
|
|
228
|
-
foobar = Leaderboard.new('foobar', Leaderboard::
|
228
|
+
foobar = Leaderboard.new('foobar', Leaderboard::DEFAULT_OPTIONS, {:host => "127.0.0.1", :db => 15})
|
229
229
|
foobar.total_members.should be(2)
|
230
230
|
|
231
231
|
first_leader_in_foobar = foobar.leaders(1).first
|
@@ -275,6 +275,16 @@ describe 'Leaderboard (reverse option)' do
|
|
275
275
|
@leaderboard.percentile_for('member_12').should eql(8)
|
276
276
|
end
|
277
277
|
|
278
|
+
it 'should return the correct information when calling score_for_percentile' do
|
279
|
+
rank_members_in_leaderboard(5)
|
280
|
+
|
281
|
+
@leaderboard.score_for_percentile(0).should eql(5.0)
|
282
|
+
@leaderboard.score_for_percentile(75).should eql(2.0)
|
283
|
+
@leaderboard.score_for_percentile(87.5).should eql(1.5)
|
284
|
+
@leaderboard.score_for_percentile(93.75).should eql(1.25)
|
285
|
+
@leaderboard.score_for_percentile(100).should eql(1.0)
|
286
|
+
end
|
287
|
+
|
278
288
|
it 'should return the correct page when calling page_for a given member in the leaderboard' do
|
279
289
|
@leaderboard.page_for('jones').should be(0)
|
280
290
|
|
data/spec/version_spec.rb
CHANGED
metadata
CHANGED
@@ -1,20 +1,18 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: leaderboard
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.
|
5
|
-
prerelease:
|
4
|
+
version: 3.4.0
|
6
5
|
platform: ruby
|
7
6
|
authors:
|
8
7
|
- David Czarnecki
|
9
8
|
autorequire:
|
10
9
|
bindir: bin
|
11
10
|
cert_chain: []
|
12
|
-
date: 2013-
|
11
|
+
date: 2013-11-12 00:00:00.000000000 Z
|
13
12
|
dependencies:
|
14
13
|
- !ruby/object:Gem::Dependency
|
15
14
|
name: redis
|
16
15
|
requirement: !ruby/object:Gem::Requirement
|
17
|
-
none: false
|
18
16
|
requirements:
|
19
17
|
- - ! '>='
|
20
18
|
- !ruby/object:Gem::Version
|
@@ -22,7 +20,6 @@ dependencies:
|
|
22
20
|
type: :runtime
|
23
21
|
prerelease: false
|
24
22
|
version_requirements: !ruby/object:Gem::Requirement
|
25
|
-
none: false
|
26
23
|
requirements:
|
27
24
|
- - ! '>='
|
28
25
|
- !ruby/object:Gem::Version
|
@@ -30,7 +27,6 @@ dependencies:
|
|
30
27
|
- !ruby/object:Gem::Dependency
|
31
28
|
name: rake
|
32
29
|
requirement: !ruby/object:Gem::Requirement
|
33
|
-
none: false
|
34
30
|
requirements:
|
35
31
|
- - ! '>='
|
36
32
|
- !ruby/object:Gem::Version
|
@@ -38,7 +34,6 @@ dependencies:
|
|
38
34
|
type: :development
|
39
35
|
prerelease: false
|
40
36
|
version_requirements: !ruby/object:Gem::Requirement
|
41
|
-
none: false
|
42
37
|
requirements:
|
43
38
|
- - ! '>='
|
44
39
|
- !ruby/object:Gem::Version
|
@@ -46,7 +41,6 @@ dependencies:
|
|
46
41
|
- !ruby/object:Gem::Dependency
|
47
42
|
name: rspec
|
48
43
|
requirement: !ruby/object:Gem::Requirement
|
49
|
-
none: false
|
50
44
|
requirements:
|
51
45
|
- - ! '>='
|
52
46
|
- !ruby/object:Gem::Version
|
@@ -54,7 +48,6 @@ dependencies:
|
|
54
48
|
type: :development
|
55
49
|
prerelease: false
|
56
50
|
version_requirements: !ruby/object:Gem::Requirement
|
57
|
-
none: false
|
58
51
|
requirements:
|
59
52
|
- - ! '>='
|
60
53
|
- !ruby/object:Gem::Version
|
@@ -86,33 +79,26 @@ files:
|
|
86
79
|
homepage: https://github.com/agoragames/leaderboard
|
87
80
|
licenses:
|
88
81
|
- MIT
|
82
|
+
metadata: {}
|
89
83
|
post_install_message:
|
90
84
|
rdoc_options: []
|
91
85
|
require_paths:
|
92
86
|
- lib
|
93
87
|
required_ruby_version: !ruby/object:Gem::Requirement
|
94
|
-
none: false
|
95
88
|
requirements:
|
96
89
|
- - ! '>='
|
97
90
|
- !ruby/object:Gem::Version
|
98
91
|
version: '0'
|
99
|
-
segments:
|
100
|
-
- 0
|
101
|
-
hash: 1089001734082897595
|
102
92
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
103
|
-
none: false
|
104
93
|
requirements:
|
105
94
|
- - ! '>='
|
106
95
|
- !ruby/object:Gem::Version
|
107
96
|
version: '0'
|
108
|
-
segments:
|
109
|
-
- 0
|
110
|
-
hash: 1089001734082897595
|
111
97
|
requirements: []
|
112
98
|
rubyforge_project: leaderboard
|
113
|
-
rubygems_version: 1.
|
99
|
+
rubygems_version: 2.1.10
|
114
100
|
signing_key:
|
115
|
-
specification_version:
|
101
|
+
specification_version: 4
|
116
102
|
summary: Leaderboards backed by Redis in Ruby
|
117
103
|
test_files:
|
118
104
|
- spec/leaderboard_spec.rb
|