yacc-vanity 1.5.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (59) hide show
  1. data/CHANGELOG +243 -0
  2. data/Gemfile +24 -0
  3. data/MIT-LICENSE +21 -0
  4. data/README.rdoc +74 -0
  5. data/Rakefile +189 -0
  6. data/bin/vanity +69 -0
  7. data/lib/vanity.rb +36 -0
  8. data/lib/vanity/adapters/abstract_adapter.rb +135 -0
  9. data/lib/vanity/adapters/active_record_adapter.rb +304 -0
  10. data/lib/vanity/adapters/mock_adapter.rb +157 -0
  11. data/lib/vanity/adapters/mongodb_adapter.rb +162 -0
  12. data/lib/vanity/adapters/redis_adapter.rb +154 -0
  13. data/lib/vanity/backport.rb +26 -0
  14. data/lib/vanity/commands/list.rb +21 -0
  15. data/lib/vanity/commands/report.rb +64 -0
  16. data/lib/vanity/commands/upgrade.rb +34 -0
  17. data/lib/vanity/experiment/ab_test.rb +482 -0
  18. data/lib/vanity/experiment/base.rb +212 -0
  19. data/lib/vanity/frameworks/rails.rb +245 -0
  20. data/lib/vanity/helpers.rb +59 -0
  21. data/lib/vanity/metric/active_record.rb +83 -0
  22. data/lib/vanity/metric/base.rb +244 -0
  23. data/lib/vanity/metric/google_analytics.rb +83 -0
  24. data/lib/vanity/metric/remote.rb +53 -0
  25. data/lib/vanity/playground.rb +332 -0
  26. data/lib/vanity/templates/_ab_test.erb +26 -0
  27. data/lib/vanity/templates/_experiment.erb +5 -0
  28. data/lib/vanity/templates/_experiments.erb +7 -0
  29. data/lib/vanity/templates/_metric.erb +14 -0
  30. data/lib/vanity/templates/_metrics.erb +13 -0
  31. data/lib/vanity/templates/_report.erb +27 -0
  32. data/lib/vanity/templates/flot.min.js +1 -0
  33. data/lib/vanity/templates/jquery.min.js +19 -0
  34. data/lib/vanity/templates/vanity.css +26 -0
  35. data/lib/vanity/templates/vanity.js +82 -0
  36. data/lib/vanity/version.rb +11 -0
  37. data/test/experiment/ab_test.rb +700 -0
  38. data/test/experiment/base_test.rb +136 -0
  39. data/test/experiments/age_and_zipcode.rb +19 -0
  40. data/test/experiments/metrics/cheers.rb +3 -0
  41. data/test/experiments/metrics/signups.rb +2 -0
  42. data/test/experiments/metrics/yawns.rb +3 -0
  43. data/test/experiments/null_abc.rb +5 -0
  44. data/test/metric/active_record_test.rb +249 -0
  45. data/test/metric/base_test.rb +293 -0
  46. data/test/metric/google_analytics_test.rb +104 -0
  47. data/test/metric/remote_test.rb +108 -0
  48. data/test/myapp/app/controllers/application_controller.rb +2 -0
  49. data/test/myapp/app/controllers/main_controller.rb +7 -0
  50. data/test/myapp/config/boot.rb +110 -0
  51. data/test/myapp/config/environment.rb +10 -0
  52. data/test/myapp/config/environments/production.rb +0 -0
  53. data/test/myapp/config/routes.rb +3 -0
  54. data/test/passenger_test.rb +43 -0
  55. data/test/playground_test.rb +10 -0
  56. data/test/rails_test.rb +294 -0
  57. data/test/test_helper.rb +134 -0
  58. data/vanity.gemspec +25 -0
  59. metadata +161 -0
