metry 2.0.5 → 2.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (44) hide show
  1. data/History.txt +4 -0
  2. data/Manifest.txt +12 -6
  3. data/Rakefile +5 -0
  4. data/TODO +1 -6
  5. data/example/example.rb +1 -1
  6. data/features/app_tracking.feature +1 -2
  7. data/features/basic_tracking.feature +19 -38
  8. data/features/psycho/dashboard.feature +3 -11
  9. data/features/psycho/experiments.feature +28 -0
  10. data/features/psycho/visitor_tracking.feature +4 -4
  11. data/features/step_definitions/experiments.rb +8 -0
  12. data/features/step_definitions/psycho.rb +14 -0
  13. data/features/step_definitions/tracking.rb +56 -24
  14. data/features/support/env.rb +0 -1
  15. data/features/support/helpers.rb +6 -0
  16. data/lib/metry.rb +12 -5
  17. data/lib/metry/cohort.rb +19 -0
  18. data/lib/metry/event.rb +26 -0
  19. data/lib/metry/experiment.rb +36 -13
  20. data/lib/metry/goal.rb +18 -0
  21. data/lib/metry/psycho.rb +24 -93
  22. data/lib/metry/psycho/dashboard.erb +5 -5
  23. data/lib/metry/psycho/edit_goal.erb +1 -1
  24. data/lib/metry/psycho/experiment.erb +25 -0
  25. data/lib/metry/psycho/new_goal.erb +1 -1
  26. data/lib/metry/psycho/visitor.erb +4 -1
  27. data/lib/metry/psycho/visitors.erb +6 -0
  28. data/lib/metry/rack/tracking.rb +19 -18
  29. data/lib/metry/visitor.rb +30 -0
  30. data/radiant/example/features/metry.feature +21 -43
  31. data/radiant/example/features/step_definitions/tracking.rb +56 -24
  32. data/radiant/example/features/step_definitions/web.rb +0 -7
  33. data/radiant/example/features/support/env.rb +7 -3
  34. data/radiant/example/features/support/helpers.rb +6 -0
  35. data/radiant/extension/lib/metry_tags.rb +3 -1
  36. data/test/shared.rb +3 -1
  37. data/test/test_experiment.rb +104 -0
  38. metadata +45 -9
  39. data/features/psycho/goals.feature +0 -53
  40. data/features/step_definitions/goals.rb +0 -3
  41. data/lib/metry/psycho/goal.erb +0 -9
  42. data/lib/metry/storage.rb +0 -142
  43. data/radiant/example/features/step_definitions/experiments.rb +0 -12
  44. data/test/test_storage.rb +0 -25
@@ -1,3 +1,7 @@
1
+ === 2.1.0 / 2009-08-13
2
+
3
+ * Added experiment/cohort analysis.
4
+
1
5
  === 2.0.5 / 2009-08-09
2
6
 
3
7
  * Added missed files.
@@ -8,24 +8,30 @@ example/example.rb
8
8
  features/app_tracking.feature
9
9
  features/basic_tracking.feature
10
10
  features/psycho/dashboard.feature
11
- features/psycho/goals.feature
11
+ features/psycho/experiments.feature
12
12
  features/psycho/visitor_tracking.feature
13
13
  features/sample_application.feature
14
- features/step_definitions/goals.rb
14
+ features/step_definitions/experiments.rb
15
+ features/step_definitions/psycho.rb
15
16
  features/step_definitions/tracking.rb
16
17
  features/step_definitions/web.rb
17
18
  features/support/env.rb
19
+ features/support/helpers.rb
18
20
  lib/metry.rb
21
+ lib/metry/cohort.rb
22
+ lib/metry/event.rb
19
23
  lib/metry/experiment.rb
24
+ lib/metry/goal.rb
20
25
  lib/metry/psycho.rb
21
26
  lib/metry/psycho/dashboard.erb
22
27
  lib/metry/psycho/edit_goal.erb
23
- lib/metry/psycho/goal.erb
28
+ lib/metry/psycho/experiment.erb
24
29
  lib/metry/psycho/layout.erb
25
30
  lib/metry/psycho/new_goal.erb
26
31
  lib/metry/psycho/visitor.erb
32
+ lib/metry/psycho/visitors.erb
27
33
  lib/metry/rack/tracking.rb
