almicube 0.0.2 → 0.0.3
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 +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
|