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
data/spec/mocks/model.rb
ADDED
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
2
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__)))
|
3
|
+
|
4
|
+
require 'bundler/setup'
|
5
|
+
Bundler.require
|
6
|
+
|
7
|
+
Dir[File.join(File.dirname(__FILE__), "supports", "*.rb")].each {|f| require f}
|
8
|
+
Dir[File.join(File.dirname(__FILE__), "mocks", "*.rb")].each {|f| require f}
|
9
|
+
|
10
|
+
RSpec.configure do |config|
|
11
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
shared_examples "ranking cog" do
|
2
|
+
let(:ranking) { Almicube::Ranking::DataRanking.new }
|
3
|
+
describe "#ranking=" do
|
4
|
+
it { expect{ target.ranking = ranking }.not_to raise_error }
|
5
|
+
end
|
6
|
+
|
7
|
+
describe "#ranking" do
|
8
|
+
before { target.ranking = ranking }
|
9
|
+
it { expect(target.ranking).to eq ranking }
|
10
|
+
end
|
11
|
+
|
12
|
+
describe "#active?" do
|
13
|
+
context "setted ranking" do
|
14
|
+
before { target.ranking = ranking }
|
15
|
+
it { expect(target).to be_active }
|
16
|
+
end
|
17
|
+
|
18
|
+
context "don't set ranking" do
|
19
|
+
it { expect(target).not_to be_active }
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: almicube
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- niaeashes
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-
|
11
|
+
date: 2014-05-11 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: redis
|
@@ -38,6 +38,34 @@ dependencies:
|
|
38
38
|
- - ~>
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '4.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: activemodel
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ~>
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '4.0'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ~>
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '4.0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rspec
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ~>
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '2.0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ~>
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '2.0'
|
41
69
|
description: Provide raking system for your ActiveRecord Model on Rails 4 with SortedSet
|
42
70
|
of Redis DataBase.
|
43
71
|
email:
|
@@ -48,18 +76,53 @@ extra_rdoc_files: []
|
|
48
76
|
files:
|
49
77
|
- .gitignore
|
50
78
|
- Gemfile
|
79
|
+
- Gemfile.lock
|
51
80
|
- LICENSE
|
52
81
|
- README.md
|
82
|
+
- Rakefile
|
53
83
|
- almicube.gemspec
|
54
84
|
- lib/almicube.rb
|
85
|
+
- lib/almicube/aggregator/base.rb
|
86
|
+
- lib/almicube/aggregator/sum_aggregator.rb
|
55
87
|
- lib/almicube/builder.rb
|
56
|
-
- lib/almicube/
|
57
|
-
- lib/almicube/
|
88
|
+
- lib/almicube/bundler/base.rb
|
89
|
+
- lib/almicube/bundler/days_ago_bundler.rb
|
90
|
+
- lib/almicube/bundler/today_bundler.rb
|
91
|
+
- lib/almicube/bundler/weekly_bundler.rb
|
92
|
+
- lib/almicube/bundler/yesterday_bundler.rb
|
93
|
+
- lib/almicube/cog.rb
|
94
|
+
- lib/almicube/config.rb
|
95
|
+
- lib/almicube/engine.rb
|
96
|
+
- lib/almicube/key.rb
|
58
97
|
- lib/almicube/model.rb
|
59
98
|
- lib/almicube/proxy/association_proxy.rb
|
60
|
-
- lib/almicube/
|
61
|
-
- lib/almicube/ranking.rb
|
99
|
+
- lib/almicube/ranking/base.rb
|
100
|
+
- lib/almicube/ranking/data_ranking.rb
|
101
|
+
- lib/almicube/ranking/sub_ranking.rb
|
102
|
+
- lib/almicube/selector/all_selector.rb
|
103
|
+
- lib/almicube/selector/base.rb
|
104
|
+
- lib/almicube/selector/has_many_selector.rb
|
105
|
+
- lib/almicube/selector/method_selector.rb
|
62
106
|
- lib/almicube/version.rb
|
107
|
+
- spec/almicube/aggregator/sum_aggregator_spec.rb
|
108
|
+
- spec/almicube/builder_sprc.rb
|
109
|
+
- spec/almicube/bundler/days_ago_bundler_spec.rb
|
110
|
+
- spec/almicube/bundler/today_bundler_spec.rb
|
111
|
+
- spec/almicube/bundler/yesterday_bundler_spec.rb
|
112
|
+
- spec/almicube/config_spec.rb
|
113
|
+
- spec/almicube/key_spec.rb
|
114
|
+
- spec/almicube/ranking/base_spec.rb
|
115
|
+
- spec/almicube/ranking/data_ranking_spec.rb
|
116
|
+
- spec/almicube/ranking/sub_ranking_spec.rb
|
117
|
+
- spec/almicube/selector/all_selector_spec.rb
|
118
|
+
- spec/almicube/selector/method_selector_spec.rb
|
119
|
+
- spec/almicube/selector/mock_spec.rb
|
120
|
+
- spec/mocks/aggregator.rb
|
121
|
+
- spec/mocks/bundler.rb
|
122
|
+
- spec/mocks/model.rb
|
123
|
+
- spec/mocks/selector.rb
|
124
|
+
- spec/spec_helper.rb
|
125
|
+
- spec/supports/shared_examples.rb
|
63
126
|
homepage: https://github.com/niaeashes/almicube
|
64
127
|
licenses:
|
65
128
|
- MIT
|
@@ -84,4 +147,23 @@ rubygems_version: 2.2.2
|
|
84
147
|
signing_key:
|
85
148
|
specification_version: 4
|
86
149
|
summary: Ranking extension for your model
|
87
|
-
test_files:
|
150
|
+
test_files:
|
151
|
+
- spec/almicube/aggregator/sum_aggregator_spec.rb
|
152
|
+
- spec/almicube/builder_sprc.rb
|
153
|
+
- spec/almicube/bundler/days_ago_bundler_spec.rb
|
154
|
+
- spec/almicube/bundler/today_bundler_spec.rb
|
155
|
+
- spec/almicube/bundler/yesterday_bundler_spec.rb
|
156
|
+
- spec/almicube/config_spec.rb
|
157
|
+
- spec/almicube/key_spec.rb
|
158
|
+
- spec/almicube/ranking/base_spec.rb
|
159
|
+
- spec/almicube/ranking/data_ranking_spec.rb
|
160
|
+
- spec/almicube/ranking/sub_ranking_spec.rb
|
161
|
+
- spec/almicube/selector/all_selector_spec.rb
|
162
|
+
- spec/almicube/selector/method_selector_spec.rb
|
163
|
+
- spec/almicube/selector/mock_spec.rb
|
164
|
+
- spec/mocks/aggregator.rb
|
165
|
+
- spec/mocks/bundler.rb
|
166
|
+
- spec/mocks/model.rb
|
167
|
+
- spec/mocks/selector.rb
|
168
|
+
- spec/spec_helper.rb
|
169
|
+
- spec/supports/shared_examples.rb
|
@@ -1,35 +0,0 @@
|
|
1
|
-
module Almicube
|
2
|
-
module Builder
|
3
|
-
class AverageRankingBuilder
|
4
|
-
extend Base
|
5
|
-
|
6
|
-
register :average
|
7
|
-
|
8
|
-
def initialize(options)
|
9
|
-
@options = self.default_options.merge(options)
|
10
|
-
end
|
11
|
-
|
12
|
-
def default_options
|
13
|
-
{ ranking_class: Almicube::Ranking, aggregate: :std }
|
14
|
-
end
|
15
|
-
|
16
|
-
def build(date)
|
17
|
-
ranking_class.new(ranking_options(date))
|
18
|
-
end
|
19
|
-
|
20
|
-
protected
|
21
|
-
|
22
|
-
RANKING_OPTIONS = %i[class_name as date_format attribute_name per_page aggregate default_score]
|
23
|
-
|
24
|
-
def ranking_options(date = Date.today)
|
25
|
-
( @options.select{ |k| self.class::RANKING_OPTIONS.include? k } ).merge( date: date )
|
26
|
-
end
|
27
|
-
|
28
|
-
%i[ranking_class].each do |name|
|
29
|
-
define_method(name) do
|
30
|
-
@options[name]
|
31
|
-
end
|
32
|
-
end
|
33
|
-
end
|
34
|
-
end
|
35
|
-
end
|
@@ -1,35 +0,0 @@
|
|
1
|
-
module Almicube
|
2
|
-
module Builder
|
3
|
-
class CountableRankingBuilder
|
4
|
-
extend Base
|
5
|
-
|
6
|
-
register :countable
|
7
|
-
|
8
|
-
def initialize(options)
|
9
|
-
@options = self.default_options.merge(options)
|
10
|
-
end
|
11
|
-
|
12
|
-
def default_options
|
13
|
-
{ ranking_class: Almicube::Ranking, aggregate: :sum }
|
14
|
-
end
|
15
|
-
|
16
|
-
def build(date)
|
17
|
-
ranking_class.new(ranking_options(date))
|
18
|
-
end
|
19
|
-
|
20
|
-
protected
|
21
|
-
|
22
|
-
RANKING_OPTIONS = %i[class_name as date_format attribute_name per_page aggregate default_score]
|
23
|
-
|
24
|
-
def ranking_options(date = Date.today)
|
25
|
-
( @options.select{ |k| self.class::RANKING_OPTIONS.include? k } ).merge( date: date )
|
26
|
-
end
|
27
|
-
|
28
|
-
%i[ranking_class].each do |name|
|
29
|
-
define_method(name) do
|
30
|
-
@options[name]
|
31
|
-
end
|
32
|
-
end
|
33
|
-
end
|
34
|
-
end
|
35
|
-
end
|
@@ -1,57 +0,0 @@
|
|
1
|
-
module Almicube
|
2
|
-
class RangedRanking < Almicube::Ranking
|
3
|
-
class << self
|
4
|
-
def overwrite_params
|
5
|
-
{ key: '%{prefix}:%{class_name}:%{range}:%{suffix}', type: :range }
|
6
|
-
end
|
7
|
-
end
|
8
|
-
|
9
|
-
def aggregate(options={})
|
10
|
-
keys = range_days(range).times.inject([]) do |keys, i|
|
11
|
-
key = key_format(@options[:data_key], @options.merge( date: date.to_date - i.days, type: :data ))
|
12
|
-
keys << key if connection.exists key
|
13
|
-
keys
|
14
|
-
end
|
15
|
-
if %i[sum max min].include? aggregate_method
|
16
|
-
connection.zunionstore key, keys, aggregate: aggregate_method
|
17
|
-
elsif aggregate_method == :std
|
18
|
-
weights = Array.new keys.length, (1.0/keys.length)
|
19
|
-
connection.zunionstore key, keys, aggregate: :sum, weights: weights
|
20
|
-
else
|
21
|
-
connection.zunionstore key, keys, aggregate: :sum
|
22
|
-
end
|
23
|
-
end
|
24
|
-
|
25
|
-
def date
|
26
|
-
super - 1.days
|
27
|
-
end
|
28
|
-
|
29
|
-
def range
|
30
|
-
@options.fetch(:range, default_range)
|
31
|
-
end
|
32
|
-
|
33
|
-
def default_range
|
34
|
-
:weekly
|
35
|
-
end
|
36
|
-
|
37
|
-
def aggregate_method
|
38
|
-
aggregate = @options.fetch(:aggregate, :sum)
|
39
|
-
end
|
40
|
-
|
41
|
-
protected
|
42
|
-
|
43
|
-
def range_days(range, default = nil)
|
44
|
-
case range.to_sym
|
45
|
-
when :yesterday
|
46
|
-
1
|
47
|
-
when :weekly
|
48
|
-
7
|
49
|
-
when :monthly
|
50
|
-
30
|
51
|
-
else
|
52
|
-
return default unless default.nil?
|
53
|
-
range_days(default_range, 7)
|
54
|
-
end
|
55
|
-
end
|
56
|
-
end
|
57
|
-
end
|
data/lib/almicube/ranking.rb
DELETED
@@ -1,134 +0,0 @@
|
|
1
|
-
require "redis"
|
2
|
-
require "active_support/all"
|
3
|
-
|
4
|
-
module Almicube
|
5
|
-
class Ranking
|
6
|
-
class << self
|
7
|
-
def default_options
|
8
|
-
{ attribute_name: :score,
|
9
|
-
type: :data,
|
10
|
-
prefix: 'ranking:%{type}',
|
11
|
-
suffix: '%{attribute_name}',
|
12
|
-
key: '%{prefix}:%{class_name}:%{date}:%{suffix}',
|
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 connection
|
22
|
-
@connection ||= Redis.new
|
23
|
-
end
|
24
|
-
|
25
|
-
def build(options={})
|
26
|
-
self.new options
|
27
|
-
end
|
28
|
-
end
|
29
|
-
|
30
|
-
def initialize(options={})
|
31
|
-
@options = self.class.default_options.merge options.symbolize_keys
|
32
|
-
|
33
|
-
raise TypeError, ":as option is only allowed Integer or Float" unless [Integer, Float].include? @options[:as]
|
34
|
-
end
|
35
|
-
|
36
|
-
def ranged(range)
|
37
|
-
Almicube::RangedRanking.new @options.merge( range: range, data_key: @options[:key] ).merge(Almicube::RangedRanking.overwrite_params)
|
38
|
-
end
|
39
|
-
|
40
|
-
KEY_PATTERN = /%{([a-z_]+)}/ # Example) %{sample_key}
|
41
|
-
|
42
|
-
def key
|
43
|
-
key_format(@options[:key], @options)
|
44
|
-
end
|
45
|
-
|
46
|
-
def all
|
47
|
-
target_class.all
|
48
|
-
end
|
49
|
-
|
50
|
-
def page(page=1)
|
51
|
-
page = [1, page.to_i].max
|
52
|
-
revrange = connection.zrevrange(key, (page - 1) * per_page, page * per_page - 1)
|
53
|
-
records = target_class.where("id IN (?)", revrange).all
|
54
|
-
revrange.inject([]) { |l, v| l << records.detect { |r| r.to_param == v } }
|
55
|
-
end
|
56
|
-
|
57
|
-
def attribute_name
|
58
|
-
@options.fetch(:attribute_name, :score).to_s.to_sym
|
59
|
-
end
|
60
|
-
|
61
|
-
def date
|
62
|
-
@options.fetch(:date, Date.today)
|
63
|
-
end
|
64
|
-
|
65
|
-
def per_page
|
66
|
-
@options.fetch(:per_page, 0)
|
67
|
-
end
|
68
|
-
|
69
|
-
def per_page=(value)
|
70
|
-
@options[:per_page] = value
|
71
|
-
end
|
72
|
-
|
73
|
-
def aggregate!(options = {})
|
74
|
-
overwrite = !! ( options.try(:overwrite) || false )
|
75
|
-
raise "ranking is already exists. if you want to force aggregating: set { overwrite: true }" if exists? && ! overwrite
|
76
|
-
|
77
|
-
all.each do |record|
|
78
|
-
score = @options.fetch(:default_score, 0)
|
79
|
-
score = record.send attribute_name if record.respond_to? attribute_name
|
80
|
-
connection.zadd key, score.to_f, record.to_param
|
81
|
-
end
|
82
|
-
end
|
83
|
-
|
84
|
-
def aggregate(options = {})
|
85
|
-
aggregate! options
|
86
|
-
true
|
87
|
-
rescue Exception => e
|
88
|
-
false
|
89
|
-
end
|
90
|
-
|
91
|
-
def exists?
|
92
|
-
connection.exists key
|
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 connection
|
118
|
-
self.class.connection
|
119
|
-
end
|
120
|
-
|
121
|
-
def target_class
|
122
|
-
@options[:class_name].to_s.constantize
|
123
|
-
end
|
124
|
-
|
125
|
-
def key_format(key_base, options)
|
126
|
-
key = key_base.to_s.clone
|
127
|
-
tmp_options = options.merge date: options.fetch(:date, Date.today).strftime(@options[:date_format])
|
128
|
-
key.match( self.class::KEY_PATTERN ) do |m|
|
129
|
-
key.gsub! m[0], tmp_options.fetch(m[1].to_sym, '').to_s
|
130
|
-
end while key =~ self.class::KEY_PATTERN
|
131
|
-
key
|
132
|
-
end
|
133
|
-
end
|
134
|
-
end
|