28
- lib/metry/storage.rb
34
+ lib/metry/visitor.rb
29
35
  radiant/example/CHANGELOG
30
36
  radiant/example/CONTRIBUTORS
31
37
  radiant/example/INSTALL
@@ -43,11 +49,11 @@ radiant/example/config/routes.rb
43
49
  radiant/example/db/schema.rb
44
50
  radiant/example/features/metry.feature
45
51
  radiant/example/features/psycho.feature
46
- radiant/example/features/step_definitions/experiments.rb
47
52
  radiant/example/features/step_definitions/radiant.rb
48
53
  radiant/example/features/step_definitions/tracking.rb
49
54
  radiant/example/features/step_definitions/web.rb
50
55
  radiant/example/features/support/env.rb
56
+ radiant/example/features/support/helpers.rb
51
57
  radiant/example/public/.htaccess
52
58
  radiant/example/public/404.html
53
59
  radiant/example/public/500.html
@@ -114,7 +120,7 @@ radiant/extension/lib/metry_tags.rb
114
120
  radiant/extension/lib/tasks/metry_extension_tasks.rake
115
121
  radiant/extension/metry_extension.rb
116
122
  test/shared.rb
117
- test/test_storage.rb
123
+ test/test_experiment.rb
118
124
  vendor/webrat/.document
119
125
  vendor/webrat/History.txt
120
126
  vendor/webrat/MIT-LICENSE.txt
data/Rakefile CHANGED
@@ -1,9 +1,14 @@
1
+ ENV["RUBY_FLAGS"] = "-I#{%w(lib ext bin test).join(File::PATH_SEPARATOR)}"
2
+
1
3
  require 'rubygems'
2
4
  require 'hoe'
3
5
 
4
6
  Hoe.spec 'metry' do
5
7
  developer('Nathaniel Talbott', 'nathaniel@terralien.com')
6
8
  self.rubyforge_name = 'terralien'
9
+ extra_deps << ['mongomapper', '~> 0.3']
10
+ extra_deps << ['mongodb-mongo', '~> 0.10']
11
+ extra_deps << ['mongodb-mongo_ext', '~> 0.4']
7
12
  end
8
13
 
9
14
  require 'cucumber/rake/task'
data/TODO CHANGED
@@ -1,10 +1,5 @@
1
- Limit visitors on dashboard to 10 most recent
2
- Add full listing of visitors
3
- Show more details about visitors
4
- Add referrer to event display on visitor pages
5
- Add display of last 10 events to dashboard
6
1
  Show goal conversion for each experiment
7
- Allow manually viewing a particular alternatively
2
+ Allow manually viewing a particular alternative
8
3
 
9
4
  More unit tests
10
5
 
@@ -18,5 +18,5 @@ get '/subpage' do
18
18
  end
19
19
 
20
20
  get '/extra' do
21
- request.env["metry.event"]["extra"] = params[:track]
21
+ request.env["metry.event"].extra["extra"] = params[:track]
22
22
  end
@@ -6,6 +6,5 @@ Feature: Application Tracking
6
6
  Scenario: Track an additional facet
7
7
  Given an empty tracking database
8
8
  When I view "/extra?track=stuff"
9
- Then there should be a tracking event "1":
10
- | key | value |
9
+ Then tracking event #1 extra should contain:
11
10
  | extra | stuff |
@@ -20,73 +20,54 @@ Feature: Access Tracking
20
20
  Scenario: Basic request data is tracked
21
21
  When I view "/"
22
22
  And I view "/subpage"
23
- Then there should be a tracking event "1":
24
- | key | value |
23
+ Then tracking event #1 should contain:
25
24
  | path | / |
26
- | time | _exists_ |
27
- And there should be a tracking event "2":
28
- | key | value |
25
+ | created_at | _exists_ |
26
+ And tracking event #2 should contain:
29
27
  | path | /subpage |
30
- | time | _exists_ |
28
+ | created_at | _exists_ |
31
29
 
32
30
  Scenario: New visitor is tracked
33
31
  When I view "/"
34
32
  And I view "/subpage"
