cohortly 0.0.9.1 → 0.0.92

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,25 +1,58 @@
1
1
  class Cohortly::ReportsController < Cohortly::CohortlyController
2
2
  def index
3
3
  Cohortly::Metric.send :attr_accessor, :groups
4
- @metric_search = Cohortly::Metric.new(params[:cohortly_metric])
5
- tags = @metric_search.tags.any? ? @metric_search.tags : nil
6
- groups = @metric_search.groups
4
+ Cohortly::Metric.send :attr_accessor, :groups_intersect
5
+ @metric_search = Cohortly::Metric.new(params[:cohortly_metric])
6
+ json_res = { }
7
+
8
+ if params[:cohortly_metric]
9
+ tags = @metric_search.tags.any? ? @metric_search.tags : ['upload']
10
+ groups = @metric_search.groups
11
+ groups_intersect = @metric_search.groups_intersect
12
+
13
+ reports = Cohortly::TagReport.where(:tags => tags).all
14
+
15
+ @tag_report = reports.inject(Cohortly::TagReport.new) { |accum, tag_report| accum.merge(tag_report) }
16
+
17
+ user_base_func = lambda { |user_ids| user_ids.length }
18
+
19
+ if groups || groups_intersect
20
+ users_constraint = false
21
+ if groups && groups.any?
22
+ users_constraint = Cohortly::UserCohort.union(Cohortly::GroupCohort.where(:name => groups).all)
23
+ end
24
+ if groups_intersect && groups_intersect.any?
25
+ group_intersect_users = Cohortly::UserCohort.intersect(Cohortly::GroupCohort.where(:name => groups_intersect).all)
26
+ users_constraint = users_constraint ? users_constraint & group_intersect_users : group_intersect_users
27
+ end
28
+ if users_constraint
29
+ user_base_func = lambda { |user_ids| (users_constraint & user_ids).length }
30
+ @tag_report.intersect(users_constraint.map(&:to_s))
31
+ end
32
+ end
7
33
 
8
- @report_name = Cohortly::Metric.report_table_name(tags, groups, true)
9
- # run this in background would be better
34
+ @base_n = Cohortly::PeriodCohort.all.inject({ }) do |base_n, per_coh|
35
+ base_n.merge( per_coh.name => {
36
+ :count => user_base_func.call(per_coh.user_ids),
37
+ :pretty_date => DateTime.strptime( per_coh.name, '%Y-%W').beginning_of_week.strftime('%m-%d-%Y') } )
38
+ end
10
39
 
11
- if Cohortly::Metric.respond_to? :delay
12
- Cohortly::Metric.delay.weekly_cohort_chart_for_tag(tags, groups)
13
- else
14
- Cohortly::Metric.weekly_cohort_chart_for_tag(tags, groups)
40
+ json_res = {
41
+ :groups => groups,
42
+ :groups_intersect => groups_intersect,
43
+ :tags => tags,
44
+ :weekly => true,
45
+ :data => @tag_report.data_without_empty_rows,
46
+ :base_n => @base_n
47
+ }
15
48
  end
16
- @report = Cohortly::Report.new( tags, groups, true )
17
-
49
+
18
50
  respond_to do |format|
19
51
  format.html
20
52
  format.js {
21
- render :json => @report
53
+ render :json => json_res
22
54
  }
23
55
  end
24
56
  end
57
+
25
58
  end
@@ -0,0 +1,8 @@
1
+ module Cohortly
2
+ class Cohorts
3
+ def self.cohort_names; end
4
+ def self.first_user_start_date(group_name = nil); end
5
+ def self.range(time_range); end
6
+ def self.group(group_name); end
7
+ end
8
+ end
@@ -0,0 +1,9 @@
1
+ module Cohortly
2
+ class GroupCohort < Cohortly::UserCohort
3
+ def store!
4
+ return unless self.name
5
+ self.user_ids = Cohortly::Cohorts.group_name(self.name)
6
+ self.save
7
+ end
8
+ end
9
+ end
@@ -51,7 +51,7 @@ module Cohortly
51
51
  :raw => true,
52
52
  :query => query})
53
53
  end
54
-
54
+
55
55
  def self.cohort_chart_for_tag(tags = nil, groups = nil)
56
56
  self.cohort_chart(tags, groups, false)
57
57
  end
