class ActiveCohort
Public: Provides a cohort analysis of a set of ActiveRecord objects. Intended to be consumed by domain-specific classes, such AigAnalyst, OrderAnalyst, etc. See the constructor’s documentation for information on the options hash.
Examples
cohort = ActiveCohort.new(some_options_hash) cohort.generate_report # => [["", "Week 0", "Week 1", "Week 2", "Week 3", "Week 4", "Week 5"], ["1/9", "27.0%", "8.1%", "2.7%", "0.0%", "0.0%", "0.0%"], ["1/16", "37.9%", "7.6%", "0.0%", "0.0%", "0.0%"], ["1/23", "42.2%", "3.1%", "0.0%", "0.0%"], ["1/30", "31.8%", "0.0%", "0.0%"], ["2/6", "-", "-"]] puts cohort.to_csv # => ,Week 0,Week 1,Week 2,Week 3,Week 4,Week 5 1/9,27.0%,8.1%,2.7%,0.0%,0.0%,0.0% 1/16,37.9%,7.6%,0.0%,0.0%,0.0% 1/23,42.2%,3.1%,0.0%,0.0% 1/30,31.8%,0.0%,0.0% 2/6,-,-
Attributes
activation_lambda[RW]
interval_timestamp_field[W]
start_at[W]
subject_collection[RW]
Public Class Methods
new(subject_collection, activation_lambda, opts={})
click to toggle source
Public: Initialize a ActiveCohort
.
Required params
subject_collection - An ActiveRecord collection of records to perform a cohort analysis on. activation_lambda - A lambda that returns a boolean indicating whether a given record has activated (e.g., converted, signed up, purchased, etc.) opts - A String naming the widget. start_at - The date at which to begin the analysis. Default: 30 days ago. interval - A string representation of the interval to run the analysis over (e.g, day, week, etc.) For instance, 'week' would result in a week-over-week analysis. Default: 'day'. interval_timestamp_field - A String representation of the timestamp field on the cohort records to be used to offset between intervals. Default: 'created_at'.
# File lib/active_cohort.rb, line 46 def initialize(subject_collection, activation_lambda, opts={}) @subject_collection = subject_collection @activation_lambda = activation_lambda opts.each { |k,v| instance_variable_set("@#{k}", v) } end
Public Instance Methods
generate_report()
click to toggle source
Public: Generates a cohort report using params supplied to the instance in the constructor.
Example
cohort.generate_report # => [["", "Week 0", "Week 1", "Week 2", "Week 3", "Week 4", "Week 5"], ["1/9", "27.0%", "8.1%", "2.7%", "0.0%", "0.0%", "0.0%"], ["1/16", "37.9%", "7.6%", "0.0%", "0.0%", "0.0%"], ["1/23", "42.2%", "3.1%", "0.0%", "0.0%"], ["1/30", "31.8%", "0.0%", "0.0%"], ["2/6", "-", "-"]]
Returns an Array of values representing the report.
# File lib/active_cohort.rb, line 85 def generate_report validate_required_fields @report = [] @report << header (number_of_intervals - 1).times do |row| @report << build_row(row) end @report end
interval()
click to toggle source
# File lib/active_cohort.rb, line 52 def interval @interval || 'day' end
interval=(interval)
click to toggle source
# File lib/active_cohort.rb, line 56 def interval=(interval) unless interval.downcase.in? valid_intervals raise "The interval \"#{interval}\" isn't valid.\n" + "Use #{valid_intervals.join ', '}" end @interval = interval.downcase end
interval_timestamp_field()
click to toggle source
# File lib/active_cohort.rb, line 68 def interval_timestamp_field @interval_timestamp_field || 'created_at' end
start_at()
click to toggle source
# File lib/active_cohort.rb, line 64 def start_at @start_at || 30.days.ago end
to_csv(seperator=',')
click to toggle source
Public: Outputs the cohort report in CSV format. Does not regenerate the report if the instance has already generated it.
Example
puts cohort.to_csv # => ,Week 0,Week 1,Week 2,Week 3,Week 4,Week 5 1/9,27.0%,8.1%,2.7%,0.0%,0.0%,0.0% 1/16,37.9%,7.6%,0.0%,0.0%,0.0% 1/23,42.2%,3.1%,0.0%,0.0% 1/30,31.8%,0.0%,0.0% 2/6,-,-
Returns a String representation of the report with CSV formatting.
# File lib/active_cohort.rb, line 109 def to_csv(seperator=',') report = @report || generate_report report.map{ |row| row.join(seperator) }.join("\n") end
Private Instance Methods
assemble_cohort(start_date, end_date)
click to toggle source
# File lib/active_cohort.rb, line 131 def assemble_cohort(start_date, end_date) @subject_collection.where( @interval_timestamp_field.to_sym => start_date..end_date ) end
build_row(row)
click to toggle source
# File lib/active_cohort.rb, line 148 def build_row(row) row_values = [] row_offset = row.send(:"#{interval}") cohort_start_date = (start_at + row_offset).send(:"beginning_of_#{interval}") cohort_end_date = cohort_start_date.send(:"end_of_#{interval}") cohort = assemble_cohort cohort_start_date, cohort_end_date row_values << cohort_start_date.strftime("%-m/%-d") (number_of_intervals - row).times do |col| activation_start_date = start_date_for_cell(row, col) activation_end_date = activation_start_date.send(:"end_of_#{interval}") activated = cohort.select { |c| @activation_lambda.call(c, activation_start_date, activation_end_date) } row_values << percentage_as_string(activated.length, cohort.length) end row_values end
header()
click to toggle source
# File lib/active_cohort.rb, line 115 def header header = [''] number_of_intervals.times do |i| header << "#{interval.capitalize} #{i}" end header end
number_of_intervals()
click to toggle source
# File lib/active_cohort.rb, line 123 def number_of_intervals @interval == 'day' ? 30 : 6 end
percentage_as_string(numerator, denominator)
click to toggle source
# File lib/active_cohort.rb, line 137 def percentage_as_string(numerator, denominator) return "-" if denominator.zero? "#{((numerator / denominator.to_f) * 100).round(1)}%" end
start_date_for_cell(row, col)
click to toggle source
# File lib/active_cohort.rb, line 142 def start_date_for_cell(row, col) row_offset = row.send(:"#{interval}") col_offset = col.send(:"#{interval}") (start_at + row_offset + col_offset).send(:"beginning_of_#{interval}") end
valid_intervals()
click to toggle source
# File lib/active_cohort.rb, line 127 def valid_intervals %w(day week month) end
validate_required_fields()
click to toggle source
# File lib/active_cohort.rb, line 164 def validate_required_fields raise "Missing subject_collection" unless subject_collection.present? raise "Missing activation_lambda" unless activation_lambda.present? end