@@ -0,0 +1,136 @@
1
+ require "test/test_helper"
2
+
3
+ class ExperimentTest < Test::Unit::TestCase
4
+
5
+ def setup
6
+ super
7
+ metric "Happiness"
8
+ end
9
+
10
+ # -- Defining experiment --
11
+
12
+ def test_can_access_experiment_by_id
13
+ exp = new_ab_test(:ice_cream_flavor) { metrics :happiness }
14
+ assert_equal exp, experiment(:ice_cream_flavor)
15
+ end
16
+
17
+ def test_fail_when_defining_same_experiment_twice
18
+ File.open "tmp/experiments/ice_cream_flavor.rb", "w" do |f|
19
+ f.write <<-RUBY
20
+ ab_test "Ice Cream Flavor" do
21
+ metrics :happiness
22
+ end
23
+ ab_test "Ice Cream Flavor" do
24
+ metrics :happiness
25
+ end
26
+ RUBY
27
+ end
28
+ assert_raises NameError do
29
+ experiment(:ice_cream_flavor)
30
+ end
31
+ end
32
+
33
+
34
+ # -- Loading experiments --
35
+
36
+ def test_fails_if_cannot_load_named_experiment
37
+ assert_raises NameError do
38
+ experiment(:ice_cream_flavor)
39
+ end
40
+ end
41
+
42
+ def test_loading_experiment
43
+ File.open "tmp/experiments/ice_cream_flavor.rb", "w" do |f|
44
+ f.write <<-RUBY
45
+ ab_test "Ice Cream Flavor" do
46
+ def xmts
47
+ "x"
48
+ end
49
+ metrics :happiness
50
+ end
51
+ RUBY
52
+ end
53
+ assert_equal "x", experiment(:ice_cream_flavor).xmts
54
+ end
55
+
56
+ def test_fails_if_error_loading_experiment
57
+ File.open "tmp/experiments/ice_cream_flavor.rb", "w" do |f|
58
+ f.write "fail 'yawn!'"
59
+ end
60
+ assert_raises NameError do
61
+ experiment(:ice_cream_flavor)
62
+ end
63
+ end
64
+
65
+ def test_complains_if_not_defined_where_expected
66
+ File.open "tmp/experiments/ice_cream_flavor.rb", "w" do |f|
67
+ f.write ""
68
+ end
69
+ assert_raises NameError do
70
+ experiment(:ice_cream_flavor)
71
+ end
72
+ end
73
+
74
+ def test_reloading_experiments
75
+ new_ab_test(:ab) { metrics :happiness }
76
+ new_ab_test(:cd) { metrics :happiness }
77
+ assert_equal 2, Vanity.playground.experiments.size
78
+ Vanity.playground.reload!
79
+ assert Vanity.playground.experiments.empty?
80
+ end
81
+
82
+
83
+ # -- Attributes --
84
+
85
+ def test_experiment_mapping_name_to_id
86
+ experiment = new_ab_test("Ice Cream Flavor/Tastes") { metrics :happiness }
87
+ assert_equal "Ice Cream Flavor/Tastes", experiment.name
88
+ assert_equal :ice_cream_flavor_tastes, experiment.id
89
+ end
90
+
91
+ def test_saving_experiment_after_definition
92
+ File.open "tmp/experiments/ice_cream_flavor.rb", "w" do |f|
93
+ f.write <<-RUBY
94
+ ab_test "Ice Cream Flavor" do
95
+ metrics :happiness
96
+ expects(:save)
97
+ end
98
+ RUBY
99
+ end
100
+ Vanity.playground.experiment(:ice_cream_flavor)
101
+ end
102
+
103
+ def test_experiment_has_created_timestamp
104
+ new_ab_test(:ice_cream_flavor) { metrics :happiness }
105
+ assert_instance_of Time, experiment(:ice_cream_flavor).created_at
106
+ assert_in_delta experiment(:ice_cream_flavor).created_at.to_i, Time.now.to_i, 1
107
+ end
108
+
109
+ def test_experiment_keeps_created_timestamp_across_definitions
110
+ past = Date.today - 1
111
+ Timecop.freeze past do
112
+ new_ab_test(:ice_cream_flavor) { metrics :happiness }
113
+ assert_equal past.to_time.to_i, experiment(:ice_cream_flavor).created_at.to_i
114
+ end
115
+
116
+ new_playground
117
+ metric :happiness
118
+ new_ab_test(:ice_cream_flavor) { metrics :happiness }
119
+ assert_equal past.to_time.to_i, experiment(:ice_cream_flavor).created_at.to_i
120
+ end
121
+
122
+ def test_experiment_has_description
123
+ new_ab_test :ice_cream_flavor do
124
+ description "Because 31 is not enough ..."
125
+ metrics :happiness
126
+ end
127
+ assert_equal "Because 31 is not enough ...", experiment(:ice_cream_flavor).description
128
+ end
129
+
130
+ def test_experiment_stores_nothing_when_collection_disabled
131
+ not_collecting!
132
+ new_ab_test(:ice_cream_flavor) { metrics :happiness }
133
+ experiment(:ice_cream_flavor).complete!
134
+ end
135
+
136
+ end
@@ -0,0 +1,19 @@
1
+ ab_test "Age and Zipcode" do
2
+ description <<-TEXT
3
+ Testing new registration form that asks for age and zipcode. Option A presents
4
+ the existing form, and option B adds age and zipcode fields.
5
+
6
+ We know option B will convert less, but higher quality leads. If we lose less
7
+ than 20% conversions, we're going to switch to option B.
8
+ TEXT
9
+ metrics :signups
10
+
11
+ complete_if do
12
+ alternatives.all? { |alt| alt.participants > 100 }
13
+ end
14
+ outcome_is do
15
+ one_field = alternative(false)
16
+ three_fields = alternative(true)
17
+ three_fields.conversion_rate >= 0.8 * one_field.conversion_rate ? three_fields : one_field
18
+ end
19
+ end
@@ -0,0 +1,3 @@
1
+ metric "Cheers" do
2
+ description "They love us, don't they?"
3
+ end
@@ -0,0 +1,2 @@
1
+ metric "Signups" do
2
+ end
@@ -0,0 +1,3 @@
1
+ metric "Yawns" do
2
+ description "How many yawns/sec can our video-sharing micro-blogging social network elicit?"
3
+ end
@@ -0,0 +1,5 @@
1
+ ab_test "Null/ABC" do
2
+ description "Testing three alternatives"
3
+ alternatives nil, :red, :green, :blue
4
+ metrics :signups
5
+ end
@@ -0,0 +1,249 @@
1
+ require "test/test_helper"
2
+
3
+ class Sky < ActiveRecord::Base
4
+ connection.drop_table :skies if table_exists?
5
+ connection.create_table :skies do |t|
6
+ t.integer :height
7
+ t.timestamps
8
+ end
9
+
10
+ named_scope :high, lambda { { :conditions=>"height >= 4" } }
11
+ end
12
+
13
+
14
+ context "ActiveRecord Metric" do
15
+
16
+ test "record count" do
17
+ File.open "tmp/experiments/metrics/sky_is_limit.rb", "w" do |f|
18
+ f.write <<-RUBY
19
+ metric "Sky is limit" do
20
+ model Sky
21
+ end
22
+ RUBY
23
+ end
24
+ Vanity.playground.metrics
25
+ Sky.create!
26
+ assert_equal 1, Sky.count
27
+ assert_equal 1, Vanity::Metric.data(metric(:sky_is_limit)).last.last
28
+ end
29
+
30
+ test "record sum" do
31
+ File.open "tmp/experiments/metrics/sky_is_limit.rb", "w" do |f|
32
+ f.write <<-RUBY
33
+ metric "Sky is limit" do
34
+ model Sky, :sum=>:height
35
+ end
36
+ RUBY
37
+ end
38
+ Vanity.playground.metrics
39
+ Sky.create! :height=>4
40
+ Sky.create! :height=>2
41
+ assert_equal 6, Vanity::Metric.data(metric(:sky_is_limit)).last.last
42
+ end
43
+
44
+ test "record average" do
45
+ File.open "tmp/experiments/metrics/sky_is_limit.rb", "w" do |f|
46
+ f.write <<-RUBY
47
+ metric "Sky is limit" do
48
+ model Sky, :average=>:height
49
+ end
50
+ RUBY
51
+ end
52
+ Vanity.playground.metrics
53
+ Sky.create! :height=>8
54
+ Sky.create! :height=>2
55
+ assert_equal 5, Vanity::Metric.data(metric(:sky_is_limit)).last.last
56
+ end
57
+
58
+ test "record minimum" do
59
+ File.open "tmp/experiments/metrics/sky_is_limit.rb", "w" do |f|
60
+ f.write <<-RUBY
61
+ metric "Sky is limit" do
62
+ model Sky, :minimum=>:height
63
+ end
64
+ RUBY
65
+ end
66
+ Vanity.playground.metrics
67
+ Sky.create! :height=>4
68
+ Sky.create! :height=>2
69
+ assert_equal 2, Vanity::Metric.data(metric(:sky_is_limit)).last.last
70
+ end
71
+
72
+ test "record maximum" do
73
+ File.open "tmp/experiments/metrics/sky_is_limit.rb", "w" do |f|
74
+ f.write <<-RUBY
75
+ metric "Sky is limit" do
76
+ model Sky, :maximum=>:height
77
+ end
78
+ RUBY
79
+ end
80
+ Vanity.playground.metrics
81
+ Sky.create! :height=>4
82
+ Sky.create! :height=>2
83
+ assert_equal 4, Vanity::Metric.data(metric(:sky_is_limit)).last.last
84
+ end
85
+
86
+ test "with conditions" do
87
+ File.open "tmp/experiments/metrics/sky_is_limit.rb", "w" do |f|
88
+ f.write <<-RUBY
89
+ metric "Sky is limit" do
90
+ model Sky, :sum=>:height, :conditions=>["height > 4"]
91
+ end
92
+ RUBY
93
+ end
94
+ Vanity.playground.metrics
95
+ high_skies = 0
96
+ metric(:sky_is_limit).hook do |metric_id, timestamp, height|
97
+ assert height > 4
98
+ high_skies += height
99
+ end
100
+ [nil,5,3,6].each do |height|
101
+ Sky.create! :height=>height
102
+ end
103
+ assert_equal 11, Vanity::Metric.data(metric(:sky_is_limit)).sum(&:last)
104
+ assert_equal 11, high_skies
105
+ end
106
+
107
+ test "with scope" do
108
+ File.open "tmp/experiments/metrics/sky_is_limit.rb", "w" do |f|
109
+ f.write <<-RUBY
110
+ metric "Sky is limit" do
111
+ model Sky.high
112
+ end
113
+ RUBY
114
+ end
115
+ Vanity.playground.metrics
116
+ total = 0
117
+ metric(:sky_is_limit).hook do |metric_id, timestamp, count|
118
+ total += count
119
+ end
120
+ Sky.create! :height=>4
121
+ Sky.create! :height=>2
122
+ assert_equal 1, Vanity::Metric.data(metric(:sky_is_limit)).last.last
123
+ assert_equal 1, total
124
+ end
125
+
126
+ test "hooks" do
127
+ File.open "tmp/experiments/metrics/sky_is_limit.rb", "w" do |f|
128
+ f.write <<-RUBY
129
+ metric "Sky is limit" do
130
+ model Sky, :sum=>:height
131
+ end
132
+ RUBY
133
+ end
134
+ Vanity.playground.metrics
135
+ total = 0
136
+ metric(:sky_is_limit).hook do |metric_id, timestamp, count|
137
+ assert_equal :sky_is_limit, metric_id
138
+ assert_in_delta Time.now.to_i, timestamp.to_i, 1
139
+ total += count
140
+ end
141
+ Sky.create! :height=>4
142
+ assert_equal 4, total
143
+ end
144
+
145
+ test "no hooks when metrics disabled" do
146
+ not_collecting!
147
+ File.open "tmp/experiments/metrics/sky_is_limit.rb", "w" do |f|
148
+ f.write <<-RUBY
149
+ metric "Sky is limit" do
150
+ model Sky, :sum=>:height
151
+ end
152
+ RUBY
153
+ end
154
+ Vanity.playground.metrics
155
+ total = 0
156
+ metric(:sky_is_limit).hook do |metric_id, timestamp, count|
157
+ total += count
158
+ end
159
+ Sky.create! :height=>4
160
+ assert_equal 0, total
161
+ end
162
+
163
+ test "after_create not after_save" do
164
+ File.open "tmp/experiments/metrics/sky_is_limit.rb", "w" do |f|
165
+ f.write <<-RUBY
166
+ metric "Sky is limit" do
167
+ model Sky
168
+ end
169
+ RUBY
170
+ end
171
+ Vanity.playground.metrics
172
+ once = nil
173
+ metric(:sky_is_limit).hook do
174
+ fail "Metric tracked twice" if once
175
+ once = true
176
+ end
177
+ Sky.create!
178
+ Sky.last.update_attributes :height=>4
179
+ end
180
+
181
+ test "with after_save" do
182
+ File.open "tmp/experiments/metrics/sky_is_limit.rb", "w" do |f|
183
+ f.write <<-RUBY
184
+ metric "Sky is limit" do
185
+ model Sky, :conditions=>["height > 3"]
186
+ Sky.after_save { |sky| track! if sky.height_changed? && sky.height > 3 }
187
+ end
188
+ RUBY
189
+ end
190
+ Vanity.playground.metrics
191
+ times = 0
192
+ metric(:sky_is_limit).hook do
193
+ times += 1
194
+ end
195
+ Sky.create!
196
+ (1..5).each do |height|
197
+ Sky.last.update_attributes! :height=>height
198
+ end
199
+ assert_equal 2, times
200
+ end
201
+
202
+ test "do it youself" do
203
+ File.open "tmp/experiments/metrics/sky_is_limit.rb", "w" do |f|
204
+ f.write <<-RUBY
205
+ metric "Sky is limit" do
206
+ Sky.after_save { |sky| track! if sky.height_changed? && sky.height > 3 }
207
+ end
208
+ RUBY
209
+ end
210
+ Vanity.playground.metrics
211
+ (1..5).each do |height|
212
+ Sky.create! :height=>height
213
+ end
214
+ Sky.first.update_attributes! :height=>4
215
+ assert_equal 3, Vanity::Metric.data(metric(:sky_is_limit)).last.last
216
+ end
217
+
218
+ test "last update for new metric" do
219
+ File.open "tmp/experiments/metrics/sky_is_limit.rb", "w" do |f|
220
+ f.write <<-RUBY
221
+ metric "Sky is limit" do
222
+ model Sky
223
+ end
224
+ RUBY
225
+ end
226
+ assert_nil metric(:sky_is_limit).last_update_at
227
+ end
228
+
229
+ test "last update with records" do
230
+ File.open "tmp/experiments/metrics/sky_is_limit.rb", "w" do |f|
231
+ f.write <<-RUBY
232
+ metric "Sky is limit" do
233
+ model Sky
234
+ end
235
+ RUBY
236
+ end
237
+ Sky.create! :height=>1
238
+ Timecop.freeze Time.now + 1.day do
239
+ Sky.create! :height=>1
240
+ end
241
+ assert_in_delta metric(:sky_is_limit).last_update_at.to_i, (Time.now + 1.day).to_i, 1
242
+ end
243
+
244
+ teardown do
245
+ Sky.delete_all
246
+ Sky.after_create.clear
247
+ Sky.after_save.clear
248
+ end
249
+ end
@@ -0,0 +1,293 @@
1
+ require "test/test_helper"
2
+
3
+
4
+ context "Metric via playground" do
5
+
6
+ test "knows all loaded metrics" do
7
+ metric "Yawns/sec", "Cheers/sec"
8
+ assert Vanity.playground.metrics.keys.include?(:yawns_sec)
9
+ assert Vanity.playground.metrics.keys.include?(:cheers_sec)
10
+ end
11
+
12
+ test "loads metric definitions" do
13
+ File.open "tmp/experiments/metrics/yawns_sec.rb", "w" do |f|
14
+ f.write <<-RUBY
15
+ metric "Yawns/sec" do
16
+ def xmts
17
+ "x"
18
+ end
19
+ end
20
+ RUBY
21
+ end
22
+ assert_equal "x", Vanity.playground.metric(:yawns_sec).xmts
23
+ end
24
+
25
+ test "bubbles up loaded metrics" do
26
+ File.open "tmp/experiments/metrics/yawns_sec.rb", "w" do |f|
27
+ f.write "fail 'yawn!'"
28
+ end
29
+ assert_raises NameError do
30
+ Vanity.playground.metric(:yawns_sec)
31
+ end
32
+ end
33
+
34
+ test "map identifier from file name" do
35
+ File.open "tmp/experiments/metrics/yawns_sec.rb", "w" do |f|
36
+ f.write <<-RUBY
37
+ metric "yawns/hour" do
38
+ end
39
+ RUBY
40
+ end
41
+ assert Vanity.playground.metric(:yawns_sec)
42
+ end
43
+
44
+ test "fails tracking unknown metric" do
45
+ assert_raises NameError do
46
+ Vanity.playground.track! :yawns_sec
47
+ end
48
+ end
49
+
50
+ test "reloading metrics" do
51
+ metric "Yawns/sec", "Cheers/sec"
52
+ Vanity.playground.metric(:yawns_sec)
53
+ Vanity.playground.metric(:cheers_sec)
54
+ assert_equal 2, Vanity.playground.metrics.size
55
+ metrics = Vanity.playground.metrics.values
56
+ Vanity.playground.reload!
57
+ assert_equal 0, Vanity.playground.metrics.size
58
+ assert_not_equal metrics, Vanity.playground.metrics.values
59
+ end
60
+
61
+ test "ignores undefined metrics in database" do
62
+ metric "Yawns/sec"
63
+ Vanity.playground.reload!
64
+ assert Vanity.playground.metrics.empty?
65
+ end
66
+
67
+ end
68
+
69
+
70
+ context "Metric tracking" do
71
+ test "disabled when metrics are disabled" do
72
+ not_collecting!
73
+ metric "Yawns/sec", "Cheers/sec"
74
+ Vanity.playground.track! :yawns_sec
75
+ Vanity.playground.track! :cheers_sec
76
+ end
77
+
78
+ test "can count" do
79
+ metric "Yawns/sec", "Cheers/sec"
80
+ 4.times { Vanity.playground.track! :yawns_sec }
81
+ 2.times { Vanity.playground.track! :cheers_sec }
82
+ yawns = Vanity.playground.metric(:yawns_sec).values(today, today).first
83
+ cheers = Vanity.playground.metric(:cheers_sec).values(today, today).first
84
+ assert yawns = 2 * cheers
85
+ end
86
+
87
+ test "can tell the time" do
88
+ metric "Yawns/sec"
89
+ Timecop.freeze(today - 4) { 4.times { Vanity.playground.track! :yawns_sec } }
90
+ Timecop.freeze(today - 2) { 2.times { Vanity.playground.track! :yawns_sec } }
91
+ 1.times { Vanity.playground.track! :yawns_sec }
92
+ boredom = Vanity.playground.metric(:yawns_sec).values(today - 5, today)
93
+ assert_equal [0,4,0,2,0,1], boredom
94
+ end
95
+
96
+ test "with no value" do
97
+ metric "Yawns/sec", "Cheers/sec", "Looks"
98
+ Vanity.playground.track! :yawns_sec, 0
99
+ Vanity.playground.track! :cheers_sec
100
+ assert_equal 0, Vanity.playground.metric(:yawns_sec).values(today, today).sum
101
+ assert_equal 1, Vanity.playground.metric(:cheers_sec).values(today, today).sum
102
+ end
103
+
104
+ test "with count" do
105
+ metric "Yawns/sec"
106
+ Timecop.freeze(today - 4) { Vanity.playground.track! :yawns_sec, 4 }
107
+ Timecop.freeze(today - 2) { Vanity.playground.track! :yawns_sec, 2 }
108
+ Vanity.playground.track! :yawns_sec
109
+ boredom = Vanity.playground.metric(:yawns_sec).values(today - 5, today)
110
+ assert_equal [0,4,0,2,0,1], boredom
111
+ end
112
+
113
+ test "runs hook" do
114
+ metric "Many Happy Returns"
115
+ total = 0
116
+ Vanity.playground.metric(:many_happy_returns).hook do |metric_id, timestamp, count|
117
+ assert_equal :many_happy_returns, metric_id
118
+ assert_in_delta Time.now.to_i, timestamp.to_i, 1
119
+ total += count
120
+ end
121
+ Vanity.playground.track! :many_happy_returns, 6
122
+ assert_equal 6, total
123
+ end
124
+
125
+ test "doesn't runs hook when metrics disabled" do
126
+ not_collecting!
127
+ metric "Many Happy Returns"
128
+ total = 0
129
+ Vanity.playground.metric(:many_happy_returns).hook do |metric_id, timestamp, count|
130
+ total += count
131
+ end
132
+ Vanity.playground.track! :many_happy_returns, 6
133
+ assert_equal 0, total
134
+ end
135
+
136
+ test "runs multiple hooks" do
137
+ metric "Many Happy Returns"
138
+ returns = 0
139
+ Vanity.playground.metric(:many_happy_returns).hook { returns += 1 }
140
+ Vanity.playground.metric(:many_happy_returns).hook { returns += 1 }
141
+ Vanity.playground.metric(:many_happy_returns).hook { returns += 1 }
142
+ Vanity.playground.track! :many_happy_returns
143
+ assert_equal 3, returns
144
+ end
145
+
146
+ test "destroy wipes metrics" do
147
+ metric "Many Happy Returns"
148
+ Vanity.playground.track! :many_happy_returns, 3
149
+ assert_equal [3], Vanity.playground.metric(:many_happy_returns).values(today, today)
150
+ Vanity.playground.metric(:many_happy_returns).destroy!
151
+ assert_equal [0], Vanity.playground.metric(:many_happy_returns).values(today, today)
152
+ end
153
+ end
154
+
155
+
156
+ context "Metric name" do
157
+ test "can be whatever" do
158
+ File.open "tmp/experiments/metrics/yawns_sec.rb", "w" do |f|
159
+ f.write <<-RUBY
160
+ metric "Yawns per second" do
161
+ end
162
+ RUBY
163
+ end
164
+ assert_equal "Yawns per second", Vanity.playground.metric(:yawns_sec).name
165
+ end
166
+ end
167
+
168
+
169
+ context "Metric description" do
170
+ test "metric with description" do
171
+ File.open "tmp/experiments/metrics/yawns_sec.rb", "w" do |f|
172
+ f.write <<-RUBY
173
+ metric "Yawns/sec" do
174
+ description "Am I that boring?"
175
+ end
176
+ RUBY
177
+ end
178
+ assert_equal "Am I that boring?", Vanity::Metric.description(Vanity.playground.metric(:yawns_sec))
179
+ end
180
+
181
+ test "metric without description" do
182
+ File.open "tmp/experiments/metrics/yawns_sec.rb", "w" do |f|
183
+ f.write <<-RUBY
184
+ metric "Yawns/sec" do
185
+ end
186
+ RUBY
187
+ end
188
+ assert_nil Vanity::Metric.description(Vanity.playground.metric(:yawns_sec))
189
+ end
190
+
191
+ test "metric with no method description" do
192
+ metric = Object.new
193
+ assert_nil Vanity::Metric.description(metric)
194
+ end
195
+ end
196
+
197
+
198
+ context "Metric bounds" do
199
+ test "metric with bounds" do
200
+ File.open "tmp/experiments/metrics/sky_is_limit.rb", "w" do |f|
201
+ f.write <<-RUBY
202
+ metric "Sky is limit" do
203
+ def bounds
204
+ [6,12]
205
+ end
206
+ end
207
+ RUBY
208
+ end
209
+ assert_equal [6,12], Vanity::Metric.bounds(Vanity.playground.metric(:sky_is_limit))
210
+ end
211
+
212
+ test "metric without bounds" do
213
+ metric "Sky is limit"
214
+ assert_equal [nil, nil], Vanity::Metric.bounds(Vanity.playground.metric(:sky_is_limit))
215
+ end
216
+
217
+ test "metric with no method bounds" do
218
+ metric = Object.new
219
+ assert_equal [nil, nil], Vanity::Metric.bounds(metric)
220
+ end
221
+ end
222
+
223
+
224
+ context "Metric last_update_at" do
225
+ test "for new metric" do
226
+ metric "Coolness"
227
+ metric = Vanity.playground.metric(:coolness)
228
+ assert_nil metric.last_update_at
229
+ end
230
+
231
+ test "with data point" do
232
+ metric "Coolness"
233
+ metric = Vanity.playground.metric(:coolness)
234
+ metric.track!
235
+ Timecop.freeze Time.now + 1.day do
236
+ metric.track!
237
+ end
238
+ assert_in_delta metric.last_update_at.to_i, (Time.now + 1.day).to_i, 1
239
+ end
240
+ end
241
+
242
+
243
+ context "Metric data" do
244
+ test "explicit dates" do
245
+ metric "Yawns/sec"
246
+ Timecop.freeze(today - 4) { Vanity.playground.track! :yawns_sec, 4 }
247
+ Timecop.freeze(today - 2) { Vanity.playground.track! :yawns_sec, 2 }
248
+ Vanity.playground.track! :yawns_sec
249
+ boredom = Vanity::Metric.data(Vanity.playground.metric(:yawns_sec), Date.today - 5, Date.today)
250
+ assert_equal [[today - 5, 0], [today - 4, 4], [today - 3, 0], [today - 2, 2], [today - 1, 0], [today, 1]], boredom
251
+ end
252
+
253
+ test "start date only" do
254
+ metric "Yawns/sec"
255
+ Timecop.freeze(today - 4) { Vanity.playground.track! :yawns_sec, 4 }
256
+ Timecop.freeze(today - 2) { Vanity.playground.track! :yawns_sec, 2 }
257
+ Vanity.playground.track! :yawns_sec
258
+ boredom = Vanity::Metric.data(Vanity.playground.metric(:yawns_sec), Date.today - 4)
259
+ assert_equal [[today - 4, 4], [today - 3, 0], [today - 2, 2], [today - 1, 0], [today, 1]], boredom
260
+ end
261
+
262
+ test "start date and duration" do
263
+ metric "Yawns/sec"
264
+ Timecop.freeze(today - 4) { Vanity.playground.track! :yawns_sec, 4 }
265
+ Timecop.freeze(today - 2) { Vanity.playground.track! :yawns_sec, 2 }
266
+ Vanity.playground.track! :yawns_sec
267
+ boredom = Vanity::Metric.data(Vanity.playground.metric(:yawns_sec), 5)
268
+ assert_equal [[today - 4, 4], [today - 3, 0], [today - 2, 2], [today - 1, 0], [today, 1]], boredom
269
+ end
270
+
271
+ test "no data" do
272
+ metric "Yawns/sec"
273
+ boredom = Vanity::Metric.data(Vanity.playground.metric(:yawns_sec))
274
+ assert_equal 90, boredom.size
275
+ assert_equal [today - 89, 0], boredom.first
276
+ assert_equal [today, 0], boredom.last
277
+ end
278
+
279
+ test "using custom values method" do
280
+ File.open "tmp/experiments/metrics/hours_in_day.rb", "w" do |f|
281
+ f.write <<-RUBY
282
+ metric "Hours in day" do
283
+ def values(from, to)
284
+ (from..to).map { |d| 24 }
285
+ end
286
+ end
287
+ RUBY
288
+ end
289
+ data = Vanity::Metric.data(Vanity.playground.metric(:hours_in_day))
290
+ assert_equal [24] * 90, data.map(&:last)
291
+ end
292
+
293
+ end