35
- Then there should be a tracking event "1":
36
- | key | value |
37
- | visitor | 1 |
38
- And there should be a tracking event "2":
39
- | key | value |
40
- | visitor | 1 |
41
- And there should be a visitor "1"
33
+ Then there should be a tracking event #1 with visitor #1
34
+ And there should be a tracking event #2 with visitor #1
35
+ And there should be a visitor #1
42
36
 
43
37
  Scenario: Two visitors are tracked
44
38
  Given I view "/"
45
39
  When I am a new visitor
46
40
  Given I view "/"
47
- Then there should be a tracking event "1":
48
- | key | value |
49
- | visitor | 1 |
50
- And there should be a tracking event "2":
51
- | key | value |
52
- | visitor | 2 |
41
+ Then there should be a tracking event #1 with visitor #1
42
+ Then there should be a tracking event #2 with visitor #2
53
43
  And there should be 2 visitors
54
- And there should be a visitor "1"
55
- And there should be a visitor "2"
56
44
 
57
45
  Scenario: All facets should be tracked
58
46
  When I view "/"
59
- Then there should be a tracking event "1":
60
- | key | value |
61
- | path | / |
62
- | time | _exists_ |
63
- | ip | 127.0.0.1 |
64
- | host | example.org |
47
+ Then tracking event #1 should contain:
48
+ | path | / |
49
+ | created_at | _exists_ |
50
+ | ip | 127.0.0.1 |
51
+ | host | www.example.com |
65
52
 
66
53
  Scenario: path should include query string
67
54
  When I view "/?here=there"
68
- Then there should be a tracking event "1":
69
- | key | value |
55
+ Then tracking event #1 should contain:
70
56
  | path | /?here=there |
71
57
 
72
58
  Scenario: Should track status codes
73
59
  When I view "/"
74
60
  And I view "/missing"
75
- Then there should be a tracking event "1":
76
- | key | value |
61
+ Then tracking event #1 should contain:
77
62
  | status | 200 |
78
- Then there should be a tracking event "2":
79
- | key | value |
63
+ Then tracking event #2 should contain:
80
64
  | status | 404 |
81
65
 
82
66
  Scenario: Should track method
83
67
  When I view "/"
84
68
  And I post to "/post":
85
- | key | value |
86
69
  | bogus | bogus |
87
- Then there should be a tracking event "1":
88
- | key | value |
70
+ Then tracking event #1 should contain:
89
71
  | method | GET |
90
- Then there should be a tracking event "2":
91
- | key | value |
72
+ Then tracking event #2 should contain:
92
73
  | method | POST |
@@ -2,16 +2,8 @@ Feature: Psycho Dashboard
2
2
 
3
3
  Scenario: Basics
4
4
  Given an empty tracking database
5
- And I add a goal named "sweet" with path "/"
6
- And I am a new visitor
7
- And I view "/"
8
- And I view "/subpage"
9
- And I am a new visitor
10
- And I view "/"
5
+ And I add an experiment "sweet"
11
6
  When I view "/admin/metry"
12
- Then I should see "Goals"
13
- And I should see "sweet: 2 visits"
14
- And I should see "Recent Visitors"
15
- And I should see "Visitor 1"
16
- And I should see "Visitor 2"
7
+ Then I should see "Experiments"
8
+ And I should see "sweet"
17
9
 
@@ -0,0 +1,28 @@
1
+ Feature: Track Experiments
2
+
3
+ Background:
4
+ Given an empty tracking database
5
+ And I add an experiment "Fred"
6
+
7
+ Scenario: Add a goal
8
+ Given I view "/admin/metry"
9
+ And I follow "Fred"
10
+ And I follow "New Goal"
11
+ And I fill in "name" with "Cool"
12
+ And I fill in "path" with "/goal"
13
+ And I press "Create"
14
+ Then I should be on the page for experiment #1
15
+ And I should see "Cool"
16
+ And I should see "Path: /goal"
17
+
18
+ Scenario: Edit a Goal
19
+ Given I add a goal named "Bogus" to experiment "Fred" with path "/"
20
+ When I view "/admin/metry"
21
+ And I follow "Fred"
22
+ And I follow "Edit"
23
+ And I fill in "name" with "Right"
24
+ And I fill in "path" with "/subpage"
25
+ And I press "Save"
26
+ Then I should be on the page for experiment #1
27
+ And I should see "Right"
28
+ And I should see "Path: /subpage"
@@ -12,8 +12,8 @@ Feature: Psycho Visitor Tracking
12
12
  And I am a new visitor
