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
@@ -0,0 +1,32 @@
|
|
1
|
+
module Almicube
|
2
|
+
module Selector
|
3
|
+
class Base
|
4
|
+
include Almicube::Cog
|
5
|
+
|
6
|
+
attr_reader :class_name
|
7
|
+
|
8
|
+
def initialize(options={})
|
9
|
+
@class_name = options[:class_name]
|
10
|
+
@class_name = class_name.constantize if class_name.is_a? String
|
11
|
+
@label = options[:label]
|
12
|
+
end
|
13
|
+
|
14
|
+
alias :model_class :class_name
|
15
|
+
|
16
|
+
def label
|
17
|
+
@label
|
18
|
+
end
|
19
|
+
|
20
|
+
def data_provider?
|
21
|
+
false
|
22
|
+
end
|
23
|
+
|
24
|
+
def before_aggregate
|
25
|
+
end
|
26
|
+
|
27
|
+
def interstore
|
28
|
+
nil
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module Almicube
|
2
|
+
module Selector
|
3
|
+
class HasManySelector < Base
|
4
|
+
|
5
|
+
attr_reader :target, :association_name
|
6
|
+
|
7
|
+
def initialize(options={})
|
8
|
+
super(options)
|
9
|
+
|
10
|
+
@target = options[:target]
|
11
|
+
@association_name = options[:association_name]
|
12
|
+
end
|
13
|
+
|
14
|
+
def records
|
15
|
+
target.send(association_name)
|
16
|
+
end
|
17
|
+
|
18
|
+
def label
|
19
|
+
"#{target.class.to_s.underscore}-#{target.to_param}"
|
20
|
+
end
|
21
|
+
|
22
|
+
def before_aggregate
|
23
|
+
records.map{ |r| r.to_param }.each do |i|
|
24
|
+
Config.config.connection.zadd(interstore_key, 0, i)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def interstore
|
29
|
+
interstore_key
|
30
|
+
end
|
31
|
+
|
32
|
+
protected
|
33
|
+
|
34
|
+
def interstore_key
|
35
|
+
_key = ranking.key
|
36
|
+
_key[:distinction] = label
|
37
|
+
_key[:suffix] = ""
|
38
|
+
_key
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module Almicube
|
2
|
+
module Selector
|
3
|
+
class MethodSelector < Base
|
4
|
+
attr_reader :accessor, :counter
|
5
|
+
|
6
|
+
def initialize(options={})
|
7
|
+
super(options)
|
8
|
+
|
9
|
+
@accessor = options[:accessor] || :all
|
10
|
+
@counter = options[:counter] || :count
|
11
|
+
|
12
|
+
raise "invalid options" unless valid?
|
13
|
+
end
|
14
|
+
|
15
|
+
def records
|
16
|
+
class_name.send(accessor)
|
17
|
+
end
|
18
|
+
|
19
|
+
def count
|
20
|
+
class_name.send(counter)
|
21
|
+
end
|
22
|
+
|
23
|
+
def valid?
|
24
|
+
validate_accessor
|
25
|
+
end
|
26
|
+
|
27
|
+
protected
|
28
|
+
|
29
|
+
def validate_accessor
|
30
|
+
class_name.class == Class && class_name.respond_to?(accessor)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
data/lib/almicube/version.rb
CHANGED
data/lib/almicube.rb
CHANGED
@@ -1,16 +1,46 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
|
1
3
|
module Almicube
|
2
|
-
|
4
|
+
module Ranking
|
5
|
+
autoload :Base, 'almicube/ranking/base'
|
6
|
+
autoload :DataRanking, 'almicube/ranking/data_ranking'
|
7
|
+
autoload :SubRanking, 'almicube/ranking/sub_ranking'
|
8
|
+
end
|
9
|
+
|
3
10
|
autoload :RangedRanking, 'almicube/ranged_ranking'
|
4
11
|
autoload :Model, 'almicube/model'
|
5
12
|
autoload :AssociationProxy, 'almicube/proxy/association_proxy'
|
13
|
+
autoload :Config, 'almicube/config'
|
14
|
+
autoload :Cog, 'almicube/cog'
|
15
|
+
autoload :Key, 'almicube/key'
|
6
16
|
|
7
17
|
autoload :Builder, 'almicube/builder'
|
8
|
-
|
9
|
-
|
10
|
-
autoload :
|
18
|
+
|
19
|
+
module Bundler
|
20
|
+
autoload :Base, 'almicube/bundler/base'
|
21
|
+
autoload :DaysAgoBundler, 'almicube/bundler/days_ago_bundler'
|
22
|
+
autoload :TodayBundler, 'almicube/bundler/today_bundler'
|
23
|
+
autoload :YesterdayBundler, 'almicube/bundler/yesterday_bundler'
|
24
|
+
autoload :WeeklyBundler, 'almicube/bundler/weekly_bundler'
|
25
|
+
end
|
26
|
+
|
27
|
+
module Selector
|
28
|
+
autoload :Base, 'almicube/selector/base'
|
29
|
+
autoload :AllSelector, 'almicube/selector/all_selector'
|
30
|
+
autoload :MethodSelector, 'almicube/selector/method_selector'
|
31
|
+
autoload :HasManySelector, 'almicube/selector/has_many_selector'
|
32
|
+
end
|
33
|
+
|
34
|
+
module Aggregator
|
35
|
+
autoload :Base, 'almicube/aggregator/base'
|
36
|
+
autoload :SumAggregator, 'almicube/aggregator/sum_aggregator'
|
11
37
|
end
|
12
38
|
|
13
39
|
if defined? ActiveRecord
|
14
40
|
ActiveRecord::Base.send :include, Almicube::Model
|
15
41
|
end
|
42
|
+
|
43
|
+
if defined? Rails
|
44
|
+
require 'almicube/engine'
|
45
|
+
end
|
16
46
|
end
|
@@ -0,0 +1,92 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Almicube::Aggregator::SumAggregator do
|
4
|
+
let(:size) { 1 }
|
5
|
+
let(:size_d) { size * 10 }
|
6
|
+
|
7
|
+
before(:all) { @connection = Redis.new }
|
8
|
+
before { @connection.flushdb }
|
9
|
+
|
10
|
+
it { expect(size).to be > 0 }
|
11
|
+
|
12
|
+
shared_examples "correct aggregation" do
|
13
|
+
before { aggregator.ranking = ranking }
|
14
|
+
|
15
|
+
it "add new sorted set" do
|
16
|
+
expect{ aggregator.aggregate }.to change{ @connection.dbsize }.by 1
|
17
|
+
end
|
18
|
+
it "has correct items" do
|
19
|
+
expect(@connection.zcard(ranking.key)).to eq 0
|
20
|
+
aggregator.aggregate
|
21
|
+
expect(@connection.zcard(ranking.key)).to eq ranking.records.count
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
context "data ranking" do
|
26
|
+
context "target attribute is score" do
|
27
|
+
let(:ranking) { double( key: "sample:score", attribute_name: :score, data?: true ) }
|
28
|
+
let(:aggregator) { described_class.new }
|
29
|
+
before do
|
30
|
+
ranking.stub(:records) { size_d.times.map { |i| double( to_param: i, score: i*10 ) } }
|
31
|
+
end
|
32
|
+
it_behaves_like "correct aggregation"
|
33
|
+
end
|
34
|
+
|
35
|
+
context "target attribute is access" do
|
36
|
+
let(:ranking) { double( key: "sample:access", attribute_name: :access, data?: true) }
|
37
|
+
let(:aggregator) { described_class.new }
|
38
|
+
before do
|
39
|
+
ranking.stub(:records) { size_d.times.map { |i| double( to_param: i, access: 1000 ) } }
|
40
|
+
end
|
41
|
+
it_behaves_like "correct aggregation"
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
context "sub ranking" do
|
46
|
+
context "target attribute is score" do
|
47
|
+
let(:ranking) { double( key: "sample:score", bundled_keys: ["sample:score:1", "sample:score:2"], attribute_name: :score, data?: false ) }
|
48
|
+
let(:aggregator) { described_class.new }
|
49
|
+
before do
|
50
|
+
ranking.stub(:records) { size_d.times.map { |i| double( to_param: i, score: i*10 ) } }
|
51
|
+
2.times.each do |i|
|
52
|
+
ranking.records.each do |record|
|
53
|
+
@connection.zadd("sample:score:#{i+1}", 20, record.to_param )
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
it_behaves_like "correct aggregation"
|
58
|
+
it "has ranking to set all score 40" do
|
59
|
+
aggregator.ranking = ranking
|
60
|
+
aggregator.aggregate
|
61
|
+
@connection.zrange("sample:score", 0, -1).each do |id|
|
62
|
+
expect(@connection.zscore("sample:score", id)).to eq 40
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
context "target attribute is access" do
|
68
|
+
let(:key) { "sample:access" }
|
69
|
+
let(:bundled_keys) { ["#{key}:1", "#{key}:2"] }
|
70
|
+
let(:ranking) { double( key: key, bundled_keys: bundled_keys, attribute_name: :access, data?: false ) }
|
71
|
+
let(:aggregator) { described_class.new }
|
72
|
+
before do
|
73
|
+
ranking.stub(:records) { size_d.times.map { |i| double( to_param: i, access: 1000 ) } }
|
74
|
+
2.times.each do |i|
|
75
|
+
ranking.records.each { |record| @connection.zadd("#{key}:#{i+1}", 1000, record.to_param ) }
|
76
|
+
end
|
77
|
+
end
|
78
|
+
it_behaves_like "correct aggregation"
|
79
|
+
it "has ranking to set all score 2000" do
|
80
|
+
aggregator.ranking = ranking
|
81
|
+
aggregator.aggregate
|
82
|
+
@connection.zrange("sample:access", 0, -1).each do |id|
|
83
|
+
expect(@connection.zscore("sample:access", id)).to eq 2000
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
it_behaves_like "ranking cog" do
|
90
|
+
let(:target) { described_class.new }
|
91
|
+
end
|
92
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Almicube::Builder do
|
4
|
+
let(:builder) { described_class.new }
|
5
|
+
|
6
|
+
describe "#selector" do
|
7
|
+
describe "defaults all selector" do
|
8
|
+
it { expect(builder.selector).to be_kind_of Almicube::Selector::AllSelector }
|
9
|
+
end
|
10
|
+
|
11
|
+
describe "with class name on initializer" do
|
12
|
+
before { builder.selector = "MockSelector" }
|
13
|
+
it { expect(builder.selector).to be_kind_of MockSelector }
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
describe "#data" do
|
18
|
+
describe "returns DataRanking instance" do
|
19
|
+
it { expect(builder.data).to be_kind_of Almicube::Ranking::DataRanking }
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Almicube::Bundler::DaysAgoBundler do
|
4
|
+
let(:ranking) { Almicube::Ranking::DataRanking.new }
|
5
|
+
|
6
|
+
describe "#name" do
|
7
|
+
let(:bundler) { described_class.new range: 7 }
|
8
|
+
before { bundler.ranking = ranking }
|
9
|
+
it { expect(bundler.name).to eq :"7-days-ago" }
|
10
|
+
end
|
11
|
+
|
12
|
+
describe "#keys" do
|
13
|
+
let(:bundler) { described_class.new range: 7 }
|
14
|
+
before { bundler.ranking = ranking }
|
15
|
+
it { expect(bundler.keys.length).to eq 7 }
|
16
|
+
7.times.each do |i|
|
17
|
+
it { expect(bundler.keys[i]).to match /:#{(Date.today-(i+1).days).strftime("%Y%m%d")}:/ }
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Almicube::Bundler::TodayBundler do
|
4
|
+
let(:bundler) { described_class.new bundle: :bundle }
|
5
|
+
|
6
|
+
describe "#name" do
|
7
|
+
it { expect(bundler.name).to eq :bundle }
|
8
|
+
end
|
9
|
+
|
10
|
+
describe "#bundle" do
|
11
|
+
it { expect(bundler.bundle).to eq bundler.name }
|
12
|
+
end
|
13
|
+
|
14
|
+
describe "#active?" do
|
15
|
+
context "with ranking" do
|
16
|
+
before { bundler.ranking = double() }
|
17
|
+
it { expect(bundler).to be_active }
|
18
|
+
end
|
19
|
+
|
20
|
+
context "without ranking" do
|
21
|
+
it { expect(bundler).not_to be_active }
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Almicube::Bundler::YesterdayBundler do
|
4
|
+
describe "#name" do
|
5
|
+
let(:bundler) { described_class.new }
|
6
|
+
it { expect(bundler.name).to eq :yesterday }
|
7
|
+
end
|
8
|
+
|
9
|
+
describe "#keys" do
|
10
|
+
let(:ranking) { Almicube::Ranking::SubRanking.new(Almicube::Ranking::DataRanking.new) }
|
11
|
+
let(:bundler) { described_class.new }
|
12
|
+
before { bundler.ranking = ranking }
|
13
|
+
it { expect(bundler.keys[0]).to match /:#{(Date.today-1.days).strftime("%Y%m%d")}:/ }
|
14
|
+
it { expect(bundler.keys.length).to eq 1 }
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Almicube::Config do
|
4
|
+
before do
|
5
|
+
File.stub(:exists?).and_return(true)
|
6
|
+
YAML.stub(:load_file).and_return(test_config)
|
7
|
+
described_class.reset
|
8
|
+
end
|
9
|
+
|
10
|
+
describe "#connection" do
|
11
|
+
let(:default_param) { { url: "redis://0.0.0.0:6380/1" } }
|
12
|
+
let(:development_param) { { url: "redis://0.0.0.0:6380/15" } }
|
13
|
+
let(:test_config) do
|
14
|
+
{
|
15
|
+
connection: {
|
16
|
+
default: default_param,
|
17
|
+
development: development_param
|
18
|
+
}
|
19
|
+
}
|
20
|
+
end
|
21
|
+
|
22
|
+
context "with default connection" do
|
23
|
+
before { Redis.should_receive(:new).with( default_param ) }
|
24
|
+
it { described_class.config.connection }
|
25
|
+
end
|
26
|
+
|
27
|
+
context "with actual connection" do
|
28
|
+
before { Redis.should_receive(:new).with( development_param ) }
|
29
|
+
it { described_class.config.connection :development }
|
30
|
+
end
|
31
|
+
|
32
|
+
context "with no-exists connection" do
|
33
|
+
before { Redis.stub(:new) }
|
34
|
+
it { expect{ described_class.config.connection :noexists }.to raise_error }
|
35
|
+
end
|
36
|
+
|
37
|
+
context "already setting up default connection" do
|
38
|
+
let(:redis) { double("redis") }
|
39
|
+
before do
|
40
|
+
Redis.stub(:new).and_return(redis)
|
41
|
+
described_class.config.connection
|
42
|
+
end
|
43
|
+
it { expect(described_class.config.connection).to eq redis }
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Almicube::Key do
|
4
|
+
describe "#options" do
|
5
|
+
context "pass options through constructor" do
|
6
|
+
let(:ranking) { Almicube::Ranking::DataRanking.new }
|
7
|
+
let(:key) { described_class.new ranking, prefix: "aaa", suffix: "bbb" }
|
8
|
+
|
9
|
+
it { expect(key[:prefix]).to eq "aaa" }
|
10
|
+
it { expect(key[:suffix]).to eq "bbb" }
|
11
|
+
end
|
12
|
+
|
13
|
+
context "pass options through ranking instance" do
|
14
|
+
let(:ranking) { Almicube::Ranking::DataRanking.new prefix: "ccc", suffix: "ddd" }
|
15
|
+
let(:key) { described_class.new ranking }
|
16
|
+
|
17
|
+
it { expect(key[:prefix]).to eq "ccc" }
|
18
|
+
it { expect(key[:suffix]).to eq "ddd" }
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
describe "#to_str" do
|
23
|
+
let(:ranking) { double( options: {} ) }
|
24
|
+
let(:key) { described_class.new ranking, prefix: "aaa", suffix: "bbb" }
|
25
|
+
before { key[:type] = :built }
|
26
|
+
it { expect("#{key}").to match /^aaa:/ }
|
27
|
+
it { expect("#{key}").to match /:bbb$/ }
|
28
|
+
it { expect("#{key}").to match /:built:/ }
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,103 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
class MockAggregator < Almicube::Aggregator::Base
|
4
|
+
end
|
5
|
+
|
6
|
+
describe Almicube::Ranking::DataRanking do
|
7
|
+
describe "#selector" do
|
8
|
+
let(:ranking) { described_class.new selector: selector }
|
9
|
+
|
10
|
+
describe "sets the mock selector" do
|
11
|
+
let(:selector) { MockSelector.new records: records }
|
12
|
+
let(:records) { [double(), double()] }
|
13
|
+
it { expect(ranking.records).to eq records }
|
14
|
+
it { expect(ranking.selector).to eq selector }
|
15
|
+
end
|
16
|
+
|
17
|
+
describe "does not set the selector" do
|
18
|
+
let(:selector) { nil }
|
19
|
+
it { expect(ranking.selector).to be_kind_of Almicube::Selector::AllSelector }
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
describe "#aggregator" do
|
24
|
+
let(:ranking) { described_class.new aggregator: aggregator }
|
25
|
+
|
26
|
+
describe "set the mock aggregator" do
|
27
|
+
let(:aggregator) { MockAggregator.new }
|
28
|
+
before { aggregator.should_receive(:aggregate).with(ranking) }
|
29
|
+
it { ranking.aggregate }
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
describe "#per_page" do
|
34
|
+
let(:ranking) { described_class.new per_page: 10 }
|
35
|
+
it { expect(ranking.per_page).to eq 10 }
|
36
|
+
end
|
37
|
+
|
38
|
+
describe "#class_name" do
|
39
|
+
let(:ranking) { described_class.new class_name: MockModel }
|
40
|
+
it { expect(ranking.class_name).to eq MockModel }
|
41
|
+
end
|
42
|
+
|
43
|
+
describe "#data?" do
|
44
|
+
let(:ranking) { described_class.new }
|
45
|
+
it { expect(ranking).to be_data }
|
46
|
+
end
|
47
|
+
|
48
|
+
describe "#key" do
|
49
|
+
context "with prefix and suffix" do
|
50
|
+
let(:ranking) { described_class.new prefix: "aaa", suffix: "bbb" }
|
51
|
+
it { expect(ranking.key).to match /^aaa:/ }
|
52
|
+
it { expect(ranking.key).to match /:bbb$/ }
|
53
|
+
end
|
54
|
+
|
55
|
+
describe "differents between two days data" do
|
56
|
+
let(:today) { Date.today }
|
57
|
+
let(:ranking1) { described_class.new date: today }
|
58
|
+
let(:ranking2) { described_class.new date: today - 1.days }
|
59
|
+
|
60
|
+
it { expect(ranking1.key).to match /#{today.strftime("%Y%m%d")}/ }
|
61
|
+
it { expect(ranking1.key).to_not match /#{ranking2.key}/ }
|
62
|
+
end
|
63
|
+
|
64
|
+
describe "include class name" do
|
65
|
+
let(:ranking) { described_class.new class_name: MockModel }
|
66
|
+
|
67
|
+
it { expect(ranking.key).to match /#{MockModel.to_s}/ }
|
68
|
+
end
|
69
|
+
|
70
|
+
describe "include attribute name" do
|
71
|
+
let(:ranking) { described_class.new attribute_name: :score }
|
72
|
+
|
73
|
+
it { expect(ranking.key).to match /score/ }
|
74
|
+
end
|
75
|
+
|
76
|
+
describe "include data flag" do
|
77
|
+
context "without specific selector" do
|
78
|
+
let(:ranking) { described_class.new }
|
79
|
+
|
80
|
+
it { expect(ranking.key).to match /:data:/ }
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
describe "exclude bundler name" do
|
85
|
+
let(:ranking) { described_class.new bundler: MockBundler.new }
|
86
|
+
|
87
|
+
it { expect(ranking.key).not_to match /bundle/ }
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
describe "#options" do
|
92
|
+
let(:ranking) { described_class.new }
|
93
|
+
let(:options) { ranking.options }
|
94
|
+
|
95
|
+
%i[selector aggregator date per_page prefix suffix].each do |key|
|
96
|
+
it { expect(options).to have_key key }
|
97
|
+
end
|
98
|
+
|
99
|
+
%i[type].each do |key|
|
100
|
+
it { expect(options).not_to have_key key }
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Almicube::Ranking::SubRanking do
|
4
|
+
let(:data_selector) { MockSelector.new }
|
5
|
+
let(:data_ranking) { Almicube::Ranking::DataRanking.new( selector: data_selector ) }
|
6
|
+
|
7
|
+
describe "#key" do
|
8
|
+
let(:ranking) { described_class.new(data_ranking, bundler: bundler) }
|
9
|
+
let(:bundler) { double( bundle: :bundled ) }
|
10
|
+
|
11
|
+
it { expect(ranking.key).not_to match /:data:/ }
|
12
|
+
it { expect(ranking.key).to match /:built:/ }
|
13
|
+
it { expect(ranking.key).to match /:bundled$/ }
|
14
|
+
end
|
15
|
+
|
16
|
+
describe "#selector" do
|
17
|
+
context "uses optional selector" do
|
18
|
+
let(:selector) { double( records: [] ) }
|
19
|
+
let(:ranking) { described_class.new(data_ranking, selector: selector) }
|
20
|
+
it { expect(ranking.selector).to eq selector }
|
21
|
+
end
|
22
|
+
|
23
|
+
context "uses selector on data ranking" do
|
24
|
+
let(:ranking) { described_class.new(data_ranking) }
|
25
|
+
it { expect(ranking.selector).to eq data_selector }
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
describe "#records" do
|
30
|
+
let(:selector) { double( records: ["a", "b"] ) }
|
31
|
+
let(:ranking) { described_class.new(data_ranking, selector: selector) }
|
32
|
+
it { expect(ranking.records).to eq selector.records }
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Almicube::Selector::AllSelector do
|
4
|
+
let(:ranking) { double( class_name: MockModel ) }
|
5
|
+
|
6
|
+
describe "#data_probider?" do
|
7
|
+
it { expect(described_class.new).to be_data_provider }
|
8
|
+
end
|
9
|
+
|
10
|
+
describe "#records" do
|
11
|
+
let(:selector) { described_class.new }
|
12
|
+
before { selector.ranking = ranking }
|
13
|
+
it "should send :all an instance of MockModel" do
|
14
|
+
MockModel.should_receive(:all)
|
15
|
+
selector.records
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
it_behaves_like "ranking cog" do
|
20
|
+
let(:target) { described_class.new }
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'mocks/model'
|
3
|
+
|
4
|
+
describe Almicube::Selector::MethodSelector do
|
5
|
+
describe "#initialize" do
|
6
|
+
it { expect{ described_class.new }.to raise_error }
|
7
|
+
it { expect{ described_class.new class_name: "UnknownClassName" }.to raise_error }
|
8
|
+
it { expect{ described_class.new accessor: :invalid, class_name: MockModelForSelector }.to raise_error }
|
9
|
+
it { expect{ described_class.new accessor: :all, class_name: MockModelForSelector }.to_not raise_error }
|
10
|
+
end
|
11
|
+
|
12
|
+
describe "#records" do
|
13
|
+
context "setted accessor method is all" do
|
14
|
+
let(:selector) { described_class.new accessor: :all, class_name: MockModelForSelector }
|
15
|
+
let(:records) { [double(), double()] }
|
16
|
+
before { MockModelForSelector.should_receive(:all).and_return(records) }
|
17
|
+
it { expect(selector.records).to eq records }
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
describe "#count" do
|
22
|
+
context "setted counter method is count" do
|
23
|
+
let(:selector) { described_class.new counter: :count, class_name: MockModelForSelector }
|
24
|
+
let(:count) { 100 }
|
25
|
+
before { MockModelForSelector.should_receive(:count).and_return(count) }
|
26
|
+
it { expect(selector.count).to eq count }
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
describe "default accessor" do
|
31
|
+
let(:selector) { described_class.new class_name: MockModelForSelector }
|
32
|
+
it { expect(selector.accessor).to eq :all }
|
33
|
+
end
|
34
|
+
|
35
|
+
describe "default counter" do
|
36
|
+
let(:selector) { described_class.new class_name: MockModelForSelector }
|
37
|
+
it { expect(selector.counter).to eq :count }
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'mocks/model'
|
3
|
+
|
4
|
+
describe Almicube::Selector::Base do
|
5
|
+
describe "#records" do
|
6
|
+
let(:selector) { described_class.new }
|
7
|
+
it { expect{ selector.records }.to raise_error }
|
8
|
+
end
|
9
|
+
|
10
|
+
describe "#initialize" do
|
11
|
+
let(:selector) { described_class.new options }
|
12
|
+
describe "with class_name" do
|
13
|
+
let(:options) { { class_name: MockModelForSelector } }
|
14
|
+
it { expect(selector.class_name).to eq MockModelForSelector }
|
15
|
+
it { expect(selector.model_class).to eq MockModelForSelector }
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
describe "#label" do
|
20
|
+
let(:selector) { described_class.new options }
|
21
|
+
describe "with label" do
|
22
|
+
let(:options) { { label: :sample } }
|
23
|
+
it { expect(selector.label).to eq :sample }
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
describe "#data_provider?" do
|
28
|
+
let(:selector) { described_class.new options }
|
29
|
+
describe "is false" do
|
30
|
+
let(:options) { {} }
|
31
|
+
it { expect(selector).to_not be_data_provider }
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|