almicube 0.0.2 → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (51) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile.lock +44 -0
  3. data/Rakefile +6 -0
  4. data/almicube.gemspec +3 -0
  5. data/lib/almicube/aggregator/base.rb +25 -0
  6. data/lib/almicube/aggregator/sum_aggregator.rb +23 -0
  7. data/lib/almicube/builder.rb +27 -30
  8. data/lib/almicube/bundler/base.rb +18 -0
  9. data/lib/almicube/bundler/days_ago_bundler.rb +22 -0
  10. data/lib/almicube/bundler/today_bundler.rb +9 -0
  11. data/lib/almicube/bundler/weekly_bundler.rb +11 -0
  12. data/lib/almicube/bundler/yesterday_bundler.rb +16 -0
  13. data/lib/almicube/cog.rb +11 -0
  14. data/lib/almicube/config.rb +40 -0
  15. data/lib/almicube/engine.rb +6 -0
  16. data/lib/almicube/key.rb +46 -0
  17. data/lib/almicube/model.rb +2 -5
  18. data/lib/almicube/proxy/association_proxy.rb +1 -1
  19. data/lib/almicube/ranking/base.rb +63 -0
  20. data/lib/almicube/ranking/data_ranking.rb +128 -0
  21. data/lib/almicube/ranking/sub_ranking.rb +51 -0
  22. data/lib/almicube/selector/all_selector.rb +18 -0
  23. data/lib/almicube/selector/base.rb +32 -0
  24. data/lib/almicube/selector/has_many_selector.rb +42 -0
  25. data/lib/almicube/selector/method_selector.rb +34 -0
  26. data/lib/almicube/version.rb +1 -1
  27. data/lib/almicube.rb +34 -4
  28. data/spec/almicube/aggregator/sum_aggregator_spec.rb +92 -0
  29. data/spec/almicube/builder_sprc.rb +22 -0
  30. data/spec/almicube/bundler/days_ago_bundler_spec.rb +20 -0
  31. data/spec/almicube/bundler/today_bundler_spec.rb +24 -0
  32. data/spec/almicube/bundler/yesterday_bundler_spec.rb +16 -0
  33. data/spec/almicube/config_spec.rb +46 -0
  34. data/spec/almicube/key_spec.rb +30 -0
  35. data/spec/almicube/ranking/base_spec.rb +9 -0
  36. data/spec/almicube/ranking/data_ranking_spec.rb +103 -0
  37. data/spec/almicube/ranking/sub_ranking_spec.rb +34 -0
  38. data/spec/almicube/selector/all_selector_spec.rb +22 -0
  39. data/spec/almicube/selector/method_selector_spec.rb +39 -0
  40. data/spec/almicube/selector/mock_spec.rb +34 -0
  41. data/spec/mocks/aggregator.rb +2 -0
  42. data/spec/mocks/bundler.rb +5 -0
  43. data/spec/mocks/model.rb +17 -0
  44. data/spec/mocks/selector.rb +9 -0
  45. data/spec/spec_helper.rb +11 -0
  46. data/spec/supports/shared_examples.rb +22 -0
  47. metadata +89 -7
  48. data/lib/almicube/builder/average_ranking_builder.rb +0 -35
  49. data/lib/almicube/builder/countable_ranking_builder.rb +0 -35
  50. data/lib/almicube/ranged_ranking.rb +0 -57
  51. data/lib/almicube/ranking.rb +0 -134
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: f5974ef075edf11c09d6e8c44485968661fcc8a5
4
- data.tar.gz: ff7ca640f98417dc29d755aa314a57a8ebefca42
3
+ metadata.gz: 3b5b3dee4cf2a4ca349f8b5d218fe23cbb6fbb7c
4
+ data.tar.gz: d5423d3770485d8176bd9cb0ac306e0ed2e32ac0
5
5
  SHA512:
6
- metadata.gz: 999950f31e8406189ebfce9726f6c5a6b99f7d4c389bb54e644dbcc9538d30c16e50169c449b35cbb86ce2cd3b3e214166a3c1acc0b2fd0b95d77d06c825f001
7
- data.tar.gz: ae64515586232c660796d417702a84e3d72907aa0f1e89563548a44c40d04617f56c653eaca9aedf74fed83ab555bcbbf15aa6316af3aa96ddb4abfbd06f8c05
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
@@ -0,0 +1,6 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'rspec/core/rake_task'
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task default: :spec
data/almicube.gemspec CHANGED
@@ -19,4 +19,7 @@ Gem::Specification.new do |spec|
19
19
 
20
20
  spec.add_dependency "redis", "~> 3.0"
21
21
  spec.add_dependency "activesupport", "~> 4.0"
22
+ spec.add_dependency "activemodel", "~> 4.0"
23
+
24
+ spec.add_development_dependency "rspec", "~> 2.0"
22
25
  end
@@ -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
@@ -1,41 +1,38 @@
1
1
  module Almicube
2
- module Builder
3
- class << self
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
- def register(name, builder_class)
10
- raise TypeError, 'invalid builder class' unless builder_class.kind_of? Builder::Base
11
- builders[name] = builder_class
12
- end
13
-
14
- def has_builder?(name)
15
- load_builder name
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
- def builders
20
- @builders ||= {}
21
- end
13
+ def data(date=nil)
14
+ date ||= self.date
15
+ Almicube::Ranking::DataRanking.new options
16
+ end
22
17
 
23
- def load_builder(name)
24
- "Almicube::Builder::#{"#{name}_ranking_builder".classify}".constantize
25
- end
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
- module Base
29
- def self.included(base)
30
- base.include InstanceMethods
31
- end
26
+ protected
32
27
 
33
- def register(name)
34
- Builder.register(name, self)
35
- end
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
- class InstanceMethods
38
- end
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,9 @@
1
+ module Almicube
2
+ module Bundler
3
+ class TodayBundler < Base
4
+ def keys
5
+ []
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,11 @@
1
+ module Almicube
2
+ module Bundler
3
+ class WeeklyBundler < DaysAgoBundler
4
+ def initialize(options={})
5
+ options[:range] = 7
6
+ options[:name] = :weekly
7
+ super(options)
8
+ end
9
+ end
10
+ end
11
+ 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
@@ -0,0 +1,11 @@
1
+ module Almicube
2
+ module Cog
3
+ attr_accessor :ranking
4
+
5
+ def active?
6
+ ! @ranking.nil?
7
+ end
8
+
9
+ alias :has_ranking? :active?
10
+ end
11
+ end
@@ -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
@@ -0,0 +1,6 @@
1
+ module Almicube
2
+ class Engine < ::Rails::Engine
3
+ config.autoload_paths += Dir[File.join("#{config.root}", "lib", "**")] if Rails.env.development?
4
+ puts config.autoload_paths
5
+ end
6
+ end
@@ -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
@@ -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.instance(builder_name, options)
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}].build(date)
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
@@ -0,0 +1,18 @@
1
+ module Almicube
2
+ module Selector
3
+ class AllSelector < Base
4
+
5
+ def records
6
+ ranking.class_name.all
7
+ end
8
+
9
+ def label
10
+ :data
11
+ end
12
+
13
+ def data_provider?
14
+ true
15
+ end
16
+ end
17
+ end
18
+ end