13
13
  And I view "/"
14
14
  When I view "/admin/metry"
15
- Then I should see "Visitor 1"
16
- And I should see "Visitor 2"
15
+ Then I should see visitor #1
16
+ And I should see visitor #2
17
17
 
18
18
  Scenario: View visitor detail
19
19
  Given I view "/"
@@ -21,7 +21,7 @@ Feature: Psycho Visitor Tracking
21
21
  And I am a new visitor
22
22
  And I view "/"
23
23
  When I view "/admin/metry"
24
- And I follow "Visitor 1"
24
+ And I follow "Visitor"
25
25
  Then I should see "/"
26
26
  And I should see "/subpage"
27
27
 
@@ -29,4 +29,4 @@ Feature: Psycho Visitor Tracking
29
29
  Given I view "/admin/metry"
30
30
  And I view "/admin/metry"
31
31
  When I view "/admin/metry"
32
- Then I should not see "Visitor 1"
32
+ Then I should see "0 events"
@@ -0,0 +1,8 @@
1
+ Given /^I add an experiment "([^\"]*)"$/ do |name|
2
+ Metry::Experiment.create(:name => name)
3
+ end
4
+
5
+ Given /^I add a goal named "([^\"]*)" to experiment "([^\"]*)" with path "([^\"]*)"$/ do |name, experiment, path|
6
+ experiment = Metry::Experiment.find(:first, :conditions => {:name => experiment})
7
+ experiment.goals << Metry::Goal.create(:name => name, :path => path)
8
+ end
@@ -0,0 +1,14 @@
1
+ Then /^I should see visitor #(\d+)$/ do |index|
2
+ visitor = at(Metry::Visitor, index)
3
+ assert_contain "Visitor #{visitor.id}"
4
+ end
5
+
6
+ Then /^I should not see visitor #(\d+)$/ do |index|
7
+ visitor = at(Metry::Visitor, index)
8
+ assert_not_contain "Visitor #{visitor.id}"
9
+ end
10
+
11
+ Then /^I should be on the page for experiment #(\d+)$/ do |index|
12
+ experiment = at(Metry::Experiment, index)
13
+ assert_equal "/admin/metry/experiments/#{experiment.id}", current_url
14
+ end
@@ -1,43 +1,75 @@
1
1
  Given /^an empty tracking database$/ do
2
- Metry.current.clear
2
+ Metry.clear
3
3
  end
4
4
 
5
5
  Then /^there should be (\d+) tracking events?$/ do |event_count|
6
- assert_equal(event_count.to_i, Metry.current.event_count)
6
+ assert_equal(event_count.to_i, Metry::Event.count)
7
7
  end
8
8
 
9
9
  Then /^there should be (\d+) visitors$/ do |visitor_count|
10
- assert_equal(visitor_count.to_i, Metry.current.visitor_count)
10
+ assert_equal(visitor_count.to_i, Metry::Visitor.count)
11
11
  end
12
12
 
13
- When /^there should be a tracking event "(\d+)":$/ do |id, table|
14
- event = Metry.current.event(id)
15
- assert event, "Unable to lookup event #{id}."
16
- table.hashes.each do |hash|
17
- expected = hash["value"]
13
+ Then /^tracking event #(\d+) should contain:$/ do |index, table|
14
+ event = at(Metry::Event, index)
15
+ assert event, "Unable to lookup event at #{index}."
16
+ table.rows_hash.each do |key, expected|
18
17
  case expected
19
18
  when "_exists_"
20
- assert event[hash["key"]], "Key #{hash["key"]} does not exist."
19
+ assert event.send(key), "Key #{key} does not exist."
21
20
  else
22
- assert_equal expected, event[hash["key"]], "Key #{hash["key"]} does not match."
21
+ assert_equal expected, event.send(key), "Key #{key} does not match."
23
22
  end
24
23
  end
25
24
  end
26
25
 
