Module: Statistics::HasStats
- Defined in:
- lib/statistics.rb
Overview
This extension provides the ability to define statistics for reporting purposes
Instance Method Summary collapse
-
#define_calculated_statistic(name, &block) ⇒ Object
Defines a statistic using a block that has access to all other defined statistics.
-
#define_statistic(name, options) ⇒ Object
OPTIONS:.
-
#filter_all_stats_on(name, cond) ⇒ Object
to keep things DRY anything that all statistics need to be filterable by can be defined seperatly using this method.
-
#get_stat(stat_name, filters = {}) ⇒ Object
returns a single statistic based on the
stat_name
paramater passed in and similarly to thestatistics
method, it also can take filters. -
#statistics(filters = {}, except = nil) ⇒ Object
Calculates all the statistics defined for this AR class and returns a hash with the values.
-
#statistics_keys ⇒ Object
returns an array containing the names/keys of all defined statistics.
Instance Method Details
#define_calculated_statistic(name, &block) ⇒ Object
Defines a statistic using a block that has access to all other defined statistics
EXAMPLE: class MockModel < ActiveRecord::Base
define_statistic "Basic Count", :count => :all
define_statistic "Basic Sum", :sum => :all, :column_name => 'amount'
define_calculated_statistic "Total Profit"
defined_stats('Basic Sum') * defined_stats('Basic Count')
end
105 106 107 108 109 110 111 112 113 114 115 116 117 |
# File 'lib/statistics.rb', line 105 def define_calculated_statistic(name, &block) method_name = name.to_s.gsub(" ", "").underscore + "_stat" @statistics ||= {} @statistics[name] = method_name (class<<self; self; end).instance_eval do define_method(method_name) do |filters| @filters = filters yield end end end |
#define_statistic(name, options) ⇒ Object
OPTIONS:
-
average
,count
,sum
,maximum
,minimum
- Only one of these keys is passed, which one depends on the type of operation. The value is an array of named scopes to scope the operation by (:all
should be used if no scopes are to be applied) -
column_name
- The SQL column to perform the operation on (default:id
) -
filter_on
- A hash with keys that represent filters. The with values in the has are rules on how to generate the query for the correspond filter. -
cached_for
- A duration for how long to cache this specific statisticAdditional options can also be passed in that would normally be passed to an ActiveRecord
calculate
call, likeconditions
,joins
, etc
EXAMPLE:
class MockModel < ActiveRecord::Base
named_scope :my_scope, :conditions => 'value > 5'
define_statistic "Basic Count", :count => :all
define_statistic "Basic Sum", :sum => :all, :column_name => 'amount'
define_statistic "Chained Scope Count", :count => [:all, :my_scope]
define_statistic "Default Filter", :count => :all
define_statistic "Custom Filter", :count => :all, :filter_on => { :channel => 'channel = ?', :start_date => 'DATE(created_at) > ?' }
define_statistic "Cached", :count => :all, :filter_on => { :channel => 'channel = ?', :blah => 'blah = ?' }, :cache_for => 1.second
end
45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 |
# File 'lib/statistics.rb', line 45 def define_statistic(name, ) method_name = name.to_s.gsub(" ", "").underscore + "_stat" @statistics ||= {} @filter_all_on ||= ActiveRecord::Base.instance_eval { @filter_all_on } @statistics[name] = method_name = { :column_name => :id }.merge() calculation = .keys.find {|opt| Statistics::supported_calculations.include?(opt)} calculation ||= :count # We must use the metaclass here to metaprogrammatically define a class method (class<<self; self; end).instance_eval do define_method(method_name) do |filters| # check the cache before running a query for the stat cached_val = Rails.cache.read("#{self.name}#{method_name}#{filters}") if [:cache_for] return cached_val unless cached_val.nil? = Marshal.load(Marshal.dump()) filters.each do |key, value| unless value.nil? sql = ((@filter_all_on || {}).merge([:filter_on] || {}))[key].gsub("?", "'#{value}'") sql = sql.gsub("%t", "#{table_name}") sql_frag = send(:sanitize_sql_for_conditions, sql) case when sql_frag.nil? then nil when [:conditions].nil? then [:conditions] = sql_frag when [:conditions].is_a?(Array) then [:conditions][0].concat(" AND #{sql_frag}") when [:conditions].is_a?(String) then [:conditions].concat(" AND #{sql_frag}") end end end if filters.is_a?(Hash) base = self # chain named scopes scopes = Array([calculation]) scopes.each do |scope| base = base.send(scope) end if scopes != [:all] stat_value = base.send(calculation, [:column_name], ()) # cache stat value Rails.cache.write("#{self.name}#{method_name}#{filters}", stat_value, :expires_in => [:cache_for]) if [:cache_for] stat_value end end end |
#filter_all_stats_on(name, cond) ⇒ Object
to keep things DRY anything that all statistics need to be filterable by can be defined seperatly using this method
EXAMPLE:
class MockModel < ActiveRecord::Base
define_statistic "Basic Count", :count => :all
define_statistic "Basic Sum", :sum => :all, :column_name => 'amount'
filter_all_stats_on(:user_id, "user_id = ?")
end
158 159 160 161 |
# File 'lib/statistics.rb', line 158 def filter_all_stats_on(name, cond) @filter_all_on ||= {} @filter_all_on[name] = cond end |
#get_stat(stat_name, filters = {}) ⇒ Object
returns a single statistic based on the stat_name
paramater passed in and similarly to the statistics
method, it also can take filters.
EXAMPLE: MockModel.get_stat(‘Basic Count’) MockModel.get_stat(‘Basic Count’, :user_type => ‘registered’, :user_status => ‘active’)
143 144 145 |
# File 'lib/statistics.rb', line 143 def get_stat(stat_name, filters = {}) send(@statistics[stat_name], filters) if @statistics[stat_name] end |
#statistics(filters = {}, except = nil) ⇒ Object
Calculates all the statistics defined for this AR class and returns a hash with the values. There is an optional parameter that is a hash of all values you want to filter by.
EXAMPLE: MockModel.statistics MockModel.statistics(:user_type => ‘registered’, :user_status => ‘active’)
130 131 132 133 134 135 |
# File 'lib/statistics.rb', line 130 def statistics(filters = {}, except = nil) (@statistics || {}).inject({}) do |stats_hash, stat| stats_hash[stat.first] = send(stat.last, filters) if stat.last != except stats_hash end end |
#statistics_keys ⇒ Object
returns an array containing the names/keys of all defined statistics
120 121 122 |
# File 'lib/statistics.rb', line 120 def statistics_keys @statistics.keys end |