@@ -0,0 +1,24 @@
1
+ module Cohortly
2
+ class PeriodCohort < Cohortly::UserCohort
3
+ key :start_time, Time
4
+ key :weekly, Boolean
5
+
6
+ def end_time
7
+ self.start_time + period
8
+ end
9
+
10
+ def period
11
+ self.weekly ? 1.week : 1.month
12
+ end
13
+
14
+ def key_pattern
15
+ self.weekly ? "%Y-%W" : "%Y-%m"
16
+ end
17
+
18
+ def store!
19
+ self.user_ids = Cohortly::Cohorts.range(self.start_time..self.end_time)
20
+ self.name = (self.start_time + 3.days).strftime(key_pattern)
21
+ self.save
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,126 @@
1
+ module Cohortly
2
+ class TagReport
3
+ include MongoMapper::Document
4
+
5
+ key :collection_name, String
6
+ key :last_update_on, Time
7
+ key :data, Hash
8
+ key :tags, Array
9
+
10
+ def run
11
+ if self.last_update_on.nil?
12
+ self.recalc_table
13
+ else
14
+ self.update_table
15
+ end
16
+ end
17
+
18
+ def tag_query
19
+ self.tags.any? ? { :tags => self.tags.first } : { }
20
+ end
21
+
22
+ def cell_query(cohort_range, cell_range)
23
+ { :created_at => {
24
+ :$gt => cell_range.begin,
25
+ :$lt => cell_range.end},
26
+ :user_start_date => {
27
+ :$gt => cohort_range.begin,
28
+ :$lt => cohort_range.end } }.tap { |x|
29
+ self.tags ? x.merge!( tag_query ) : x
30
+ }
31
+ end
32
+
33
+ def start_time
34
+ Cohortly::Metric.where(tag_query).sort(:user_start_date).limit(1).first.user_start_date.utc.beginning_of_week
35
+ end
36
+
37
+ def cohort_iter(starting_time)
38
+ cohort_time = starting_time
39
+ while cohort_time <= Time.now
40
+ yield cohort_time..(cohort_time + 1.week)
41
+ cohort_time += 1.week
42
+ end
43
+ end
44
+
45
+ def cell_iter(cell_starting_time)
46
+ cohort_time = start_time
47
+ while cohort_time <= Time.now
48
+ cell_time = [cohort_time, cell_starting_time].max
49
+ while cell_time <= Time.now
50
+ yield cohort_time..(cohort_time + 1.week), cell_time..(cell_time + 1.week)
51
+ cell_time += 1.week
52
+ end
53
+ cohort_time += 1.week
54
+ end
55
+ end
56
+
57
+ def recalc_table
58
+ self.data = { }
59
+ self.last_update_on = Time.now
60
+ self.cell_iter(self.start_time) { |cohort_range, cell_range| self.store_cell(cohort_range, cell_range)}
61
+ end
62
+
63
+ def update_table
64
+ starting_time = self.last_update_on.utc.beginning_of_week
65
+ self.last_update_on = Time.now
66
+ self.cell_iter(starting_time)
67
+ end
68
+
69
+ def store_cell(cohort_range, cell_range)
70
+ cohort_key = cohort_range.begin.strftime('%Y-%W')
71
+ cell_key = cell_range.begin.strftime('%Y-%W')
72
+ p cohort_key + " " + cell_key
73
+ self.data[cohort_key] ||= { }
74
+ self.data[cohort_key][cell_key] ||= { }
75
+ Cohortly::Metric.collection.distinct( :user_id, cell_query(cohort_range, cell_range) ).each do |user_id|
76
+ self.data[cohort_key][cell_key][user_id.to_s] = 1
77
+ end
78
+ end
79
+
80
+ def merge(tag_report)
81
+ TagReport::Product.new(:tag_report => self, :tags => self.tags, :data => self.data).merge(tag_report)
82
+ end
83
+
84
+ class Product
85
+ attr_accessor :tag_report, :tags, :data
86
+ def initialize(options = { })
87
+ self.tags = options[:tags]
88
+ self.tag_report = options[:tag_report]
89
+ self.data = options[:data]
90
+ end
91
+
92
+ def merge(tag_report)
93
+ TagReport::Product.new(:tag_report => self.tag_report,
94
+ :tags => self.tags | tag_report.tags,
95
+ :data => self.deep_merge(self.data, tag_report.data))
96
+ end
97
+
98
+ def deep_merge(data1, data2)
99
+ (data1.keys + data2.keys).uniq.inject({}) do |accum, key|
100
+ if (data1[key] || data2[key]).is_a?(Hash)
101
+ accum[key] = deep_merge(data1[key] || { }, data2[key] || { })
102
+ else
103
+ accum[key] = data1[key] || data2[key]
104
+ end
105
+ accum
106
+ end
107
+ end
108
+
109
+ # user_ids need to be strings
110
+ def intersect(user_ids)
111
+ self.tag_report.cell_iter(self.tag_report.start_time) do |cohort_range, cell_range|
112
+ cohort_key = cohort_range.begin.strftime('%Y-%W')
113
+ cell_key = cell_range.begin.strftime('%Y-%W')
114
+ cell = self.data[cohort_key][cell_key]
115
+ intersected_ids = cell.keys & user_ids
116
+ self.data[cohort_key][cell_key] = intersected_ids.inject({ }) { |accum, user_id| accum.merge!(user_id => 1); accum }
117
+ end
118
+ end
119
+
120
+ def data_without_empty_rows
121
+ self.data.keys.sort.inject({ }) { |new_data, key| puts ; self.data[key].values.collect(&:length).sum > 0 ? new_data.merge(key => self.data[key]) : new_data }
122
+ end
123
+
124
+ end
125
+ end
126
+ end
@@ -0,0 +1,18 @@
1
+ module Cohortly
2
+ class UserCohort
3
+ include MongoMapper::Document
4
+ key :user_ids, Array
5
+ key :name, String
6
+ key :_type, String
7
+ timestamps!
8
+
9
+ def self.intersect(cohorts)
10
+ cohorts.inject(cohorts.first.user_ids) { |user_ids, cohort| user_ids & cohort.user_ids }
11
+ end
12
+
13
+ def self.union(cohorts)
14
+ cohorts.inject([]) { |user_ids, cohort| user_ids | cohort.user_ids }
15
+ end
16
+
17
+ end
18
+ end
@@ -1,5 +1,5 @@
1
1
  <div class="tags">