27
- Then /^there should be a visitor "([^\"]*)":$/ do |id, table|
28
- visitor = Metry.current.visitor(id)
29
- assert visitor, "Unable to lookup visitor #{id}."
30
- table.hashes.each do |hash|
31
- expected = hash["value"]
32
- case expected
33
- when "_exists_"
34
- assert visitor[hash["key"]], "Key #{hash["key"]} does not exist."
35
- else
36
- assert_equal expected, visitor[hash["key"]], "Key #{hash["key"]} does not match."
37
- end
26
+ Then /^tracking event #(\d+) extra should contain:$/ do |index, table|
27
+ event = at(Metry::Event, index)
28
+ table.rows_hash.each do |key, expected|
29
+ assert_equal expected, event.extra[key]
38
30
  end
39
31
  end
40
32
 
41
- Then /^there should be a visitor "([^\"]*)"$/ do |id|
42
- assert Metry.current.visitor(id)
43
- end
33
+ Then /^there should be a tracking event #(\d+) with visitor #(\d+)$/ do |event_index, visitor_index|
34
+ event = at(Metry::Event, event_index)
35
+ visitor = at(Metry::Visitor, visitor_index)
36
+ assert_equal event.visitor, visitor
37
+ end
38
+
39
+ Then /^there should be a visitor #(\d+)$/ do |index|
40
+ assert at(Metry::Visitor, index)
41
+ end
42
+
43
+ Then /^visitor #(\d+) should have experiment "([^\"]*)" with "([^\"]*)"$/ do |index, experiment, alternative|
44
+ visitor = at(Metry::Visitor, index)
45
+ experiment = Metry::Experiment.find(:first, :conditions => {:name => experiment})
46
+ assert experiment.cohort_for(visitor)
47
+ end
48
+
49
+ Then /^event #(\d+) should have experiment "([^\"]*)" with "([^\"]*)"$/ do |index, experiment, alternative|
50
+ event = at(Metry::Event, index)
51
+ experiment = Metry::Experiment.find(:first, :conditions => {:name => experiment})
52
+ assert_equal alternative, event.experiments[experiment.id]
53
+ end
54
+
55
+ Then /^I should see the same page (\d+) times$/ do |count|
56
+ expected_body = webrat.response_body
57
+ count.to_i.times do
58
+ When(%(I view "#{current_url}"))
59
+ assert_equal expected_body, webrat.response_body
60
+ end
61
+ end
62
+
63
+ When /^(\d+) visitors view "([^\"]*)"$/ do |count, path|
64
+ @alternatives = Hash.new(0)
65
+ count.to_i.times do
66
+ visit(path)
67
+ @alternatives[webrat.response_body] += 1
68
+ clear_cookies
69
+ end
70
+ end
71
+
72
+ Then /^there should be (\d+) alternatives each displayed at least (\d+) times$/ do |alternatives, minimum|
73
+ assert_equal alternatives.to_i, @alternatives.size
74
+ assert @alternatives.values.all?{|e| e >= minimum.to_i}
75
+ end
@@ -16,7 +16,6 @@ World(Webrat::Methods)
16
16
  World(Webrat::Matchers)
17
17
 
18
18
  require 'metry'
19
- Metry::Storage.predictable_keys = true
20
19
 
21
20
  require File.dirname(__FILE__) + '/../../example/example.rb'
22
21
  def app
@@ -0,0 +1,6 @@
1
+ module CucumberHelpers
2
+ def at(model, index)
3
+ model.find(:all, :order => 'created_at')[index.to_i-1]
4
+ end
5
+ end
6
+ World(CucumberHelpers)
@@ -1,18 +1,25 @@
1
1
  $: << File.dirname(__FILE__)
2
2
 
3
- require 'metry/storage'
3
+ require 'mongomapper'
4
+
5
+ require 'metry/event'
6
+ require 'metry/visitor'
7
+ require 'metry/goal'
4
8
  require 'metry/rack/tracking'
5
9
  require 'metry/experiment'
10
+ require 'metry/cohort'
6
11
  require 'metry/psycho'
7
12
 
8
13
  module Metry
9
- VERSION = '2.0.5'
14
+ VERSION = '2.1.0'
10
15
 
11
16
  def self.init(dbname)
12
- @storage = Storage.new(dbname)
17
+ MongoMapper.database = dbname
13
18
  end
14
19
 
15
- def self.current
16
- @storage
20
+ def self.clear
21
+ [Metry::Event, Metry::Visitor, Metry::Goal, Metry::Experiment].each do |m|
22
+ m.delete_all
23
+ end
17
24
  end
18
25
  end