class Metricky::Base

Constants

VALID_TYPES

Attributes

params[R]
query[R]

Public Class Methods

default_range(val = nil) click to toggle source
# File lib/metricky/ranges.rb, line 6
def self.default_range(val = nil)
  self.default_range_key = val
end
metric_name() click to toggle source
# File lib/metricky/base.rb, line 51
def self.metric_name
  name.demodulize.sub(/Metric$/, "")
end
new(params, options = {}) click to toggle source
# 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
range_priority(key, priority) click to toggle source

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_range(key, label: nil, priority: nil, &block) click to toggle source

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
remove_range(key) click to toggle source
# File lib/metricky/ranges.rb, line 44
def self.remove_range(key)
  self.ranges.delete(key.to_sym)
end
remove_ranges(*keys) click to toggle source

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
reset_ranges!() click to toggle source

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

chart() click to toggle source

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
chart?() click to toggle source
# File lib/metricky/base.rb, line 96
def chart?
  results.is_a?(Hash) || results.is_a?(Array)
end
chart_options() click to toggle source
# File lib/metricky/base.rb, line 23
def chart_options
  @chart_options ||= {}
end
collection_label(range_thing) click to toggle source
# File lib/metricky/ranges.rb, line 100
def collection_label(range_thing)
  "#{range_thing.label}"
end
columns() click to toggle source

Column(s) to perform the calculation on.

:total_in_cents, :department
# File lib/metricky/base.rb, line 87
def columns
  'id'
end
form?() click to toggle source

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_name() click to toggle source

Form key

# File lib/metricky/base.rb, line 64
def form_name
  "#{uri_key}_metric"
end
group() click to toggle source
# File lib/metricky/base.rb, line 104
def group
  false
end
group?() click to toggle source
# File lib/metricky/base.rb, line 108
def group?
  group.present?
end
json?() click to toggle source
# File lib/metricky/base.rb, line 112
def json?
  false
end
name() click to toggle source
# File lib/metricky/base.rb, line 47
def name
  self.class.metric_name
end
noun() click to toggle source
# 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
period() click to toggle source

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
period_column() click to toggle source

What column to specify for the period calculation. Normally `created_at`

# File lib/metricky/period.rb, line 13
def period_column
  'created_at'
end
range() click to toggle source
# File lib/metricky/ranges.rb, line 104
def range
  params.dig(form_name, :range) || default_range_key
end
range_collection() click to toggle source

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
range_column() click to toggle source

What column to specify for the range calculation. Normally `created_at`

# File lib/metricky/ranges.rb, line 96
def range_column
  'created_at'
end
range_to_value() click to toggle source

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
results() click to toggle source

Actual result of the metric

# File lib/metricky/base.rb, line 43
def results
  assets
end
scope() click to toggle source

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
subtitle() click to toggle source
# File lib/metricky/base.rb, line 59
def subtitle
  "#{noun} #{scope.model_name.human.pluralize}"
end
title() click to toggle source
# File lib/metricky/base.rb, line 55
def title
  self.class.metric_name
end
to_json() click to toggle source
# File lib/metricky/base.rb, line 100
def to_json
  results.chart_json
end
to_partial_path() click to toggle source

What partial is rendered.

# File lib/metricky/base.rb, line 28
def to_partial_path
  '/metricky/metric'
end
type() click to toggle source

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
uri_key() click to toggle source

Param key

# File lib/metricky/base.rb, line 69
def uri_key
  self.class.metric_name.tableize
end

Private Instance Methods

assets() click to toggle source
# 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
format_value(value) click to toggle source
# File lib/metricky/base.rb, line 148
def format_value(value)
  value
end
h() click to toggle source
# File lib/metricky/base.rb, line 144
def h
  @h ||= ActionController::Base.helpers
end
period?() click to toggle source
# File lib/metricky/period.rb, line 20
def period?
  period.present?
end
valid_period?() click to toggle source
# File lib/metricky/period.rb, line 25
def valid_period?
  return true unless period?
  Groupdate::PERIODS.include?(period.to_sym)
end
valid_type?() click to toggle source
# File lib/metricky/base.rb, line 152
def valid_type?
  VALID_TYPES.include?(type.to_sym)
end