2
- <% Cohortly::TagConfig.all_groups.sort.each_slice(3) do |groups| %>
2
+ <% Cohortly::Cohorts.group_names.sort.each_slice(3) do |groups| %>
3
3
  <div class="tag_group" style="float:left; padding: 10px;">
4
4
  <% groups.sort.each do |group| %>
5
5
  <div class"tag">
@@ -0,0 +1,14 @@
1
+ <div class="tags">
2
+ <% Cohortly::Cohorts.group_names.sort.each_slice(3) do |groups| %>
3
+ <div class="tag_group" style="float:left; padding: 10px;">
4
+ <% groups.sort.each do |group| %>
5
+ <div class"tag">
6
+ <%= check_box_tag 'cohortly_metric[groups_intersect][]', group,
7
+ params[:cohortly_metric] && params[:cohortly_metric][:groups_intersect] &&
8
+ params[:cohortly_metric][:groups_intersect].include?(group) %><label><%= group %></label>
9
+ </div>
10
+ <% end %>
11
+ </div>
12
+ <% end %>
13
+ <div style="clear:both;"></div>
14
+ </div>
@@ -1,5 +1,5 @@
1
1
  <div class="tags">
2
- <% (Cohortly::Metric.collection.distinct(:tags) - Cohortly::TagConfig.all_groups).sort.each_slice(8) do |tags| %>
2
+ <% Cohortly::TagReport.collection.distinct(:tags).sort.each_slice(8) do |tags| %>
3
3
  <div class="tag_group" style="float:left; padding: 10px;">
4
4
  <% tags.sort.each do |tag| %>
5
5
  <div class"tag">
@@ -2,8 +2,10 @@
2
2
 
3
3
  <%= form_for @metric_search, :url => cohortly_reports_path, :html =>
4
4
  {:method => :get, :class => 'cohortly_report_form'} do |f| %>
5
- <h3>Groups</h3>
5
+ <h3>Groups Union</h3>
6
6
  <%= render :partial => 'cohortly/metrics/groups' %>
7
+ <h3>Groups Intersect</h3>
8
+ <%= render :partial => 'cohortly/metrics/groups_intersect' %>
7
9
  <h3>Tags</h3>
8
10
  <%= render :partial => 'cohortly/metrics/tags' %>
9
11
  <%= f.submit 'Get Report'%>
