ActiveCohort 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/lib/active_cohort.rb +168 -0
- metadata +44 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 8ad4bb05ec3fab6b833e77b81f463873eb86fbe1
|
4
|
+
data.tar.gz: 3c8782baa944cebc1f36ca2a209d09d920075e61
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 9b1f88caf2d8111c3f606e33eb16f08f710f3b27ade16d688ed2411b3c9455ef4a03d26f8934463d5931cae79663c2a8f6ccc840663d8ee9ab6384380565dbbd
|
7
|
+
data.tar.gz: 28d7ae8c4984b3d15d357dbd2758573363ebb9e868c790dc6fb611a83d69b6d820aaa6dc1d18ff70b72723bf51a813d0958a39c17bf36acc913fd46656ce8bf0
|
@@ -0,0 +1,168 @@
|
|
1
|
+
# Public: Provides a cohort analysis of a set of ActiveRecord objects. Intended to be
|
2
|
+
# consumed by domain-specific classes, such AigAnalyst, OrderAnalyst, etc.
|
3
|
+
# See the constructor's documentation for information on the options hash.
|
4
|
+
#
|
5
|
+
# Examples
|
6
|
+
#
|
7
|
+
# cohort = ActiveCohort.new(some_options_hash)
|
8
|
+
# cohort.generate_report
|
9
|
+
# # => [["", "Week 0", "Week 1", "Week 2", "Week 3", "Week 4", "Week 5"],
|
10
|
+
# ["1/9", "27.0%", "8.1%", "2.7%", "0.0%", "0.0%", "0.0%"],
|
11
|
+
# ["1/16", "37.9%", "7.6%", "0.0%", "0.0%", "0.0%"],
|
12
|
+
# ["1/23", "42.2%", "3.1%", "0.0%", "0.0%"],
|
13
|
+
# ["1/30", "31.8%", "0.0%", "0.0%"],
|
14
|
+
# ["2/6", "-", "-"]]
|
15
|
+
#
|
16
|
+
# puts cohort.to_csv
|
17
|
+
# # => ,Week 0,Week 1,Week 2,Week 3,Week 4,Week 5
|
18
|
+
# 1/9,27.0%,8.1%,2.7%,0.0%,0.0%,0.0%
|
19
|
+
# 1/16,37.9%,7.6%,0.0%,0.0%,0.0%
|
20
|
+
# 1/23,42.2%,3.1%,0.0%,0.0%
|
21
|
+
# 1/30,31.8%,0.0%,0.0%
|
22
|
+
# 2/6,-,-
|
23
|
+
class ActiveCohort
|
24
|
+
attr_accessor :subject_collection, :activation_lambda
|
25
|
+
attr_writer :start_at, :interval_timestamp_field
|
26
|
+
|
27
|
+
# Public: Initialize a ActiveCohort.
|
28
|
+
#
|
29
|
+
# Required params
|
30
|
+
# subject_collection - An ActiveRecord collection of records to perform a
|
31
|
+
# cohort analysis on.
|
32
|
+
# activation_lambda - A lambda that returns a boolean indicating whether
|
33
|
+
# a given record has activated (e.g., converted,
|
34
|
+
# signed up, purchased, etc.)
|
35
|
+
# opts - A String naming the widget.
|
36
|
+
# start_at - The date at which to begin the analysis.
|
37
|
+
# Default: 30 days ago.
|
38
|
+
# interval - A string representation of the interval to run the analysis
|
39
|
+
# over (e.g, day, week, etc.) For instance, 'week' would
|
40
|
+
# result in a week-over-week analysis.
|
41
|
+
# Default: 'day'.
|
42
|
+
# interval_timestamp_field - A String representation of the timestamp
|
43
|
+
# field on the cohort records to be used to
|
44
|
+
# offset between intervals.
|
45
|
+
# Default: 'created_at'.
|
46
|
+
def initialize(subject_collection, activation_lambda, opts={})
|
47
|
+
@subject_collection = subject_collection
|
48
|
+
@activation_lambda = activation_lambda
|
49
|
+
opts.each { |k,v| instance_variable_set("@#{k}", v) }
|
50
|
+
end
|
51
|
+
|
52
|
+
def interval
|
53
|
+
@interval || 'day'
|
54
|
+
end
|
55
|
+
|
56
|
+
def interval=(interval)
|
57
|
+
unless interval.downcase.in? valid_intervals
|
58
|
+
raise "The interval \"#{interval}\" isn't valid.\n" +
|
59
|
+
"Use #{valid_intervals.join ', '}"
|
60
|
+
end
|
61
|
+
@interval = interval.downcase
|
62
|
+
end
|
63
|
+
|
64
|
+
def start_at
|
65
|
+
@start_at || 30.days.ago
|
66
|
+
end
|
67
|
+
|
68
|
+
def interval_timestamp_field
|
69
|
+
@interval_timestamp_field || 'created_at'
|
70
|
+
end
|
71
|
+
|
72
|
+
# Public: Generates a cohort report using params supplied to the instance in
|
73
|
+
# the constructor.
|
74
|
+
#
|
75
|
+
# Example
|
76
|
+
# cohort.generate_report
|
77
|
+
# # => [["", "Week 0", "Week 1", "Week 2", "Week 3", "Week 4", "Week 5"],
|
78
|
+
# ["1/9", "27.0%", "8.1%", "2.7%", "0.0%", "0.0%", "0.0%"],
|
79
|
+
# ["1/16", "37.9%", "7.6%", "0.0%", "0.0%", "0.0%"],
|
80
|
+
# ["1/23", "42.2%", "3.1%", "0.0%", "0.0%"],
|
81
|
+
# ["1/30", "31.8%", "0.0%", "0.0%"],
|
82
|
+
# ["2/6", "-", "-"]]
|
83
|
+
#
|
84
|
+
# Returns an Array of values representing the report.
|
85
|
+
def generate_report
|
86
|
+
validate_required_fields
|
87
|
+
@report = []
|
88
|
+
@report << header
|
89
|
+
|
90
|
+
(number_of_intervals - 1).times do |row|
|
91
|
+
@report << build_row(row)
|
92
|
+
end
|
93
|
+
@report
|
94
|
+
end
|
95
|
+
|
96
|
+
# Public: Outputs the cohort report in CSV format. Does not regenerate the
|
97
|
+
# report if the instance has already generated it.
|
98
|
+
#
|
99
|
+
# Example
|
100
|
+
# puts cohort.to_csv
|
101
|
+
# # => ,Week 0,Week 1,Week 2,Week 3,Week 4,Week 5
|
102
|
+
# 1/9,27.0%,8.1%,2.7%,0.0%,0.0%,0.0%
|
103
|
+
# 1/16,37.9%,7.6%,0.0%,0.0%,0.0%
|
104
|
+
# 1/23,42.2%,3.1%,0.0%,0.0%
|
105
|
+
# 1/30,31.8%,0.0%,0.0%
|
106
|
+
# 2/6,-,-
|
107
|
+
#
|
108
|
+
# Returns a String representation of the report with CSV formatting.
|
109
|
+
def to_csv(seperator=',')
|
110
|
+
report = @report || generate_report
|
111
|
+
report.map{ |row| row.join(seperator) }.join("\n")
|
112
|
+
end
|
113
|
+
|
114
|
+
private
|
115
|
+
def header
|
116
|
+
header = ['']
|
117
|
+
number_of_intervals.times do |i|
|
118
|
+
header << "#{interval.capitalize} #{i}"
|
119
|
+
end
|
120
|
+
header
|
121
|
+
end
|
122
|
+
|
123
|
+
def number_of_intervals
|
124
|
+
@interval == 'day' ? 30 : 6
|
125
|
+
end
|
126
|
+
|
127
|
+
def valid_intervals
|
128
|
+
%w(day week month)
|
129
|
+
end
|
130
|
+
|
131
|
+
def assemble_cohort(start_date, end_date)
|
132
|
+
@subject_collection.where(
|
133
|
+
@interval_timestamp_field.to_sym => start_date..end_date
|
134
|
+
)
|
135
|
+
end
|
136
|
+
|
137
|
+
def percentage_as_string(numerator, denominator)
|
138
|
+
return "-" if denominator.zero?
|
139
|
+
"#{((numerator / denominator.to_f) * 100).round(1)}%"
|
140
|
+
end
|
141
|
+
|
142
|
+
def start_date_for_cell(row, col)
|
143
|
+
row_offset = row.send(:"#{interval}")
|
144
|
+
col_offset = col.send(:"#{interval}")
|
145
|
+
(start_at + row_offset + col_offset).send(:"beginning_of_#{interval}")
|
146
|
+
end
|
147
|
+
|
148
|
+
def build_row(row)
|
149
|
+
row_values = []
|
150
|
+
row_offset = row.send(:"#{interval}")
|
151
|
+
cohort_start_date = (start_at + row_offset).send(:"beginning_of_#{interval}")
|
152
|
+
cohort_end_date = cohort_start_date.send(:"end_of_#{interval}")
|
153
|
+
cohort = assemble_cohort cohort_start_date, cohort_end_date
|
154
|
+
row_values << cohort_start_date.strftime("%-m/%-d")
|
155
|
+
(number_of_intervals - row).times do |col|
|
156
|
+
activation_start_date = start_date_for_cell(row, col)
|
157
|
+
activation_end_date = activation_start_date.send(:"end_of_#{interval}")
|
158
|
+
activated = cohort.select { |c| @activation_lambda.call(c, activation_start_date, activation_end_date) }
|
159
|
+
row_values << percentage_as_string(activated.length, cohort.length)
|
160
|
+
end
|
161
|
+
row_values
|
162
|
+
end
|
163
|
+
|
164
|
+
def validate_required_fields
|
165
|
+
raise "Missing subject_collection" unless subject_collection.present?
|
166
|
+
raise "Missing activation_lambda" unless activation_lambda.present?
|
167
|
+
end
|
168
|
+
end
|
metadata
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: ActiveCohort
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Josh Saint Jacque
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2017-02-25 00:00:00.000000000 Z
|
12
|
+
dependencies: []
|
13
|
+
description: Quickly product cohort reports from active record data.
|
14
|
+
email: joshsaintjacque@gmail.com
|
15
|
+
executables: []
|
16
|
+
extensions: []
|
17
|
+
extra_rdoc_files: []
|
18
|
+
files:
|
19
|
+
- lib/active_cohort.rb
|
20
|
+
homepage: http://rubygems.org/gems/activecohort
|
21
|
+
licenses:
|
22
|
+
- MIT
|
23
|
+
metadata: {}
|
24
|
+
post_install_message:
|
25
|
+
rdoc_options: []
|
26
|
+
require_paths:
|
27
|
+
- lib
|
28
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
29
|
+
requirements:
|
30
|
+
- - ">="
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '0'
|
33
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
34
|
+
requirements:
|
35
|
+
- - ">="
|
36
|
+
- !ruby/object:Gem::Version
|
37
|
+
version: '0'
|
38
|
+
requirements: []
|
39
|
+
rubyforge_project:
|
40
|
+
rubygems_version: 2.6.6
|
41
|
+
signing_key:
|
42
|
+
specification_version: 4
|
43
|
+
summary: Cohort reports for ActiveRecord.
|
44
|
+
test_files: []
|