almicube 0.0.2 → 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile.lock +44 -0
- data/Rakefile +6 -0
- data/almicube.gemspec +3 -0
- data/lib/almicube/aggregator/base.rb +25 -0
- data/lib/almicube/aggregator/sum_aggregator.rb +23 -0
- data/lib/almicube/builder.rb +27 -30
- data/lib/almicube/bundler/base.rb +18 -0
- data/lib/almicube/bundler/days_ago_bundler.rb +22 -0
- data/lib/almicube/bundler/today_bundler.rb +9 -0
- data/lib/almicube/bundler/weekly_bundler.rb +11 -0
- data/lib/almicube/bundler/yesterday_bundler.rb +16 -0
- data/lib/almicube/cog.rb +11 -0
- data/lib/almicube/config.rb +40 -0
- data/lib/almicube/engine.rb +6 -0
- data/lib/almicube/key.rb +46 -0
- data/lib/almicube/model.rb +2 -5
- data/lib/almicube/proxy/association_proxy.rb +1 -1
- data/lib/almicube/ranking/base.rb +63 -0
- data/lib/almicube/ranking/data_ranking.rb +128 -0
- data/lib/almicube/ranking/sub_ranking.rb +51 -0
- data/lib/almicube/selector/all_selector.rb +18 -0
- data/lib/almicube/selector/base.rb +32 -0
- data/lib/almicube/selector/has_many_selector.rb +42 -0
- data/lib/almicube/selector/method_selector.rb +34 -0
- data/lib/almicube/version.rb +1 -1
- data/lib/almicube.rb +34 -4
- data/spec/almicube/aggregator/sum_aggregator_spec.rb +92 -0
- data/spec/almicube/builder_sprc.rb +22 -0
- data/spec/almicube/bundler/days_ago_bundler_spec.rb +20 -0
- data/spec/almicube/bundler/today_bundler_spec.rb +24 -0
- data/spec/almicube/bundler/yesterday_bundler_spec.rb +16 -0
- data/spec/almicube/config_spec.rb +46 -0
- data/spec/almicube/key_spec.rb +30 -0
- data/spec/almicube/ranking/base_spec.rb +9 -0
- data/spec/almicube/ranking/data_ranking_spec.rb +103 -0
- data/spec/almicube/ranking/sub_ranking_spec.rb +34 -0
- data/spec/almicube/selector/all_selector_spec.rb +22 -0
- data/spec/almicube/selector/method_selector_spec.rb +39 -0
- data/spec/almicube/selector/mock_spec.rb +34 -0
- data/spec/mocks/aggregator.rb +2 -0
- data/spec/mocks/bundler.rb +5 -0
- data/spec/mocks/model.rb +17 -0
- data/spec/mocks/selector.rb +9 -0
- data/spec/spec_helper.rb +11 -0
- data/spec/supports/shared_examples.rb +22 -0
- metadata +89 -7
- data/lib/almicube/builder/average_ranking_builder.rb +0 -35
- data/lib/almicube/builder/countable_ranking_builder.rb +0 -35
- data/lib/almicube/ranged_ranking.rb +0 -57
- data/lib/almicube/ranking.rb +0 -134
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3b5b3dee4cf2a4ca349f8b5d218fe23cbb6fbb7c
|
4
|
+
data.tar.gz: d5423d3770485d8176bd9cb0ac306e0ed2e32ac0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 86cc68a0f86730eb0d64e526dd49135265090574ac085ea3bbdf267940573cfd1f222abbf6b1eae7348b408684de7f204a0552b0927666850f0b61a0a2d29b04
|
7
|
+
data.tar.gz: a3d2279edd141c513f93a6e34ae80ab77089d7e01f2c7c354af3fa5ee048ca22e2eea82fa630e850787c78e77b23266e298ecdf2d7395ee12245633a6b12e986
|
data/Gemfile.lock
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
almicube (0.0.2)
|
5
|
+
activemodel (~> 4.0)
|
6
|
+
activesupport (~> 4.0)
|
7
|
+
redis (~> 3.0)
|
8
|
+
|
9
|
+
GEM
|
10
|
+
remote: https://rubygems.org/
|
11
|
+
specs:
|
12
|
+
activemodel (4.1.0)
|
13
|
+
activesupport (= 4.1.0)
|
14
|
+
builder (~> 3.1)
|
15
|
+
activesupport (4.1.0)
|
16
|
+
i18n (~> 0.6, >= 0.6.9)
|
17
|
+
json (~> 1.7, >= 1.7.7)
|
18
|
+
minitest (~> 5.1)
|
19
|
+
thread_safe (~> 0.1)
|
20
|
+
tzinfo (~> 1.1)
|
21
|
+
builder (3.2.2)
|
22
|
+
diff-lcs (1.2.5)
|
23
|
+
i18n (0.6.9)
|
24
|
+
json (1.8.1)
|
25
|
+
minitest (5.3.3)
|
26
|
+
redis (3.0.7)
|
27
|
+
rspec (2.14.1)
|
28
|
+
rspec-core (~> 2.14.0)
|
29
|
+
rspec-expectations (~> 2.14.0)
|
30
|
+
rspec-mocks (~> 2.14.0)
|
31
|
+
rspec-core (2.14.8)
|
32
|
+
rspec-expectations (2.14.5)
|
33
|
+
diff-lcs (>= 1.1.3, < 2.0)
|
34
|
+
rspec-mocks (2.14.6)
|
35
|
+
thread_safe (0.3.3)
|
36
|
+
tzinfo (1.1.0)
|
37
|
+
thread_safe (~> 0.1)
|
38
|
+
|
39
|
+
PLATFORMS
|
40
|
+
ruby
|
41
|
+
|
42
|
+
DEPENDENCIES
|
43
|
+
almicube!
|
44
|
+
rspec (~> 2.0)
|
data/Rakefile
ADDED
data/almicube.gemspec
CHANGED
@@ -0,0 +1,25 @@
|
|
1
|
+
module Almicube
|
2
|
+
module Aggregator
|
3
|
+
class Base
|
4
|
+
include Almicube::Cog
|
5
|
+
|
6
|
+
class << self
|
7
|
+
def connection
|
8
|
+
@redis ||= Almicube::Config.config.connection
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def aggregate(ranking=nil)
|
13
|
+
self.ranking = ranking unless active? || ranking.nil?
|
14
|
+
|
15
|
+
self.ranking.selector.before_aggregate if self.ranking.selector.respond_to? :before_aggregate
|
16
|
+
|
17
|
+
if self.ranking.data?
|
18
|
+
data_aggregate self.ranking.key
|
19
|
+
else
|
20
|
+
sub_aggregate self.ranking.key
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Almicube
|
2
|
+
module Aggregator
|
3
|
+
class SumAggregator < Base
|
4
|
+
protected
|
5
|
+
|
6
|
+
def data_aggregate(key)
|
7
|
+
ranking.records.each do |record|
|
8
|
+
value = record.send(ranking.attribute_name) if record.respond_to? ranking.attribute_name
|
9
|
+
value = ranking.default_score if value.nil?
|
10
|
+
self.class.connection.zadd(key, value, record.to_param)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
def sub_aggregate(key)
|
15
|
+
keys = ranking.bundled_keys.select { |k| self.class.connection.zcard(k) > 0 }
|
16
|
+
keys << ranking.selector.interstore
|
17
|
+
if keys.length
|
18
|
+
self.class.connection.zinterstore(key, keys)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
data/lib/almicube/builder.rb
CHANGED
@@ -1,41 +1,38 @@
|
|
1
1
|
module Almicube
|
2
|
-
|
3
|
-
|
4
|
-
def instance(name, options={})
|
5
|
-
raise ArgumentError, "invalid #1 name" unless has_builder? name
|
6
|
-
builders[name].new options
|
7
|
-
end
|
2
|
+
class Builder
|
3
|
+
attr_accessor :selector, :date, :bundler, :class_name, :attribute_name
|
8
4
|
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
builders.has_key? name
|
17
|
-
end
|
5
|
+
def initialize(options={})
|
6
|
+
@class_name = options[:class_name]
|
7
|
+
@attribute_name = options[:attribute_name]
|
8
|
+
@selector = select_selector(options[:selector])
|
9
|
+
@bundler = select_bundler(options[:bundler])
|
10
|
+
@date = options[:date] || Date.today
|
11
|
+
end
|
18
12
|
|
19
|
-
|
20
|
-
|
21
|
-
|
13
|
+
def data(date=nil)
|
14
|
+
date ||= self.date
|
15
|
+
Almicube::Ranking::DataRanking.new options
|
16
|
+
end
|
22
17
|
|
23
|
-
|
24
|
-
|
25
|
-
|
18
|
+
def options
|
19
|
+
{ selector: selector,
|
20
|
+
bundler: bundler,
|
21
|
+
date: date,
|
22
|
+
class_name: class_name,
|
23
|
+
attribute_name: attribute_name }
|
26
24
|
end
|
27
25
|
|
28
|
-
|
29
|
-
def self.included(base)
|
30
|
-
base.include InstanceMethods
|
31
|
-
end
|
26
|
+
protected
|
32
27
|
|
33
|
-
|
34
|
-
|
35
|
-
|
28
|
+
def select_selector(selector)
|
29
|
+
selector = selector.constantize if selector.is_a?(String) && Object.const_defined?(selector.to_s)
|
30
|
+
selector = selector.new if selector.is_a? Class
|
31
|
+
selector
|
32
|
+
end
|
36
33
|
|
37
|
-
|
38
|
-
|
34
|
+
def select_bundler(bundler)
|
35
|
+
bundler
|
39
36
|
end
|
40
37
|
end
|
41
38
|
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Almicube
|
2
|
+
module Bundler
|
3
|
+
class Base
|
4
|
+
include Almicube::Cog
|
5
|
+
attr_reader :name
|
6
|
+
|
7
|
+
def initialize(options={})
|
8
|
+
@name = options[:bundle] || options[:name]
|
9
|
+
end
|
10
|
+
|
11
|
+
alias :bundle :name
|
12
|
+
|
13
|
+
def keys
|
14
|
+
[]
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module Almicube
|
2
|
+
module Bundler
|
3
|
+
class DaysAgoBundler < Base
|
4
|
+
attr_reader :range
|
5
|
+
|
6
|
+
def initialize(options={})
|
7
|
+
@range = ( options[:range] || 1 ).to_i
|
8
|
+
options[:name] ||= :"#{range}-days-ago"
|
9
|
+
super options
|
10
|
+
end
|
11
|
+
|
12
|
+
def keys
|
13
|
+
return [] unless has_ranking?
|
14
|
+
range.times.map do |i|
|
15
|
+
key = ranking.data_key
|
16
|
+
key[:date] = key[:date] - (i+1).days
|
17
|
+
key
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module Almicube
|
2
|
+
module Bundler
|
3
|
+
class YesterdayBundler < Base
|
4
|
+
def initialize(options={})
|
5
|
+
options[:name] = :yesterday
|
6
|
+
super(options)
|
7
|
+
end
|
8
|
+
|
9
|
+
def keys
|
10
|
+
key = ranking.data_key
|
11
|
+
key[:date] = ranking.date - 1.days
|
12
|
+
[key]
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
data/lib/almicube/cog.rb
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'active_model'
|
2
|
+
|
3
|
+
module Almicube
|
4
|
+
class Config
|
5
|
+
include ActiveModel::Model
|
6
|
+
attr_accessor :connection, :key_format
|
7
|
+
|
8
|
+
class << self
|
9
|
+
def root
|
10
|
+
Rails.root if defined? Rails
|
11
|
+
end
|
12
|
+
|
13
|
+
def filepath
|
14
|
+
@filepath ||= File.join(root.to_s, "config", "almicube.yml")
|
15
|
+
end
|
16
|
+
|
17
|
+
def config
|
18
|
+
if @instance.nil? && File.exists?(filepath)
|
19
|
+
@instance = self.new YAML.load_file(filepath)
|
20
|
+
end
|
21
|
+
@instance ||= self.new {}
|
22
|
+
end
|
23
|
+
|
24
|
+
def reset
|
25
|
+
@instance = nil
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def connection(env = :default)
|
30
|
+
@connection ||= { default: nil }
|
31
|
+
raise ArgumentError, "connection does not exist" unless @connection.has_key? env
|
32
|
+
@redis ||= Redis.new @connection[env] unless @connection[env].nil?
|
33
|
+
@redis ||= Redis.new
|
34
|
+
end
|
35
|
+
|
36
|
+
def key_format
|
37
|
+
@key_format ||= '%{prefix}:%{class_name}:%{attribute_name}:%{type}:%{distinction}:%{suffix}'
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
data/lib/almicube/key.rb
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
module Almicube
|
2
|
+
class Key
|
3
|
+
|
4
|
+
ALLOWED_OPTIONS = %i[prefix suffix class_name attribute_name type distinction date selector]
|
5
|
+
KEY_PATTERN = /%{([a-z_]+)}/ # Example) %{sample_key}
|
6
|
+
|
7
|
+
attr_reader :options, :ranking
|
8
|
+
|
9
|
+
attr_accessor :config
|
10
|
+
|
11
|
+
def initialize(ranking, options={})
|
12
|
+
@ranking = ranking
|
13
|
+
@options = ranking.options.merge(options).select { |k| self.class::ALLOWED_OPTIONS.include? k.to_sym }
|
14
|
+
@config ||= Config.config
|
15
|
+
end
|
16
|
+
|
17
|
+
def [](name)
|
18
|
+
options[name.to_sym]
|
19
|
+
end
|
20
|
+
|
21
|
+
def []=(name, value)
|
22
|
+
options[name.to_sym] = value if self.class::ALLOWED_OPTIONS.include? name.to_sym
|
23
|
+
end
|
24
|
+
|
25
|
+
def method_missing(m, *args, &block)
|
26
|
+
if to_str.respond_to? m
|
27
|
+
to_str.send(m, *args, &block)
|
28
|
+
else
|
29
|
+
super
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def to_str
|
34
|
+
key = config.key_format.clone
|
35
|
+
key.match( self.class::KEY_PATTERN ) do |m|
|
36
|
+
value = options.fetch(m[1].to_sym, '')
|
37
|
+
value = value.strftime(options.fetch(:date_format, '%Y%m%d')) if value.is_a? Date
|
38
|
+
value = value.label if value.kind_of? Selector::Base
|
39
|
+
key.gsub! m[0], value.to_s
|
40
|
+
end while key =~ self.class::KEY_PATTERN
|
41
|
+
key
|
42
|
+
end
|
43
|
+
|
44
|
+
alias :to_s :to_str
|
45
|
+
end
|
46
|
+
end
|
data/lib/almicube/model.rb
CHANGED
@@ -10,16 +10,13 @@ module Almicube
|
|
10
10
|
ranker = ranker.to_s
|
11
11
|
options = options.symbolize_keys!.merge(class_name: self, attribute_name: ranker.to_sym)
|
12
12
|
|
13
|
-
builder_name = options.delete :builder
|
14
|
-
builder_name = :countable unless builder_name
|
15
|
-
|
16
13
|
@ranking_builders ||= {}
|
17
|
-
@ranking_builders[ranker.to_sym] = Almicube::Builder.
|
14
|
+
@ranking_builders[ranker.to_sym] = Almicube::Builder.new options
|
18
15
|
|
19
16
|
class_eval <<-EVAL
|
20
17
|
def self.#{ranker}_ranking(date = Date.today)
|
21
18
|
@rankings ||= {}
|
22
|
-
@rankings[:"#{ranker}:\#{date.to_s}"] ||= @ranking_builders[:#{ranker}].
|
19
|
+
@rankings[:"#{ranker}:\#{date.to_s}"] ||= @ranking_builders[:#{ranker}].data(date)
|
23
20
|
end
|
24
21
|
|
25
22
|
def #{ranker}_ranking(date = Date.today)
|
@@ -1,7 +1,7 @@
|
|
1
1
|
module Almicube
|
2
2
|
class AssociationProxy
|
3
3
|
def initialize(ranking, item)
|
4
|
-
raise TypeError, "without the Almicube::Ranking as #1 argument" unless ranking.kind_of? Ranking
|
4
|
+
raise TypeError, "without the Almicube::Ranking as #1 argument" unless ranking.kind_of? Ranking::Base
|
5
5
|
@item = item
|
6
6
|
@ranking = ranking
|
7
7
|
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
module Almicube
|
2
|
+
module Ranking
|
3
|
+
class Base
|
4
|
+
attr_reader :selector, :bundler, :aggregator, :class_name, :date
|
5
|
+
attr_accessor :per_page
|
6
|
+
|
7
|
+
def initialize(options={})
|
8
|
+
@selector = options[:selector]
|
9
|
+
@aggregator = options[:aggregator] || Aggregator::SumAggregator.new
|
10
|
+
@bundler = options[:bundler]
|
11
|
+
@prefix = options[:prefix]
|
12
|
+
@suffix = options[:suffix]
|
13
|
+
@date = options[:date] || Date.today
|
14
|
+
@class_name = options[:class_name]
|
15
|
+
@class_name = @class_name.constantize if @class_name.is_a? String
|
16
|
+
@per_page = options[:per_page] || 10
|
17
|
+
|
18
|
+
@selector.ranking = self unless @selector.nil?
|
19
|
+
@aggregator.ranking = self unless @aggregator.nil?
|
20
|
+
@bundler.ranking = self unless @bundler.nil?
|
21
|
+
end
|
22
|
+
|
23
|
+
def records
|
24
|
+
selector.records
|
25
|
+
end
|
26
|
+
|
27
|
+
def bundled_keys
|
28
|
+
bundler.keys || []
|
29
|
+
end
|
30
|
+
|
31
|
+
def connection
|
32
|
+
Almicube::Config.config.connection
|
33
|
+
end
|
34
|
+
|
35
|
+
def page(page=1)
|
36
|
+
aggregate!
|
37
|
+
page = [1, page.to_i].max
|
38
|
+
revrange = connection.zrevrange(key, (page - 1) * per_page, page * per_page - 1)
|
39
|
+
records = class_name.where("id IN (?)", revrange).all
|
40
|
+
revrange.inject([]) { |l, v| l << records.detect { |r| r.to_param == v } }
|
41
|
+
end
|
42
|
+
|
43
|
+
def aggregate!(options = {})
|
44
|
+
@aggregator.aggregate self
|
45
|
+
end
|
46
|
+
|
47
|
+
def aggregate(options = {})
|
48
|
+
aggregate! options
|
49
|
+
true
|
50
|
+
rescue Exception => e
|
51
|
+
false
|
52
|
+
end
|
53
|
+
|
54
|
+
def data?
|
55
|
+
false
|
56
|
+
end
|
57
|
+
|
58
|
+
protected
|
59
|
+
|
60
|
+
attr_reader :prefix, :suffix
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,128 @@
|
|
1
|
+
require "redis"
|
2
|
+
require "active_support/all"
|
3
|
+
|
4
|
+
module Almicube
|
5
|
+
module Ranking
|
6
|
+
class DataRanking < Base
|
7
|
+
class << self
|
8
|
+
def default_options
|
9
|
+
{ attribute_name: :score,
|
10
|
+
prefix: 'ranking',
|
11
|
+
suffix: '',
|
12
|
+
distinction: '%{date}',
|
13
|
+
date_format: '%Y%m%d',
|
14
|
+
date: Date.today,
|
15
|
+
per_page: 10,
|
16
|
+
as: Float,
|
17
|
+
default_score: 0,
|
18
|
+
class_name: nil }
|
19
|
+
end
|
20
|
+
|
21
|
+
def build(options={})
|
22
|
+
self.new options
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def initialize(options={})
|
27
|
+
@options = self.class.default_options.merge options.symbolize_keys
|
28
|
+
|
29
|
+
raise TypeError, ":as option is only allowed Integer or Float" unless [Integer, Float].include? @options[:as]
|
30
|
+
|
31
|
+
super(@options)
|
32
|
+
|
33
|
+
@selector ||= Selector::AllSelector.new self.options
|
34
|
+
@options.delete(:selector)
|
35
|
+
@selector.ranking = self
|
36
|
+
|
37
|
+
@options[:aggregator] ||= Aggregator::SumAggregator.new
|
38
|
+
@options[:aggregator].ranking = self
|
39
|
+
end
|
40
|
+
|
41
|
+
KEY_PATTERN = /%{([a-z_]+)}/ # Example) %{sample_key}
|
42
|
+
|
43
|
+
def key(options={})
|
44
|
+
Almicube::Key.new self, options.merge( type: :data )
|
45
|
+
end
|
46
|
+
|
47
|
+
def data_key
|
48
|
+
key_format(@options[:data_key], @options.merge({ type: :data }))
|
49
|
+
end
|
50
|
+
|
51
|
+
def attribute_name
|
52
|
+
@options.fetch(:attribute_name, :score).to_s.to_sym
|
53
|
+
end
|
54
|
+
|
55
|
+
def date
|
56
|
+
@options.fetch(:date, Date.today)
|
57
|
+
end
|
58
|
+
|
59
|
+
def in(target)
|
60
|
+
association_name = class_name.to_s.underscore.pluralize
|
61
|
+
|
62
|
+
if ( target.class != class_name ) && target.respond_to?(association_name)
|
63
|
+
_selector = Selector::HasManySelector.new target: target, association_name: association_name
|
64
|
+
_selector.ranking = self
|
65
|
+
return SubRanking.new self, selector: _selector
|
66
|
+
end
|
67
|
+
|
68
|
+
self
|
69
|
+
end
|
70
|
+
|
71
|
+
def ranged(name)
|
72
|
+
SubRanking.new(self).ranged(name)
|
73
|
+
end
|
74
|
+
|
75
|
+
def per_page=(value)
|
76
|
+
@options[:per_page] = value
|
77
|
+
end
|
78
|
+
|
79
|
+
def options
|
80
|
+
@options.select{ |k| k != :type }.merge({ selector: selector, aggregator: aggregator })
|
81
|
+
end
|
82
|
+
|
83
|
+
def data?
|
84
|
+
selector.data_provider?
|
85
|
+
end
|
86
|
+
|
87
|
+
def exists?
|
88
|
+
connection.exists key
|
89
|
+
end
|
90
|
+
|
91
|
+
def default_score
|
92
|
+
@options.fetch(:default_score, 0)
|
93
|
+
end
|
94
|
+
|
95
|
+
def score(item)
|
96
|
+
actual_score = ( connection.zscore key, item.to_param ) || @options.fetch(:default_score, 0)
|
97
|
+
case @options[:as].to_s
|
98
|
+
when "Integer"
|
99
|
+
actual_score.to_i
|
100
|
+
when "Float"
|
101
|
+
actual_score.to_f
|
102
|
+
else
|
103
|
+
actual_score
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
def rank(item)
|
108
|
+
connection.zrevrank(key, item.to_param) + 1
|
109
|
+
end
|
110
|
+
|
111
|
+
def incr(item, score = 1)
|
112
|
+
connection.zincrby key, score, item.to_param
|
113
|
+
end
|
114
|
+
|
115
|
+
protected
|
116
|
+
|
117
|
+
def key_format(key_base, options)
|
118
|
+
key = key_base.to_s.clone
|
119
|
+
tmp_options = options.merge date: options.fetch(:date, Date.today).strftime(@options[:date_format])
|
120
|
+
tmp_options[:type] ||= :data
|
121
|
+
key.match( self.class::KEY_PATTERN ) do |m|
|
122
|
+
key.gsub! m[0], tmp_options.fetch(m[1].to_sym, '').to_s
|
123
|
+
end while key =~ self.class::KEY_PATTERN
|
124
|
+
key
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
128
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
module Almicube
|
2
|
+
module Ranking
|
3
|
+
class SubRanking < Base
|
4
|
+
attr_reader :ranking, :bundler
|
5
|
+
|
6
|
+
def initialize(ranking, options={})
|
7
|
+
super(options)
|
8
|
+
|
9
|
+
@ranking = ranking
|
10
|
+
self.selector ||= ranking.selector
|
11
|
+
self.bundler = ( options[:bundler] || Almicube::Bundler::YesterdayBundler.new )
|
12
|
+
@class_name ||= ranking.class_name
|
13
|
+
end
|
14
|
+
|
15
|
+
def key
|
16
|
+
key = ranking.key
|
17
|
+
key[:type] = :built
|
18
|
+
key[:suffix] = suffix
|
19
|
+
key[:selector] = selector
|
20
|
+
key[:distinction] = "%{date}:in-%{selector}" unless selector.is_a? Selector::AllSelector
|
21
|
+
key
|
22
|
+
end
|
23
|
+
|
24
|
+
def data_key
|
25
|
+
ranking.key
|
26
|
+
end
|
27
|
+
|
28
|
+
def bundler=(value)
|
29
|
+
@bundler = value
|
30
|
+
value.ranking = self
|
31
|
+
end
|
32
|
+
|
33
|
+
def selector=(value)
|
34
|
+
@selector = value
|
35
|
+
value.ranking = self
|
36
|
+
end
|
37
|
+
|
38
|
+
def ranged(name)
|
39
|
+
bundler_class = "Almicube::Bundler::#{name.to_s.classify}Bundler".constantize
|
40
|
+
self.bundler = bundler_class.new if bundler_class.is_a? Class
|
41
|
+
self
|
42
|
+
end
|
43
|
+
|
44
|
+
protected
|
45
|
+
|
46
|
+
def suffix
|
47
|
+
bundler.bundle unless bundler.nil?
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|