@@ -34,9 +34,11 @@
34
34
  render: function() {
35
35
  $('.result_table', this.el).html(
36
36
  ['<h3>',
37
- this.model.get('groups') ? 'Groups: ' + this.model.get('groups').join(', ') + ' | ': 'Groups: __ | ',
37
+ this.model.get('groups') ? 'Groups: ' + this.model.get('groups').join(', ') + ' | ': 'Groups: __ | ',
38
38
  '',
39
- this.model.get('tags') ? 'Tags: ' + this.model.get('tags').join(', ') : 'Tags: __ ',
39
+ this.model.get('groups_intersect') ? 'Groups Int: ' + this.model.get('groups_intersect').join(', ') + ' | ': 'Groups Int: __ |',
40
+ '',
41
+ this.model.get('tags') ? 'Tags: ' + this.model.get('tags').join(', ') : 'Tags: __ ',
40
42
  '</h3>',
41
43
  '<table class="one-column-emphasis">',
42
44
  '<colgroup><col class="oce-first"></colgroup>',
@@ -55,22 +57,23 @@
55
57
  ].join('');
56
58
  },
57
59
  render_rows: function() {
58
- return _(this.model.get('data')).map(this.render_row).join('');
60
+ return _(_(this.model.get('data')).keys()).sortBy(function(x)
61
+ { return x }).map(this.render_row).join('');
59
62
  },
60
- render_row: function(row) {
61
- var row_key = row['_id'];
62
- var base_n = this.model.get('base_n')[row_key];
63
+ render_row: function(row_key) {
64
+ var base_n_data = this.model.get('base_n')[row_key];
63
65
  return [
64
66
  '<tr>',
65
- '<td>' + row['_id']+ '</td>',
66
- '<td>' + base_n + '</td>',
67
- this.render_cells(row, base_n),
67
+ '<td>' + base_n_data.pretty_date + '</td>',
68
+ '<td>' + base_n_data.count + '</td>',
69
+ this.render_cells(row_key, base_n_data.count),
68
70
  '</tr>'
69
71
  ].join('');
70
72
  },
71
- render_cells: function(row, base_n) {
72
- return _(_(row.value).keys()).sortBy(function(x){return x}).slice(0,14).map(function(key) {
73
- var num_users = _(row.value[key]).keys().length;
73
+ render_cells: function(row_key, base_n) {
74
+ var row = this.model.get('data')[row_key];
75
+ return _(_(row).keys()).sortBy(function(x){return x}).slice(0,14).map(function(key) {
76
+ var num_users = _(row[key]).keys().length;
74
77
  var percent = (base_n > 0) ? (num_users / base_n) : 0;
75
78
  return [
76
79
  '<td style="text-align:right;">',
@@ -79,7 +82,6 @@
79
82
  ].join('');
80
83
  }).join('');
81
84
  }
82
-
83
85
  });
84
86
 
85
87
  $(function() {
@@ -9,8 +9,10 @@ module Cohortly
9
9
  Cohortly::Metric.connection Mongo::Connection.new(cfg.host, cfg.port)
10
10
  Cohortly::Metric.set_database_name cfg.database
11
11
  Cohortly::Metric.database.authenticate(cfg.username, cfg.password) if(cfg.password)
12
- Cohortly::ReportMeta.connection Cohortly::Metric.connection
13
- Cohortly::ReportMeta.set_database_name cfg.database
12
+ Cohortly::TagReport.connection Cohortly::Metric.connection
13
+ Cohortly::TagReport.set_database_name cfg.database
14
+ Cohortly::UserCohort.connection Cohortly::Metric.connection
15
+ Cohortly::UserCohort.set_database_name cfg.database
14
16
  end
15
17
  end
16
18
  Cohortly::StoredProcedures.store_procedures
@@ -1,3 +1,3 @@
1
1
  module Cohortly
2
- VERSION = "0.0.9.1"
2
+ VERSION = "0.0.92"
3
3
  end
@@ -1,28 +1,55 @@
1
1
  namespace :cohortly do
2
2
  namespace :run do
3
3
  desc "run the reports for all the tags"
4
- task :reseed_reports => :environment do
5
- Cohortly::ReportMeta.delete_all
6
- Cohortly::Metric.cohort_chart(nil, nil, true)
7
- puts "main report"
8
- real_tags = (Cohortly::Metric.collection.distinct(:tags) - Cohortly::TagConfig.all_groups)
4
+ task :recalc_reports => :environment do
5
+ real_tags = Cohortly::Metric.collection.distinct(:tags)
9
6
  real_tags.each do |tag|
10
- Cohortly::Metric.cohort_chart([tag], nil, true)
11
- puts "tag: #{tag}"
12
- end
13
- Cohortly::TagConfig.all_groups.each do |group|
14
- real_tags.each do |tag|
15
- puts "tag: #{tag} group: #{group}"
16
- Cohortly::Metric.cohort_chart([tag], [group], true)
17
- end
7
+ report = Cohortly::TagReport.where(:tags => tag).first
8
+ report ||= Cohortly::TagReport.new(:tags => [tag])
9
+ report.recalc_table
10
+ report.save
18
11
  end
12
+
13
+ # the empty report
14
+ report = Cohortly::TagReport.where(:tags => []).first
15
+ report ||= Cohortly::TagReport.new(:tags => [])
16
+ report.recalc_table
17
+ report.save
19
18
  end
20
19
 
21
20
  desc "update all existing reports"
22
21
  task :updates => :environment do
23
- Cohortly::ReportMeta.all.each do |rep|
24
- puts rep.collection_name
25
- rep.run
22
+ real_tags = Cohortly::Metric.collection.distinct(:tags)
23
+ real_tags.each do |tag|
24
+ report = Cohortly::TagReport.where(:tags => tag).first
25
+ report ||= Cohortly::TagReport.new(:tags => [tag])
26
+ report.run
27
+ report.save
28
+ end
29
+
30
+ # the empty report
31
+ report = Cohortly::TagReport.where(:tags => []).first
32
+ report ||= Cohortly::TagReport.new(:tags => [])
33
+ report.run
34
+ report.save
35
+ end
36
+
37
+ desc "build cohorts"
38
+ task :build_cohorts => :environment do
39
+ Cohortly::Cohorts.group_names.each do |name|
40
+ cohort = Cohortly::GroupCohort.find_or_create_by_name(name)
41
+ cohort.store!
42
+ end
43
+
44
+ #weekly cohort
45
+ cur_time = Cohortly::Cohorts.first_user_start_date.utc.beginning_of_week
46
+ while(cur_time < Time.now) do
47
+ time_key = (cur_time + 3.days).strftime("%Y-%W")
48
+ cohort = Cohortly::PeriodCohort.find_or_create_by_name(time_key)
49
+ cohort.start_time = cur_time
50
+ cohort.weekly = true
51
+ cohort.store!
52
+ cur_time += 1.week
26
53
  end
27
54
  end
28
55
  end
@@ -0,0 +1,15 @@
1
+ module Cohortly
2
+ class Cohorts
3
+ def group_names
4
+ [:rand_1, :rand_2, :rand_3]
5
+ end
6
+
7
+ def group_name(name)
8
+ Cohortly::Metric.collection.distinct(:user_id, :tag => [name])
9
+ end
10
+
11
+ def range(time_range)
12
+ Cohortly::Metric.collection.distinct(:user_id, :user_start_time => { :$gte => time_range.begin, :lt => time_range.end })
13
+ end
14
+ end
15
+ end
@@ -9997,3 +9997,160 @@ Started GET "/cohortly/reports.js?utf8=%E2%9C%93" for 127.0.0.1 at 2011-10-27 00
9997
9997
  Processing by Cohortly::ReportsController#index as JS
9998
9998
  Parameters: {"utf8"=>"✓"}
9999
9999
  Completed 200 OK in 166ms (Views: 112.0ms)
10000
+
10001
+
10002
+ Started GET "/" for 127.0.0.1 at 2011-10-30 14:52:13 -0400
10003
+ Processing by StuffController#index as HTML
10004
+ Rendered stuff/index.html.erb within layouts/application (1.5ms)
10005
+ Completed 200 OK in 101ms (Views: 95.9ms)
10006
+
10007
+
10008
+ Started GET "/cohortly/reports" for 127.0.0.1 at 2011-10-30 14:52:16 -0400
10009
+ Processing by Cohortly::ReportsController#index as HTML
10010
+ Completed in 56ms
10011
+
10012
+ ArgumentError (wrong number of arguments (0 for 1)):
10013
+
10014
+
10015
+ Rendered /Users/bhauman/.rvm/gems/ruby-1.9.2-p136@cohortly/gems/actionpack-3.0.4/lib/action_dispatch/middleware/templates/rescues/_trace.erb (1.1ms)
10016
+ Rendered /Users/bhauman/.rvm/gems/ruby-1.9.2-p136@cohortly/gems/actionpack-3.0.4/lib/action_dispatch/middleware/templates/rescues/_request_and_response.erb (68.4ms)
10017
+ Rendered /Users/bhauman/.rvm/gems/ruby-1.9.2-p136@cohortly/gems/actionpack-3.0.4/lib/action_dispatch/middleware/templates/rescues/diagnostics.erb within rescues/layout (76.5ms)
10018
+
10019
+
10020
+ Started GET "/cohortly/reports" for 127.0.0.1 at 2011-10-30 14:54:50 -0400
10021
+ Processing by Cohortly::ReportsController#index as HTML
10022
+ Completed in 64ms
10023
+
10024
+ NameError (undefined local variable or method `cohort' for #<Cohortly::ReportsController:0x00000100e57a80>):
10025
+
10026
+
10027
+ Rendered /Users/bhauman/.rvm/gems/ruby-1.9.2-p136@cohortly/gems/actionpack-3.0.4/lib/action_dispatch/middleware/templates/rescues/_trace.erb (1.1ms)
10028
+ Rendered /Users/bhauman/.rvm/gems/ruby-1.9.2-p136@cohortly/gems/actionpack-3.0.4/lib/action_dispatch/middleware/templates/rescues/_request_and_response.erb (56.9ms)
10029
+ Rendered /Users/bhauman/.rvm/gems/ruby-1.9.2-p136@cohortly/gems/actionpack-3.0.4/lib/action_dispatch/middleware/templates/rescues/diagnostics.erb within rescues/layout (61.4ms)
10030
+
10031
+
10032
+ Started GET "/cohortly/reports" for 127.0.0.1 at 2011-10-30 14:55:07 -0400
10033
+ Processing by Cohortly::ReportsController#index as HTML
10034
+ Completed in 75ms
10035
+
10036
+ NoMethodError (undefined method `stftime' for 2011-04-25 00:00:00 UTC:Time):
10037
+
10038
+
10039
+ Rendered /Users/bhauman/.rvm/gems/ruby-1.9.2-p136@cohortly/gems/actionpack-3.0.4/lib/action_dispatch/middleware/templates/rescues/_trace.erb (1.1ms)
10040
+ Rendered /Users/bhauman/.rvm/gems/ruby-1.9.2-p136@cohortly/gems/actionpack-3.0.4/lib/action_dispatch/middleware/templates/rescues/_request_and_response.erb (65.4ms)
10041
+ Rendered /Users/bhauman/.rvm/gems/ruby-1.9.2-p136@cohortly/gems/actionpack-3.0.4/lib/action_dispatch/middleware/templates/rescues/diagnostics.erb within rescues/layout (70.0ms)
10042
+
10043
+
10044
+ Started GET "/cohortly/reports" for 127.0.0.1 at 2011-10-30 14:55:18 -0400
10045
+ Processing by Cohortly::ReportsController#index as HTML
10046
+ Completed in 52ms
10047
+
10048
+ NoMethodError (undefined method `start' for 2011-04-25 00:00:00 UTC..2011-05-02 00:00:00 UTC:Range):
10049
+
10050
+
10051
+ Rendered /Users/bhauman/.rvm/gems/ruby-1.9.2-p136@cohortly/gems/actionpack-3.0.4/lib/action_dispatch/middleware/templates/rescues/_trace.erb (1.0ms)
10052
+ Rendered /Users/bhauman/.rvm/gems/ruby-1.9.2-p136@cohortly/gems/actionpack-3.0.4/lib/action_dispatch/middleware/templates/rescues/_request_and_response.erb (51.4ms)
10053
+ Rendered /Users/bhauman/.rvm/gems/ruby-1.9.2-p136@cohortly/gems/actionpack-3.0.4/lib/action_dispatch/middleware/templates/rescues/diagnostics.erb within rescues/layout (55.7ms)
10054
+
10055
+
10056
+ Started GET "/cohortly/reports" for 127.0.0.1 at 2011-10-30 14:55:28 -0400
10057
+ Processing by Cohortly::ReportsController#index as HTML
10058
+ Rendered /Users/bhauman/workspace/cohortly/app/views/cohortly/metrics/_groups.html.erb (1.3ms)
10059
+ Rendered /Users/bhauman/workspace/cohortly/app/views/cohortly/metrics/_tags.html.erb (1183.8ms)
10060
+ Rendered /Users/bhauman/workspace/cohortly/app/views/cohortly/reports/index.html.erb within layouts/cohortly/application (1213.2ms)
10061
+ Completed in 3077ms
10062
+
10063
+ ActionView::Template::Error (comparison of String with Array failed):
10064
+ 1: <div class="tags">
10065
+ 2: <% (Cohortly::Metric.collection.distinct(:tags) - Cohortly::TagConfig.all_groups).sort.each_slice(8) do |tags| %>
10066
+ 3: <div class="tag_group" style="float:left; padding: 10px;">
10067
+ 4: <% tags.sort.each do |tag| %>
10068
+ 5: <div class"tag">
10069
+
10070
+
10071
+ Rendered /Users/bhauman/.rvm/gems/ruby-1.9.2-p136@cohortly/gems/actionpack-3.0.4/lib/action_dispatch/middleware/templates/rescues/_trace.erb (1.1ms)
10072
+ Rendered /Users/bhauman/.rvm/gems/ruby-1.9.2-p136@cohortly/gems/actionpack-3.0.4/lib/action_dispatch/middleware/templates/rescues/_request_and_response.erb (75.2ms)
10073
+ Rendered /Users/bhauman/.rvm/gems/ruby-1.9.2-p136@cohortly/gems/actionpack-3.0.4/lib/action_dispatch/middleware/templates/rescues/template_error.erb within rescues/layout (80.2ms)
10074
+
10075
+
10076
+ Started GET "/cohortly/reports" for 127.0.0.1 at 2011-10-30 15:06:30 -0400
10077
+ Processing by Cohortly::ReportsController#index as HTML
10078
+ Completed in 55ms
10079
+
10080
+ NoMethodError (undefined method `utc' for nil:NilClass):
10081
+
10082
+
10083
+ Rendered /Users/bhauman/.rvm/gems/ruby-1.9.2-p136@cohortly/gems/actionpack-3.0.4/lib/action_dispatch/middleware/templates/rescues/_trace.erb (1.0ms)
10084
+ Rendered /Users/bhauman/.rvm/gems/ruby-1.9.2-p136@cohortly/gems/actionpack-3.0.4/lib/action_dispatch/middleware/templates/rescues/_request_and_response.erb (50.8ms)
10085
+ Rendered /Users/bhauman/.rvm/gems/ruby-1.9.2-p136@cohortly/gems/actionpack-3.0.4/lib/action_dispatch/middleware/templates/rescues/diagnostics.erb within rescues/layout (55.3ms)
10086
+
10087
+
10088
+ Started GET "/cohortly/reports" for 127.0.0.1 at 2011-10-30 15:09:32 -0400
10089
+ Processing by Cohortly::ReportsController#index as HTML
10090
+ Rendered /Users/bhauman/workspace/cohortly/app/views/cohortly/metrics/_groups.html.erb (0.7ms)
10091
+ Rendered /Users/bhauman/workspace/cohortly/app/views/cohortly/metrics/_tags.html.erb (1129.6ms)
10092
+ Rendered /Users/bhauman/workspace/cohortly/app/views/cohortly/reports/index.html.erb within layouts/cohortly/application (1136.1ms)
10093
+ Completed 200 OK in 2988ms (Views: 1140.6ms)
10094
+
10095
+
10096
+ Started GET "/cohortly/reports.js?utf8=%E2%9C%93" for 127.0.0.1 at 2011-10-30 15:09:43 -0400
10097
+ Processing by Cohortly::ReportsController#index as JS
10098
+ Parameters: {"utf8"=>"✓"}
10099
+ Completed 200 OK in 2108ms (Views: 285.1ms)
10100
+
10101
+
10102
+ Started GET "/cohortly/reports" for 127.0.0.1 at 2011-10-30 15:10:28 -0400
10103
+ Processing by Cohortly::ReportsController#index as HTML
10104
+ Rendered /Users/bhauman/workspace/cohortly/app/views/cohortly/metrics/_groups.html.erb (0.7ms)
10105
+ Rendered /Users/bhauman/workspace/cohortly/app/views/cohortly/metrics/_tags.html.erb (1147.7ms)
10106
+ Rendered /Users/bhauman/workspace/cohortly/app/views/cohortly/reports/index.html.erb within layouts/cohortly/application (1179.5ms)
10107
+ Completed 200 OK in 3007ms (Views: 1184.0ms)
10108
+
10109
+
10110
+ Started GET "/cohortly/reports" for 127.0.0.1 at 2011-10-30 15:11:45 -0400
10111
+ Processing by Cohortly::ReportsController#index as HTML
10112
+ Rendered /Users/bhauman/workspace/cohortly/app/views/cohortly/metrics/_groups.html.erb (0.7ms)
10113
+ Rendered /Users/bhauman/workspace/cohortly/app/views/cohortly/metrics/_tags.html.erb (1181.6ms)
10114
+ Rendered /Users/bhauman/workspace/cohortly/app/views/cohortly/reports/index.html.erb within layouts/cohortly/application (1188.1ms)
10115
+ Completed 200 OK in 3150ms (Views: 1193.9ms)
10116
+
10117
+
10118
+ Started GET "/cohortly/reports.js?utf8=%E2%9C%93" for 127.0.0.1 at 2011-10-30 15:11:52 -0400
10119
+ Processing by Cohortly::ReportsController#index as JS
10120
+ Parameters: {"utf8"=>"✓"}
10121
+ Completed 200 OK in 2224ms (Views: 299.9ms)
10122
+
10123
+
10124
+ Started GET "/cohortly/reports" for 127.0.0.1 at 2011-10-30 15:12:48 -0400
10125
+ Processing by Cohortly::ReportsController#index as HTML
10126
+ Rendered /Users/bhauman/workspace/cohortly/app/views/cohortly/metrics/_groups.html.erb (0.8ms)
10127
+ Rendered /Users/bhauman/workspace/cohortly/app/views/cohortly/metrics/_tags.html.erb (1193.8ms)
10128
+ Rendered /Users/bhauman/workspace/cohortly/app/views/cohortly/reports/index.html.erb within layouts/cohortly/application (1200.4ms)
10129
+ Completed 200 OK in 3060ms (Views: 1204.8ms)
10130
+
10131
+
10132
+ Started GET "/cohortly/reports.js?utf8=%E2%9C%93" for 127.0.0.1 at 2011-10-30 15:13:09 -0400
10133
+ Processing by Cohortly::ReportsController#index as JS
10134
+ Parameters: {"utf8"=>"✓"}
10135
+ Completed 200 OK in 2218ms (Views: 391.1ms)
10136
+
10137
+
10138
+ Started GET "/" for 127.0.0.1 at 2011-10-30 15:15:58 -0400
10139
+ Processing by StuffController#index as HTML
10140
+ Rendered stuff/index.html.erb within layouts/application (1.4ms)
10141
+ Completed 200 OK in 22ms (Views: 5.5ms)
10142
+
10143
+
10144
+ Started GET "/cohortly/reports.js?utf8=%E2%9C%93" for 127.0.0.1 at 2011-10-30 15:16:02 -0400
10145
+ Processing by Cohortly::ReportsController#index as JS
10146
+ Parameters: {"utf8"=>"✓"}
10147
+ Completed 200 OK in 2273ms (Views: 298.8ms)
10148
+ DEPRECATION WARNING: ActionController::Routing::Routes is deprecated. Instead, use Rails.application.routes. (called from block in irb_binding at (irb):15)
10149
+ DEPRECATION WARNING: RAILS_DEFAULT_LOGGER is deprecated. Please use ::Rails.logger. (called from block in irb_binding at (irb):15)
10150
+ DEPRECATION WARNING: RAILS_ENV is deprecated. Please use ::Rails.env. (called from block in irb_binding at (irb):15)
10151
+ DEPRECATION WARNING: RAILS_ROOT is deprecated. Please use ::Rails.root.to_s. (called from block in irb_binding at (irb):15)
10152
+ DEPRECATION WARNING: ActiveSupport::JSON::CircularReferenceError is deprecated! Use ActiveSupport::JSON::Encoding::CircularReferenceError instead. (called from block in irb_binding at (irb):15)
10153
+ DEPRECATION WARNING: ActiveSupport::JSON::CircularReferenceError is deprecated! Use ActiveSupport::JSON::Encoding::CircularReferenceError instead. (called from block in irb_binding at (irb):15)
10154
+ DEPRECATION WARNING: ActionController::Routing::Routes is deprecated. Instead, use Rails.application.routes. (called from block in irb_binding at (irb):20)
10155
+ DEPRECATION WARNING: ActiveSupport::JSON::CircularReferenceError is deprecated! Use ActiveSupport::JSON::Encoding::CircularReferenceError instead. (called from block in irb_binding at (irb):20)
10156
+ DEPRECATION WARNING: ActiveSupport::JSON::CircularReferenceError is deprecated! Use ActiveSupport::JSON::Encoding::CircularReferenceError instead. (called from block in irb_binding at (irb):20)
metadata CHANGED
@@ -2,7 +2,7 @@
2
2
  name: cohortly
3
3
  version: !ruby/object:Gem::Version
4
4
  prerelease:
5
- version: 0.0.9.1
5
+ version: 0.0.92
6
6
  platform: ruby
7
7
  authors:
8
8
  - Bruce Hauman
@@ -10,7 +10,7 @@ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
12
 
13
- date: 2011-10-27 00:00:00 -07:00
13
+ date: 2011-11-02 00:00:00 -07:00
14
14
  default_executable:
15
15
  dependencies: []
16
16
 
@@ -29,11 +29,15 @@ files:
29
29
  - app/controllers/cohortly/cohortly_controller.rb
30
30
  - app/controllers/cohortly/metrics_controller.rb
31
31
  - app/controllers/cohortly/reports_controller.rb
32
+ - app/models/cohortly/cohorts.rb
33
+ - app/models/cohortly/group_cohort.rb
32
34
  - app/models/cohortly/metric.rb
33
- - app/models/cohortly/report.rb
34
- - app/models/cohortly/report_meta.rb
35
+ - app/models/cohortly/period_cohort.rb
35
36
  - app/models/cohortly/stored_procedures.rb
37
+ - app/models/cohortly/tag_report.rb
38
+ - app/models/cohortly/user_cohort.rb
36
39
  - app/views/cohortly/metrics/_groups.html.erb
40
+ - app/views/cohortly/metrics/_groups_intersect.html.erb
37
41
  - app/views/cohortly/metrics/_metric.html.erb
38
42
  - app/views/cohortly/metrics/_pagination.html.erb
39
43
  - app/views/cohortly/metrics/_tags.html.erb
@@ -58,6 +62,7 @@ files:
58
62
  - test/dummy/app/controllers/stuff_controller.rb
59
63
  - test/dummy/app/helpers/application_helper.rb
60
64
  - test/dummy/app/helpers/stuff_helper.rb
65
+ - test/dummy/app/models/cohortly/cohorts.rb
61
66
  - test/dummy/app/views/layouts/application.html.erb
62
67
  - test/dummy/app/views/stuff/index.html.erb
63
68
  - test/dummy/app/views/stuff/my_stuff.html.erb
@@ -97,7 +102,6 @@ files:
97
102
  - test/dummy/public/javascripts/vendor/underscore.js
98
103
  - test/dummy/Rakefile
99
104
  - test/dummy/script/rails
100
- - test/dummy/tmp/pids/server.pid
101
105
  - test/integration/navigation_test.rb
102
106
  - test/support/integration_case.rb
103
107
  - test/support/test_tag_config.rb
@@ -136,6 +140,7 @@ test_files:
136
140
  - test/dummy/app/controllers/stuff_controller.rb
137
141
  - test/dummy/app/helpers/application_helper.rb
138
142
  - test/dummy/app/helpers/stuff_helper.rb
143
+ - test/dummy/app/models/cohortly/cohorts.rb
139
144
  - test/dummy/app/views/layouts/application.html.erb
140
145
  - test/dummy/app/views/stuff/index.html.erb
141
146
  - test/dummy/app/views/stuff/my_stuff.html.erb
@@ -175,7 +180,6 @@ test_files:
175
180
  - test/dummy/public/javascripts/vendor/underscore.js
176
181
  - test/dummy/Rakefile
177
182
  - test/dummy/script/rails
178
- - test/dummy/tmp/pids/server.pid
179
183
  - test/integration/navigation_test.rb
180
184
  - test/support/integration_case.rb
181
185
  - test/support/test_tag_config.rb
@@ -1,118 +0,0 @@
1
- module Cohortly
2
- class Report
3
- # this is the reduced collection
4
- attr_accessor :collection, :weekly, :key_pattern, :groups, :tags, :report_meta
5
- def initialize( tags = nil, groups = nil, weekly = true )
6
- self.collection = Cohortly::Metric.report_table_name(tags, groups, weekly)
7
- self.report_meta = ReportMeta.find_or_create_by_collection_name(self.collection)
8
- self.groups = groups
9
- self.tags = tags
10
- self.weekly = weekly
11
- self.key_pattern = self.weekly ? "%Y-%W" : "%Y-%m"
12
- end
13
-
14
- def data
15
- @data ||= (Cohortly::Metric.database[self.report_meta.store_name].find().collect {|x| x}).sort_by {|x| x['_id'] }
16
- end
17
-
18
- def fix_data_lines
19
- data.each do |line|
20
- period_cohorts_from(line['_id']).collect do |key|
21
- if line["value"][key].nil?
22
- line["value"][key] = { }
23
- end
24
- end
25
- end
26
- end
27
-
28
- def offset
29
- self.weekly ? 1.week : 1.month
30
- end
31
-
32
- def start_key
33
- data.first['_id']
34
- end
35
-
36
- def end_key
37
- time_to_key(Time.now.utc)
38
- end
39
-
40
- def time_to_key(time)
41
- time.strftime(self.key_pattern)
42
- end
43
-
44
- def key_to_time(report_key)
45
- DateTime.strptime(report_key, self.key_pattern).to_time.utc
46
- end
47
-
48
- def user_count_in_cohort(report_key)
49
- params = { :user_start_date => { :$gt => key_to_time(report_key) - 1.week,
50
- :$lt => (key_to_time(report_key) )}}
51
- params[:tags] = { :$in => groups } if self.groups
52
- Cohortly::Metric.collection.distinct(:user_id, params).length
53
- end
54
-
55
- def period_cohorts
56
- return [] unless data.first
57
- start_time = key_to_time(start_key)
58
- end_time = key_to_time(end_key)
59
- cur_time = start_time
60
- res = [start_key]
61
- cur_time += self.offset
62
- while(cur_time < end_time) do
63
- res << time_to_key(cur_time)
64
- cur_time += self.offset
65
- end
66
- res
67
- end
68
-
69
- def period_cohorts_from(cohort_key)
70
- index = period_cohorts.index(cohort_key)
71
- if index
72
- period_cohorts[index..-1]
73
- else
74
- []
75
- end
76
- end
77
-
78
- def report_line(cohort_key)
79
- line = data.find {|x| x['_id'] == cohort_key}
80
- return [] unless line
81
- period_cohorts_from(cohort_key).collect do |key|
82
- if line["value"][key]
83
- line["value"][key].keys.length
84
- else
85
- 0
86
- end
87
- end
88
- end
89
-
90
- def percent_line(cohort_key)
91
- line = report_line(cohort_key)
92
- base = user_count_in_cohort(cohort_key)
93
- line.collect { |x| (x && base > 0.0 ) ? (x/base.to_f * 100).round : 0 }.unshift base
94
- end
95
-
96
- def report_totals
97
- period_cohorts.collect do |cohort_key|
98
- report_line(cohort_key)
99
- end
100
- end
101
-
102
- def base_n
103
- @base_n ||= self.period_cohorts.inject({ }) { |accum, key| accum[key] = user_count_in_cohort(key); accum }
104
- end
105
-
106
- def as_json(*args)
107
- fix_data_lines
108
- { :name => report_meta.collection_name,
109
- :store_name => report_meta.store_name,
110
- :groups => self.groups,
111
- :tags => self.tags,
112
- :weekly => self.weekly,
113
- :data => data,
114
- :base_n => base_n
115
- }
116
- end
117
- end
118
- end
@@ -1,17 +0,0 @@
1
- module Cohortly
2
- class ReportMeta
3
- include MongoMapper::Document
4
-
5
- key :collection_name, String
6
- key :last_update_on, Time
7
-
8
- def store_name
9
- "cohortly_report_#{self.id}"
10
- end
11
-
12
- def run
13
- args = Metric.report_name_to_args(self.collection_name)
14
- Cohortly::Metric.cohort_chart(*args)
15
- end
16
- end
17
- end
@@ -1 +0,0 @@
1
- 5601