leaderboard_factory 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +17 -0
- data/.rspec +2 -0
- data/.rvmrc +1 -0
- data/CHANGELOG.md +5 -0
- data/Gemfile +3 -0
- data/LICENSE +22 -0
- data/README.md +81 -0
- data/Rakefile +12 -0
- data/leaderboard_factory.gemspec +23 -0
- data/lib/leaderboard_factory/configuration.rb +13 -0
- data/lib/leaderboard_factory/helper_proxy.rb +21 -0
- data/lib/leaderboard_factory/helpers.rb +85 -0
- data/lib/leaderboard_factory/version.rb +3 -0
- data/lib/leaderboard_factory.rb +113 -0
- data/spec/helper_proxy_spec.rb +14 -0
- data/spec/helpers_spec.rb +22 -0
- data/spec/leaderboard_factory_spec.rb +129 -0
- data/spec/spec_helper.rb +9 -0
- metadata +133 -0
data/.gitignore
ADDED
data/.rspec
ADDED
data/.rvmrc
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
rvm --create 1.9.3@leaderboard_factory_gem
|
data/CHANGELOG.md
ADDED
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2012 Matt Wilson
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,81 @@
|
|
1
|
+
# LeaderboardFactory
|
2
|
+
|
3
|
+
Helpful tools for defining a bunch of leaderboards associated with your objects. Builds on the [leaderboard](https://github.com/agoragames/leaderboard) gem.
|
4
|
+
|
5
|
+
## Installation
|
6
|
+
|
7
|
+
Add this line to your application's Gemfile:
|
8
|
+
|
9
|
+
gem 'leaderboard_factory'
|
10
|
+
|
11
|
+
And then execute:
|
12
|
+
|
13
|
+
$ bundle
|
14
|
+
|
15
|
+
Or install it yourself as:
|
16
|
+
|
17
|
+
$ gem install leaderboard_factory
|
18
|
+
|
19
|
+
You'll need to tell it how to find Redis. Configure this on the module:
|
20
|
+
|
21
|
+
```ruby
|
22
|
+
LeaderboardFactory.redis = Redis.new
|
23
|
+
# or
|
24
|
+
LeaderboardFactory.configure do |c|
|
25
|
+
c.redis = Redis.new(db: 15)
|
26
|
+
end
|
27
|
+
```
|
28
|
+
|
29
|
+
## Usage
|
30
|
+
|
31
|
+
Let's start with an example:
|
32
|
+
|
33
|
+
```ruby
|
34
|
+
class Player
|
35
|
+
include LeaderboardFactory
|
36
|
+
|
37
|
+
attr_accessor :id
|
38
|
+
|
39
|
+
leaderboard 'game_duration', :id
|
40
|
+
leaderboard 'maps_by_wins', :id
|
41
|
+
collection_leaderboard 'best_finishes', { reverse: true }
|
42
|
+
end
|
43
|
+
```
|
44
|
+
|
45
|
+
What we've done here is define two leaderboards that are scoped to a player's ID, and one that applies to the entire collection of players. This latter one also ranks things in reverse order--there are two optional parameters to both methods, both hashes, and both are simply passed along to the leaderboard gem. The first is the leaderboard options, the second any specific redis options--if you need to pass along something specific for, say, a leaderboard in a different Redis instance. Check out the [leaderboard](https://github.com/agoragames/leaderboard) gem documentation for more details.
|
46
|
+
|
47
|
+
Let's look at how to use these.
|
48
|
+
|
49
|
+
```ruby
|
50
|
+
p = Player.new
|
51
|
+
p.id = 1234
|
52
|
+
|
53
|
+
p.game_duration # => <Leaderboard @leaderboard_name="game-duration-1234">
|
54
|
+
game_id = 1234
|
55
|
+
game_duration = 2345
|
56
|
+
p.rank_game_duration game_id, game_duration # => ["OK"]
|
57
|
+
p.game_duration.all_members # => [...]
|
58
|
+
|
59
|
+
Player.best_finishes # => <Leaderboard @leaderboard_name="best-finishes">
|
60
|
+
Player.rank_best_finishes p.id, 3, { player_name: "Bob" } # => ["OK", true]
|
61
|
+
Player.best_finishes.all_members(with_member_data: true) # etc etc
|
62
|
+
```
|
63
|
+
|
64
|
+
As you can see, we have a handy accessor that returns our leaderboard, and we even have a handy shortcut to add (*rank* in leaderboard parlance) new items to the board.
|
65
|
+
|
66
|
+
You can examine the options for any defined leaderboard via `Player.leaderboard_specs`.
|
67
|
+
|
68
|
+
There is a nascent and evolving set of helpers that you can access via `Player.leaderboards`--check out the helpers.rb file for more details there. These helpers will probably change.
|
69
|
+
|
70
|
+
|
71
|
+
## Contributing
|
72
|
+
|
73
|
+
1. Fork it
|
74
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
75
|
+
3. Commit your changes (`git commit -am 'Added some feature'`)
|
76
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
77
|
+
5. Create new Pull Request
|
78
|
+
|
79
|
+
## Copyright
|
80
|
+
|
81
|
+
Copyright (c) 2012 Matt Wilson. See LICENSE for further details.
|
data/Rakefile
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
require 'bundler'
|
2
|
+
Bundler::GemHelper.install_tasks
|
3
|
+
|
4
|
+
require 'rspec/core/rake_task'
|
5
|
+
|
6
|
+
RSpec::Core::RakeTask.new(:spec) do |spec|
|
7
|
+
spec.pattern = 'spec/**/*_spec.rb'
|
8
|
+
spec.rspec_opts = ['--backtrace']
|
9
|
+
# spec.ruby_opts = ['-w']
|
10
|
+
end
|
11
|
+
|
12
|
+
task default: :spec
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require 'leaderboard_factory/version'
|
4
|
+
|
5
|
+
Gem::Specification.new do |gem|
|
6
|
+
gem.authors = ["Matt Wilson"]
|
7
|
+
gem.email = ["mwilson@majorleaguegaming.com"]
|
8
|
+
gem.description = %q{Helps you define and work with a bunch of leaderboards, from, e.g. an ActiveModel object}
|
9
|
+
gem.summary = %q{Helps you define and work with a bunch of leaderboards, from, e.g. an ActiveModel object}
|
10
|
+
gem.homepage = "https://github.com/agoragames/leaderboard_factory"
|
11
|
+
|
12
|
+
gem.files = `git ls-files`.split($\)
|
13
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
14
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
15
|
+
gem.name = "leaderboard_factory"
|
16
|
+
gem.require_paths = ["lib"]
|
17
|
+
gem.version = LeaderboardFactory::VERSION
|
18
|
+
|
19
|
+
gem.add_dependency('leaderboard')
|
20
|
+
gem.add_dependency('active_support')
|
21
|
+
gem.add_development_dependency('rake')
|
22
|
+
gem.add_development_dependency('rspec')
|
23
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'leaderboard_factory/helpers'
|
2
|
+
|
3
|
+
module LeaderboardFactory
|
4
|
+
class HelperProxy
|
5
|
+
include LeaderboardFactory::Helpers
|
6
|
+
|
7
|
+
attr_accessor :context
|
8
|
+
|
9
|
+
def initialize context
|
10
|
+
self.context = context
|
11
|
+
end
|
12
|
+
|
13
|
+
end
|
14
|
+
|
15
|
+
module HelperProxyMethods
|
16
|
+
# Returns a contextualized helper instance so that one can use the helpers.
|
17
|
+
def leaderboards
|
18
|
+
HelperProxy.new(self)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,85 @@
|
|
1
|
+
module LeaderboardFactory
|
2
|
+
# This system is in the most flux. These are some helpers that I found very, ahem, *helpful*.
|
3
|
+
# I'm just not sure I'm sold on the API, and I know that there will be more.
|
4
|
+
module Helpers
|
5
|
+
def board_name name, key = nil
|
6
|
+
name = name.gsub('_', '-')
|
7
|
+
name += "-#{context.send(key)}" if key
|
8
|
+
name
|
9
|
+
end
|
10
|
+
|
11
|
+
# Takes the top item off of the pivot and optionally passes the result through a callable mapper.
|
12
|
+
#
|
13
|
+
# @param leaderboard [Symbol] the name of the leaderboard
|
14
|
+
# @param options [Hash] +:mapper+ is the only unique option, other per +#pivot+
|
15
|
+
#
|
16
|
+
# Example
|
17
|
+
#
|
18
|
+
# leaderboards.top(:personal_bests) # => [16.0, ['Event ID 1', 'Event ID 3']]
|
19
|
+
# leaderboards.top(:personal_bests, mapper: Proc.new do |score, bests|
|
20
|
+
# { high_score: score.to_i, tied: bests.size, best_events: bests }
|
21
|
+
# end) # => { high_score: 16, tied: 2, best_events: ['Event ID 1', 'Event ID 3'] }
|
22
|
+
def top leaderboard, options = {}
|
23
|
+
result = pivot(leaderboard, options).first
|
24
|
+
if options[:mapper]
|
25
|
+
options[:mapper].call(*result)
|
26
|
+
else
|
27
|
+
result
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
# Take the leaderboard and pivot the data by the score.
|
32
|
+
# By default it will group the members by their score.
|
33
|
+
#
|
34
|
+
# @param leaderboard [Symbol] the name of the leaderboard you want to pivot
|
35
|
+
# @param options [Hash] (optional) tweak the output
|
36
|
+
#
|
37
|
+
# Available options
|
38
|
+
#
|
39
|
+
# +:member_data+ whether or not to include member data
|
40
|
+
# +:score+ a callable object that will transform the score
|
41
|
+
# +:pluck+ the name of a +member_data+ attribute. If you don't want all of the data.
|
42
|
+
#
|
43
|
+
# Examples
|
44
|
+
#
|
45
|
+
# leaderboards.pivot(:personal_bests) # => { 16.0 => ['Event ID 1', 'Event ID 3'], 14.2 => ['Event ID 2'] }
|
46
|
+
# leaderboards.pivot(:personal_bests, member_data: true)
|
47
|
+
# # => { 16.0 => [{ 'event_name' => 'My Event Name', 'timestamp' => '12323425' },
|
48
|
+
# { 'event_name' => 'My Third Attempt', 'timestamp' => '12323488' } ], ...
|
49
|
+
# leaderboards.pivot(:personal_bests, member_data: true, pluck: 'event_name')
|
50
|
+
# # => { 16.0 => ['My Event Name', 'My Third Attempt'], 14.2 => ['Followup'] }
|
51
|
+
# leaderboards.pivot(:personal_bests, score: Proc.new { |s| s.to_i })
|
52
|
+
# # => { 16 => ['Event ID 1', 'Event ID 3'], 14 => ['Event ID 2'] }
|
53
|
+
def pivot leaderboard, options
|
54
|
+
lb_options = {}
|
55
|
+
if options[:member_data]
|
56
|
+
lb_options.merge!(with_member_data: true)
|
57
|
+
end
|
58
|
+
context.send(leaderboard).all_members(lb_options).inject({}) do |buf, member|
|
59
|
+
key = options[:score] ? options[:score].call(member[:score]) : member[:score]
|
60
|
+
buf[key] ||= []
|
61
|
+
item = if options[:pluck]
|
62
|
+
member[:member_data][options[:pluck]]
|
63
|
+
elsif options[:member_data]
|
64
|
+
member[:member_data]
|
65
|
+
else
|
66
|
+
member[:member]
|
67
|
+
end
|
68
|
+
buf[key] << item
|
69
|
+
buf
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
# returns the given leaderboard
|
74
|
+
#
|
75
|
+
# @param leaderboard [Symbol] the name of the leaderboard you want
|
76
|
+
#
|
77
|
+
# Example
|
78
|
+
#
|
79
|
+
# leaderboards.get(:personal_bests) # => Leaderboard
|
80
|
+
def get leaderboard
|
81
|
+
context.send(leaderboard)
|
82
|
+
end
|
83
|
+
|
84
|
+
end
|
85
|
+
end
|
@@ -0,0 +1,113 @@
|
|
1
|
+
require 'leaderboard'
|
2
|
+
require 'leaderboard_factory/configuration'
|
3
|
+
require 'leaderboard_factory/helper_proxy'
|
4
|
+
require 'leaderboard_factory/version'
|
5
|
+
require 'active_support/inflector'
|
6
|
+
require 'active_support/concern'
|
7
|
+
require 'active_support/core_ext/class/attribute'
|
8
|
+
|
9
|
+
module LeaderboardFactory
|
10
|
+
extend Configuration
|
11
|
+
extend ActiveSupport::Concern
|
12
|
+
|
13
|
+
included do
|
14
|
+
class_attribute :leaderboard_specs
|
15
|
+
self.leaderboard_specs = {
|
16
|
+
instance: {},
|
17
|
+
collection: {}
|
18
|
+
}
|
19
|
+
|
20
|
+
include HelperProxyMethods
|
21
|
+
extend HelperProxyMethods
|
22
|
+
end
|
23
|
+
|
24
|
+
module ClassMethods
|
25
|
+
# Defines a new leaderboard that will be scoped to some unique property on the object instance.
|
26
|
+
# Use this if you want to, say, track a specific player's personal bests, or some other
|
27
|
+
# stat that is specific to the individual.
|
28
|
+
# This method defines an accessor that will return the leaderboard, as well as a shorthand
|
29
|
+
# method for ranking a new item in the leaderboard
|
30
|
+
#
|
31
|
+
# @param board [String] the name of the leaderboard
|
32
|
+
# @param scope_key [String/Symbol] the name of an attribute on the instance that will scope the leaderboard.
|
33
|
+
# @param options [Hash] optional; these are passed along to the leaderboard object
|
34
|
+
# @param redis_options [Hash] optional; these are also passed along to the leaderboard object
|
35
|
+
#
|
36
|
+
# Example
|
37
|
+
#
|
38
|
+
# class Player < ActiveRecord::Base
|
39
|
+
# include LeaderboardFactory
|
40
|
+
# leaderboard 'maps_by_wins', :id
|
41
|
+
# end
|
42
|
+
#
|
43
|
+
# p = Player.new(id: 77)
|
44
|
+
# p.maps_by_wins # => the player's personal maps leaderboard
|
45
|
+
# p.rank_map_by_wins map.name, 33, { map_id: 42 } # => ["OK", true]
|
46
|
+
def leaderboard board, scope_key, options = {}, redis_options = {}
|
47
|
+
self.leaderboard_specs[:instance][board] = {
|
48
|
+
key: scope_key,
|
49
|
+
options: options,
|
50
|
+
redis_options: redis_options
|
51
|
+
}
|
52
|
+
|
53
|
+
define_methods board, :instance
|
54
|
+
end
|
55
|
+
|
56
|
+
# As +leaderboard+, but on the class rather than the instance.
|
57
|
+
# it does not take a +scope_key+ parameter, but all other functionality is the same.
|
58
|
+
#
|
59
|
+
# @param board [String] the name of the leaderboard
|
60
|
+
# @param scope_key [String/Symbol] the name of an attribute on the instance that will scope the leaderboard.
|
61
|
+
# @param options [Hash] optional; these are passed along to the leaderboard object
|
62
|
+
# @param redis_options [Hash] optional; these are also passed along to the leaderboard object
|
63
|
+
#
|
64
|
+
# Example
|
65
|
+
#
|
66
|
+
# class Player < ActiveRecord::Base
|
67
|
+
# include LeaderboardFactory
|
68
|
+
# collection_leaderboard 'strength_of_schedule'
|
69
|
+
# end
|
70
|
+
#
|
71
|
+
# Player.strength_of_schedule # => the leaderboard object
|
72
|
+
# Player.rank_strength_of_schedule 232, 66.3, { player_name: 'Bob' } # => ["OK", true]
|
73
|
+
def collection_leaderboard board, options = {}, redis_options = {}
|
74
|
+
self.leaderboard_specs[:collection][board] = {
|
75
|
+
options: options,
|
76
|
+
redis_options: redis_options
|
77
|
+
}
|
78
|
+
|
79
|
+
define_methods board, :collection, 'self.'
|
80
|
+
end
|
81
|
+
|
82
|
+
# Method what actually does the defining.
|
83
|
+
def define_methods board, type = :instance, prefix = ''
|
84
|
+
singluar_object, *remainder_of_name = board.split("_")
|
85
|
+
singluar_object = singluar_object.singularize
|
86
|
+
accessor_method_name = ([singluar_object] + remainder_of_name).join("_")
|
87
|
+
|
88
|
+
class_eval <<-METHODS, __FILE__, __LINE__
|
89
|
+
def #{prefix}#{board}
|
90
|
+
return @#{board} if @#{board}
|
91
|
+
options = leaderboard_specs[:#{type}]['#{board}'][:options]
|
92
|
+
redis_options = leaderboard_specs[:#{type}]['#{board}'][:redis_options]
|
93
|
+
redis_key = leaderboard_specs[:#{type}]['#{board}'][:key]
|
94
|
+
|
95
|
+
redis_options.merge!({
|
96
|
+
redis_connection: LeaderboardFactory.redis
|
97
|
+
})
|
98
|
+
|
99
|
+
@#{board} = Leaderboard.new( leaderboards.board_name('#{board}', redis_key),
|
100
|
+
Leaderboard::DEFAULT_OPTIONS.merge(options),
|
101
|
+
redis_options )
|
102
|
+
end
|
103
|
+
|
104
|
+
def #{prefix}rank_#{accessor_method_name} object, rank, member_data = nil
|
105
|
+
#{board}.rank_member object, rank, member_data
|
106
|
+
end
|
107
|
+
METHODS
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
# instance methods would go here...
|
112
|
+
|
113
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module LeaderboardFactory
|
4
|
+
describe HelperProxy do
|
5
|
+
it "takes on parameter to initialize, the context" do
|
6
|
+
foo = mock
|
7
|
+
proxy = HelperProxy.new(foo)
|
8
|
+
proxy.context.should === foo
|
9
|
+
end
|
10
|
+
it "includes the actual helpers" do
|
11
|
+
HelperProxy.included_modules.should include(LeaderboardFactory::Helpers)
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module LeaderboardFactory
|
4
|
+
describe Helpers do
|
5
|
+
let(:kontext) {
|
6
|
+
mock
|
7
|
+
}
|
8
|
+
let(:proxy) {
|
9
|
+
LeaderboardFactory::HelperProxy.new(kontext)
|
10
|
+
}
|
11
|
+
|
12
|
+
describe "#board_name" do
|
13
|
+
it "returns a good name for the leaderboard" do
|
14
|
+
proxy.board_name('garlics_by_weight').should == 'garlics-by-weight'
|
15
|
+
end
|
16
|
+
it "takes an optional second parameter which will be used to uniqify the name" do
|
17
|
+
kontext.should_receive(:id).and_return(1234)
|
18
|
+
proxy.board_name('personal_best_garlics', :id).should == 'personal-best-garlics-1234'
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,129 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe LeaderboardFactory do
|
4
|
+
let(:test_harness) {
|
5
|
+
Class.new do
|
6
|
+
attr_accessor :id
|
7
|
+
include LeaderboardFactory
|
8
|
+
end
|
9
|
+
}
|
10
|
+
|
11
|
+
it "isn't borked" do
|
12
|
+
test_harness.included_modules.should include(LeaderboardFactory)
|
13
|
+
end
|
14
|
+
|
15
|
+
context 'configuration' do
|
16
|
+
it 'has a redis accessor' do
|
17
|
+
LeaderboardFactory.should respond_to(:redis)
|
18
|
+
end
|
19
|
+
it "uses the redis that is configured" do
|
20
|
+
LeaderboardFactory.redis.client.db.should == 15
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
describe ".leaderboard" do
|
25
|
+
it "defines a connection to a leaderboard object" do
|
26
|
+
test_harness.should respond_to(:leaderboard)
|
27
|
+
test_harness.class_eval do
|
28
|
+
leaderboard 'fu_manchu', :id
|
29
|
+
end
|
30
|
+
test_harness.leaderboard_specs[:instance]['fu_manchu'].should include({
|
31
|
+
key: :id,
|
32
|
+
options: {}
|
33
|
+
})
|
34
|
+
end
|
35
|
+
it "creates a factory method that returns said leaderboard" do
|
36
|
+
test_harness.class_eval do
|
37
|
+
leaderboard 'fu_manchu', :id
|
38
|
+
end
|
39
|
+
instance = test_harness.new
|
40
|
+
|
41
|
+
instance.fu_manchu.should be_a_kind_of(Leaderboard)
|
42
|
+
end
|
43
|
+
it "uses the second parameter to namespace the leaderboard" do
|
44
|
+
test_harness.class_eval do
|
45
|
+
leaderboard 'fu_manchu', :id
|
46
|
+
end
|
47
|
+
instance = test_harness.new
|
48
|
+
instance.id = 'haha'
|
49
|
+
leaderboard = instance.fu_manchu
|
50
|
+
leaderboard.leaderboard_name.should == 'fu-manchu-haha'
|
51
|
+
end
|
52
|
+
it "doesn't leak the abstraction" do
|
53
|
+
klass = Class.new do
|
54
|
+
attr_accessor :id
|
55
|
+
include LeaderboardFactory
|
56
|
+
leaderboard 'garlic', :id
|
57
|
+
end
|
58
|
+
|
59
|
+
klass.new.leaderboard_specs[:instance].keys.should include('garlic')
|
60
|
+
test_harness.new.leaderboard_specs[:instance].should be_empty
|
61
|
+
end
|
62
|
+
it "is connected to the configured redis instance" do
|
63
|
+
test_harness.class_eval do
|
64
|
+
leaderboard 'fu_manchu', :id
|
65
|
+
end
|
66
|
+
redis = test_harness.new.fu_manchu.instance_variable_get(:@redis_connection)
|
67
|
+
redis.should === LeaderboardFactory.redis
|
68
|
+
end
|
69
|
+
it "adds a convience accessor based on the singularized object name, e.g. maps_by_wins => rank_map_by_wins" do
|
70
|
+
test_harness.class_eval do
|
71
|
+
leaderboard 'maps_by_wins', :id
|
72
|
+
end
|
73
|
+
instance = test_harness.new
|
74
|
+
|
75
|
+
instance.should respond_to(:rank_map_by_wins)
|
76
|
+
instance.rank_map_by_wins 'map', 3
|
77
|
+
instance.maps_by_wins.all_members.should include({:member=>"map", :rank=>1, :score=>3.0})
|
78
|
+
end
|
79
|
+
describe "this convience accessor" do
|
80
|
+
it "accepts an optional third parameter, which is member data" do
|
81
|
+
test_harness.class_eval do
|
82
|
+
leaderboard 'maps_by_wins', :id
|
83
|
+
end
|
84
|
+
instance = test_harness.new
|
85
|
+
|
86
|
+
instance.rank_map_by_wins 'map', 3, { event_name: 'framulator 5000' }
|
87
|
+
instance.maps_by_wins.all_members(with_member_data: true).should include({
|
88
|
+
member: "map",
|
89
|
+
rank: 1,
|
90
|
+
score: 3.0,
|
91
|
+
member_data: {"event_name"=>"framulator 5000"}
|
92
|
+
})
|
93
|
+
end
|
94
|
+
end
|
95
|
+
it "can be overriden in the class" do
|
96
|
+
klass = Class.new do
|
97
|
+
attr_accessor :id
|
98
|
+
include LeaderboardFactory
|
99
|
+
leaderboard 'garlics_by_weight', :id
|
100
|
+
|
101
|
+
def rank_garlic_by_weight
|
102
|
+
"HA! HA!"
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
klass.new.rank_garlic_by_weight.should == "HA! HA!"
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
describe ".collection_leaderboard" do
|
111
|
+
it "defines a connection to a leaderboard object" do
|
112
|
+
test_harness.should respond_to(:collection_leaderboard)
|
113
|
+
test_harness.class_eval do
|
114
|
+
collection_leaderboard 'greatest_of_all_time'
|
115
|
+
end
|
116
|
+
test_harness.leaderboard_specs[:collection]['greatest_of_all_time'].should include({
|
117
|
+
options: {}
|
118
|
+
})
|
119
|
+
end
|
120
|
+
it "creates a factory method that returns said leaderboard" do
|
121
|
+
test_harness.class_eval do
|
122
|
+
collection_leaderboard 'greatest_of_all_time'
|
123
|
+
end
|
124
|
+
|
125
|
+
test_harness.greatest_of_all_time.should be_a_kind_of(Leaderboard)
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
end
|
data/spec/spec_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,133 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: leaderboard_factory
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Matt Wilson
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-08-03 00:00:00.000000000 Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: leaderboard
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '0'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ! '>='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '0'
|
30
|
+
- !ruby/object:Gem::Dependency
|
31
|
+
name: active_support
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
33
|
+
none: false
|
34
|
+
requirements:
|
35
|
+
- - ! '>='
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '0'
|
38
|
+
type: :runtime
|
39
|
+
prerelease: false
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ! '>='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: '0'
|
46
|
+
- !ruby/object:Gem::Dependency
|
47
|
+
name: rake
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
49
|
+
none: false
|
50
|
+
requirements:
|
51
|
+
- - ! '>='
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: '0'
|
54
|
+
type: :development
|
55
|
+
prerelease: false
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ! '>='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
- !ruby/object:Gem::Dependency
|
63
|
+
name: rspec
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
65
|
+
none: false
|
66
|
+
requirements:
|
67
|
+
- - ! '>='
|
68
|
+
- !ruby/object:Gem::Version
|
69
|
+
version: '0'
|
70
|
+
type: :development
|
71
|
+
prerelease: false
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ! '>='
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '0'
|
78
|
+
description: Helps you define and work with a bunch of leaderboards, from, e.g. an
|
79
|
+
ActiveModel object
|
80
|
+
email:
|
81
|
+
- mwilson@majorleaguegaming.com
|
82
|
+
executables: []
|
83
|
+
extensions: []
|
84
|
+
extra_rdoc_files: []
|
85
|
+
files:
|
86
|
+
- .gitignore
|
87
|
+
- .rspec
|
88
|
+
- .rvmrc
|
89
|
+
- CHANGELOG.md
|
90
|
+
- Gemfile
|
91
|
+
- LICENSE
|
92
|
+
- README.md
|
93
|
+
- Rakefile
|
94
|
+
- leaderboard_factory.gemspec
|
95
|
+
- lib/leaderboard_factory.rb
|
96
|
+
- lib/leaderboard_factory/configuration.rb
|
97
|
+
- lib/leaderboard_factory/helper_proxy.rb
|
98
|
+
- lib/leaderboard_factory/helpers.rb
|
99
|
+
- lib/leaderboard_factory/version.rb
|
100
|
+
- spec/helper_proxy_spec.rb
|
101
|
+
- spec/helpers_spec.rb
|
102
|
+
- spec/leaderboard_factory_spec.rb
|
103
|
+
- spec/spec_helper.rb
|
104
|
+
homepage: https://github.com/agoragames/leaderboard_factory
|
105
|
+
licenses: []
|
106
|
+
post_install_message:
|
107
|
+
rdoc_options: []
|
108
|
+
require_paths:
|
109
|
+
- lib
|
110
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
111
|
+
none: false
|
112
|
+
requirements:
|
113
|
+
- - ! '>='
|
114
|
+
- !ruby/object:Gem::Version
|
115
|
+
version: '0'
|
116
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
117
|
+
none: false
|
118
|
+
requirements:
|
119
|
+
- - ! '>='
|
120
|
+
- !ruby/object:Gem::Version
|
121
|
+
version: '0'
|
122
|
+
requirements: []
|
123
|
+
rubyforge_project:
|
124
|
+
rubygems_version: 1.8.24
|
125
|
+
signing_key:
|
126
|
+
specification_version: 3
|
127
|
+
summary: Helps you define and work with a bunch of leaderboards, from, e.g. an ActiveModel
|
128
|
+
object
|
129
|
+
test_files:
|
130
|
+
- spec/helper_proxy_spec.rb
|
131
|
+
- spec/helpers_spec.rb
|
132
|
+
- spec/leaderboard_factory_spec.rb
|
133
|
+
- spec/spec_helper.rb
|