class Metricky::Base
Constants
- VALID_TYPES
Attributes
Public Class Methods
# File lib/metricky/ranges.rb, line 6 def self.default_range(val = nil) self.default_range_key = val end
# File lib/metricky/base.rb, line 51 def self.metric_name name.demodulize.sub(/Metric$/, "") end
# File lib/metricky/base.rb, line 8 def initialize(params, options = {}) @params = params options.each do |k,v| self.class.attr_reader k self.instance_variable_set("@#{k}", v) end @query = nil end
Rewrite the priority of a range thing.
class UserMetric
range_priority '24h', 99
end
# File lib/metricky/ranges.rb, line 15 def self.range_priority(key, priority) self.ranges[key.to_sym].priority = priority end
Register a range. Priority is used for the select order.
@param [String] key The value for the option in the select for the form @param [String] label The text shown on the option in the select for the form @param [Integer] priority What order the resulting collection @param [Block/Proc] block The Ruby-converted value. Usually a DateTime/Date/Time object.
class UserMetric
register_range '15w', label: '15 weeks', priority: 99 do 15.weeks.ago end
end
@return RangeThing
# File lib/metricky/ranges.rb, line 33 def self.register_range(key, label: nil, priority: nil, &block) label ||= key priority ||= self.ranges.size self.ranges[key.to_sym] = RangeThing.new(label, priority, block) end
# File lib/metricky/ranges.rb, line 44 def self.remove_range(key) self.ranges.delete(key.to_sym) end
Removes the listed ranges from the select
# File lib/metricky/ranges.rb, line 40 def self.remove_ranges(*keys) keys.each { self.remove_range(key) } end
Remove all ranges
# File lib/metricky/ranges.rb, line 49 def self.reset_ranges! self.ranges = {} self.default_range_key = nil end
Public Instance Methods
Must be one of Chartkick charts line_chart, pie_chart, columnchart, bar_chart, areachart, geo_chart, timeline
# File lib/metricky/base.rb, line 19 def chart :column_chart end
# File lib/metricky/base.rb, line 96 def chart? results.is_a?(Hash) || results.is_a?(Array) end
# File lib/metricky/base.rb, line 23 def chart_options @chart_options ||= {} end
# File lib/metricky/ranges.rb, line 100 def collection_label(range_thing) "#{range_thing.label}" end
Column(s) to perform the calculation on.
- :total_in_cents, :department
# File lib/metricky/base.rb, line 87 def columns 'id' end
If you have a static metric that doesn't need to be queried (e.g. average users age of all users), disable the form
# File lib/metricky/base.rb, line 92 def form? ranges.any? end
Form key
# File lib/metricky/base.rb, line 64 def form_name "#{uri_key}_metric" end
# File lib/metricky/base.rb, line 104 def group false end
# File lib/metricky/base.rb, line 108 def group? group.present? end
# File lib/metricky/base.rb, line 112 def json? false end
# File lib/metricky/base.rb, line 47 def name self.class.metric_name end
# File lib/metricky/base.rb, line 32 def noun { count: "total number of", average: "average #{columns} of", sum: "total", min: "minimum", max: "maximum" }[type.to_sym] end
How it's grouped. Leave nil if no grouping
[:second, :minute, :hour, :day, :week, :month, :quarter, :year, :day_of_week, :hour_of_day, :minute_of_hour, :day_of_month, :month_of_year]
# File lib/metricky/period.rb, line 7 def period nil end
What column to specify for the period calculation. Normally `created_at`
# File lib/metricky/period.rb, line 13 def period_column 'created_at' end
# File lib/metricky/ranges.rb, line 104 def range params.dig(form_name, :range) || default_range_key end
Used in the HTML form for the metric as the select options
# File lib/metricky/ranges.rb, line 109 def range_collection ranges.sort_by { |_, range| range.priority }.collect { |key, range_thing| [collection_label(range_thing), key] } end
What column to specify for the range calculation. Normally `created_at`
# File lib/metricky/ranges.rb, line 96 def range_column 'created_at' end
Lookup the passed range and convert it to a value for our ActiveRecord query
# File lib/metricky/ranges.rb, line 85 def range_to_value return nil if range.nil? if val = self.ranges[range.to_sym] val.value.call else raise TypeError, "invalid range #{range}. Please define it." end end
Actual result of the metric
# File lib/metricky/base.rb, line 43 def results assets end
What ActiveRecord class (or scoped class) is being used for the metric
# File lib/metricky/base.rb, line 74 def scope raise NotImplementedError, "please add a scope to your metric." end
# File lib/metricky/base.rb, line 59 def subtitle "#{noun} #{scope.model_name.human.pluralize}" end
# File lib/metricky/base.rb, line 55 def title self.class.metric_name end
# File lib/metricky/base.rb, line 100 def to_json results.chart_json end
What partial is rendered.
# File lib/metricky/base.rb, line 28 def to_partial_path '/metricky/metric' end
What kind of metric we're pulling.
Must be one of :sum, :max, :min, :average, :count
# File lib/metricky/base.rb, line 81 def type :count end
Param key
# File lib/metricky/base.rb, line 69 def uri_key self.class.metric_name.tableize end
Private Instance Methods
# File lib/metricky/base.rb, line 118 def assets @query = scope unless range_to_value.nil? @query = scope.where("#{range_column} > ?", range_to_value) end if period? && valid_period? @query = @query.group_by_period(period, period_column) elsif period? raise NameError, "period #{period} is not a valid period. Must be one of #{Groupdate::PERIODS}." end if group? @query = @query.group(group) end if valid_type? @query = @query.send(type, *columns) else raise TypeError, "#{type} is not a valid type." end if @query.is_a?(Hash) @query.transform_values! { |value| format_value(value) } else @query = format_value(@query) end @query end
# File lib/metricky/base.rb, line 148 def format_value(value) value end
# File lib/metricky/base.rb, line 144 def h @h ||= ActionController::Base.helpers end
# File lib/metricky/period.rb, line 20 def period? period.present? end
# File lib/metricky/period.rb, line 25 def valid_period? return true unless period? Groupdate::PERIODS.include?(period.to_sym) end
# File lib/metricky/base.rb, line 152 def valid_type? VALID_TYPES.include?(type.to_sym) end