experimental 0.2.0 → 0.2.1

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.
checksums.yaml CHANGED
@@ -1,7 +1,15 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 1c78c9b7d6c365503d9c865f63b3e24f7abbdec5
4
- data.tar.gz: adc2a47c070863a3a87432d4eca968614155d3a9
5
- SHA512:
6
- metadata.gz: 9eee13366381e3d96a44abc8da8b003c405850a140f96091ec7d8410dad321d3501b4ac3577976217d5a46b279b6cdbc7704cd219dedf6ab1633a05431b480b8
7
- data.tar.gz: 755c66a9193290985db2a6852a68c01edd3780fc94672d9691743fc6b02b3407051242ef30c8882b6753e98184e1f9a94850913976b878ba7a3b6cd76541b36d
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ Y2Y3MWRjY2E3ZThhNzZhNjFhNWJjMmVhYjA2YTlhNzA3NWUwYzljNQ==
5
+ data.tar.gz: !binary |-
6
+ ZDRmMjU5MTg5MDMwMmI4MjM5Y2IwMmU4M2ZmZDY1ZmIyYzZkODliOQ==
7
+ !binary "U0hBNTEy":
8
+ metadata.gz: !binary |-
9
+ MDVhMDA3ZDg3YzI1ZjY5ZGI3ZjMzYzU5YWViYWIwZTVhMzg5Mjg2ZTMxMzAy
10
+ YjIwYzllY2E3OWMyZTI3NmUwM2JlZGM3ZWU3N2UxOTFjMDU5Yzc1YmJjNGJh
11
+ NTY0ODhlMWQwMjgzYTRlNGE0YzMwMmUyMWEyYzAzZmFmNzkyYmQ=
12
+ data.tar.gz: !binary |-
13
+ ZWNiMzRkYzhmMzU2MmQ3NTA3YjVmOGVjOGZiODI2OTFiNmMwOWIzZDdkMmE2
14
+ YWQ4MDE2OGIyYjQ4MTU3MzE2NmEyMDcwYmI1NjgxYWJmZjE4ODkwOTVmZTA2
15
+ YTk0YzM4N2UxZjliMTM5MDdjM2MxODc5YTc1NzBkYzA5MmExZDc=
data/README.markdown CHANGED
@@ -185,6 +185,12 @@ user.in_bucket?(:my_experiment, 0)
185
185
  To see if a user is in the experiment population **ONLY**
186
186
  ```ruby
187
187
  user.in_experiment?(:my_experiment)
188
+ user.not_in_experiment?(:my_experiment) # inverse
189
+ ```
190
+
191
+ To see which bucket of an experiment a user is in:
192
+ ```ruby
193
+ user.experiment_bucket(:my_experiment)
188
194
  ```
189
195
 
190
196
  ### Ending an experiment
@@ -214,72 +220,49 @@ Then run `rake experimental:sync`
214
220
 
215
221
  ## Testing
216
222
 
217
- ### Setup
218
- in `spec_helper.rb` (after inclusion of ActiveSupport)
223
+ In your test suite, you typically want to have an neutral starting state across
224
+ all your tests. For experiments, this means all subjects are out of all
225
+ experiments. You then opt a particular subject into a particular bucket for any
226
+ experiment as your test requires.
219
227
 
220
- ```ruby
221
- require 'experimental/rspec_helpers'
222
- ```
228
+ Experimental ships with support to do this in a number of popular test
229
+ frameworks. Setup instructions for each framework are in the following sections.
223
230
 
224
- *You may want to force experiments off for all tests by default*
225
- ```ruby
226
- config.before(:each) do
227
- User.any_instance.stub(:in_experiment?).and_return(false)
228
- end
229
- ```
231
+ Once set up, you can then force a subject into a bucket for an experiment as
232
+ follows:
230
233
 
231
- ### Testing experiments
232
-
233
- Include the Rspec helpers in your spec class or spec_helper
234
234
  ```ruby
235
- include Experimental::RspecHelpers
235
+ set_experimental_bucket(subject, :my_experiment, 1)
236
236
  ```
237
237
 
238
- Shared contexts are available for in_experiment? and in_bucket?
238
+ If you set the bucket (1 in the above example) to `nil`, this means set the
239
+ subject to be out of the experiment (the default state).
240
+
241
+ ### Minitest
239
242
  ```ruby
240
- include_context "in experiment"
241
- include_context "not in experiment"
243
+ require 'experimental/test/unit'
242
244
 
243
- include_context "in experiment bucket 0"
244
- include_context "in experiment bucket 1"
245
+ class MyTest < Test::Unit::TestCase
246
+ include Experimental::Test::Unit
247
+ ...
248
+ end
245
249
  ```
246
250
 
247
- Helper methods are also available:
251
+ Note that if you define a `setup` method, then you must remember to call
252
+ `super` (always good practice in general).
248
253
 
249
- **is_in_experiment**
254
+ ### RSpec
250
255
  ```ruby
251
- # first param is true for in experiment, false for not in experiment
252
- # second param is the experiment name
253
- # third param is the subject object
254
- is_in_experiment(true, :my_experiment, my_subject)
255
-
256
- # if user and experiment_name are defined, you can do
257
- let(:experiment_name) { :my_experiment }
258
- let(:user) { User.new }
259
- is_in_experiment # true if in experiment
260
- is_in_experiment(false) # true if NOT in experiment
261
- ```
256
+ require 'experimental/test/rspec'
262
257
 
263
- **is_not_in_experiment**
264
- ```ruby
265
- # first param is name of experiment
266
- # second param is subject object
267
- is_not_in_experiment(:my_experiment, my_subject)
268
-
269
- # if user and experiment_name are defined, you can do
270
- let(:experiment_name) { :my_experiment }
271
- let(:user) { User.new }
272
- is_not_in_experiment
258
+ RSpec.configure do |config|
259
+ config.include Experimental::Test::RSpec
260
+ end
273
261
  ```
274
262
 
275
- **has_experiment_bucket**
263
+ ### Cucumber
276
264
  ```ruby
277
- has_experiment_bucket(1, :my_experiment, my_subject)
278
-
279
- # if user and experiment_name are defined, you can do
280
- let(:experiment_name) { :my_experiment }
281
- let(:user) { User.new }
282
- has_experiment_bucket(1)
265
+ require 'experimental/test/cucumber'
283
266
  ```
284
267
 
285
268
  ## Developer Workflow
@@ -67,6 +67,7 @@ module Experimental
67
67
  self.winning_bucket = nil
68
68
  self.start_date = Time.now
69
69
  self.end_date = nil
70
+ self.removed_at = nil
70
71
 
71
72
  save
72
73
  end
@@ -95,8 +96,12 @@ module Experimental
95
96
  !removed? && !ended?
96
97
  end
97
98
 
99
+ def self.available
100
+ where(removed_at: nil)
101
+ end
102
+
98
103
  def self.active
99
- where(['removed_at IS NULL AND (end_date IS NULL OR ? <= end_date)', Time.now])
104
+ available.where(['end_date IS NULL OR ? <= end_date', Time.now])
100
105
  end
101
106
 
102
107
  def to_sql_formula(subject_table = "users")
@@ -5,8 +5,8 @@ module Experimental
5
5
  Experiment.find_by_name(name)
6
6
  end
7
7
 
8
- def active
9
- Experiment.active.all
8
+ def available
9
+ Experiment.available.all
10
10
  end
11
11
  end
12
12
  end
@@ -6,8 +6,8 @@ module Experimental
6
6
  raise NotImplementedError, 'abstract'
7
7
  end
8
8
 
9
- # Return all active experiments.
10
- def active
9
+ # Return all non-removed experiments.
10
+ def available
11
11
  raise NotImplementedError, 'abstract'
12
12
  end
13
13
  end
@@ -19,7 +19,7 @@ module Experimental
19
19
  cache[name.to_s]
20
20
  end
21
21
 
22
- def active
22
+ def available
23
23
  refresh if dirty?
24
24
  cache.values
25
25
  end
@@ -35,7 +35,7 @@ module Experimental
35
35
 
36
36
  def refresh
37
37
  cache.clear
38
- source.active.each do |experiment|
38
+ source.available.each do |experiment|
39
39
  cache[experiment.name] = experiment
40
40
  end
41
41
  self.last_update = Time.now.to_f
@@ -13,7 +13,7 @@ module Experimental
13
13
  @experiments[name.to_s]
14
14
  end
15
15
 
16
- def active
16
+ def available
17
17
  @experiments.values
18
18
  end
19
19
  end
@@ -0,0 +1,5 @@
1
+ require 'experimental/test'
2
+
3
+ Experimental::Test.initialize
4
+ Before { Experimental::Test.setup }
5
+ World(Experimental::Test)
@@ -0,0 +1,12 @@
1
+ module Experimental
2
+ module Test
3
+ module RSpec
4
+ include Test
5
+
6
+ def self.included(base)
7
+ Test.initialize
8
+ base.before(:each) { Test.setup }
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,16 @@
1
+ module Experimental
2
+ module Test
3
+ module Unit
4
+ include Test
5
+
6
+ def self.included(base)
7
+ Test.initialize
8
+ end
9
+
10
+ def setup
11
+ Test.setup
12
+ super
13
+ end
14
+ end
15
+ end
16
+ end
@@ -1,14 +1,22 @@
1
1
  module Experimental
2
+ # Test helpers for applications that use Experimental.
3
+ #
4
+ # For popular test frameworks, simply require the appropriate
5
+ # experimental/test/*.rb file. If those doesn't cover you, check one of those
6
+ # to see how to hook up your favorite framework.
2
7
  module Test
3
- def self.included(base)
4
- base.before do
5
- Experimental.source = Experimental::Source::Configuration.new
6
- Experimental.overrides.reset
7
- end
8
+ # Call this once to initialize Experimental for your test suite.
9
+ #
10
+ # Calling it again isn't harmful, just unnecessary.
11
+ def self.initialize
12
+ return if @initialized
13
+ Experimental.source = Experimental::Source::Configuration.new
14
+ @initialized = true
15
+ end
8
16
 
9
- base.after do
10
- Experimental.overrides.reset
11
- end
17
+ # Call this before each test.
18
+ def self.setup
19
+ Experimental.overrides.reset
12
20
  end
13
21
 
14
22
  # Force the given subject into the given +bucket+ of the given +experiment+.
@@ -1,5 +1,5 @@
1
1
  module Experimental
2
- VERSION = [0, 2, 0]
2
+ VERSION = [0, 2, 1]
3
3
 
4
4
  class << VERSION
5
5
  include Comparable
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: experimental
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.2.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - HowAboutWe.com
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2013-10-22 00:00:00.000000000 Z
13
+ date: 2013-11-14 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: rails
@@ -30,98 +30,98 @@ dependencies:
30
30
  name: jquery-rails
31
31
  requirement: !ruby/object:Gem::Requirement
32
32
  requirements:
33
- - - '>='
33
+ - - ! '>='
34
34
  - !ruby/object:Gem::Version
35
35
  version: '0'
36
36
  type: :runtime
37
37
  prerelease: false
38
38
  version_requirements: !ruby/object:Gem::Requirement
39
39
  requirements:
40
- - - '>='
40
+ - - ! '>='
41
41
  - !ruby/object:Gem::Version
42
42
  version: '0'
43
43
  - !ruby/object:Gem::Dependency
44
44
  name: sqlite3
45
45
  requirement: !ruby/object:Gem::Requirement
46
46
  requirements:
47
- - - '>='
47
+ - - ! '>='
48
48
  - !ruby/object:Gem::Version
49
49
  version: '0'
50
50
  type: :development
51
51
  prerelease: false
52
52
  version_requirements: !ruby/object:Gem::Requirement
53
53
  requirements:
54
- - - '>='
54
+ - - ! '>='
55
55
  - !ruby/object:Gem::Version
56
56
  version: '0'
57
57
  - !ruby/object:Gem::Dependency
58
58
  name: timecop
59
59
  requirement: !ruby/object:Gem::Requirement
60
60
  requirements:
61
- - - '>='
61
+ - - ! '>='
62
62
  - !ruby/object:Gem::Version
63
63
  version: '0'
64
64
  type: :development
65
65
  prerelease: false
66
66
  version_requirements: !ruby/object:Gem::Requirement
67
67
  requirements:
68
- - - '>='
68
+ - - ! '>='
69
69
  - !ruby/object:Gem::Version
70
70
  version: '0'
71
71
  - !ruby/object:Gem::Dependency
72
72
  name: rspec-rails
73
73
  requirement: !ruby/object:Gem::Requirement
74
74
  requirements:
75
- - - '>='
75
+ - - ! '>='
76
76
  - !ruby/object:Gem::Version
77
77
  version: '0'
78
78
  type: :development
79
79
  prerelease: false
80
80
  version_requirements: !ruby/object:Gem::Requirement
81
81
  requirements:
82
- - - '>='
82
+ - - ! '>='
83
83
  - !ruby/object:Gem::Version
84
84
  version: '0'
85
85
  - !ruby/object:Gem::Dependency
86
86
  name: activeadmin
87
87
  requirement: !ruby/object:Gem::Requirement
88
88
  requirements:
89
- - - '>='
89
+ - - ! '>='
90
90
  - !ruby/object:Gem::Version
91
91
  version: '0'
92
92
  type: :development
93
93
  prerelease: false
94
94
  version_requirements: !ruby/object:Gem::Requirement
95
95
  requirements:
96
- - - '>='
96
+ - - ! '>='
97
97
  - !ruby/object:Gem::Version
98
98
  version: '0'
99
99
  - !ruby/object:Gem::Dependency
100
100
  name: sass-rails
101
101
  requirement: !ruby/object:Gem::Requirement
102
102
  requirements:
103
- - - '>='
103
+ - - ! '>='
104
104
  - !ruby/object:Gem::Version
105
105
  version: '0'
106
106
  type: :development
107
107
  prerelease: false
108
108
  version_requirements: !ruby/object:Gem::Requirement
109
109
  requirements:
110
- - - '>='
110
+ - - ! '>='
111
111
  - !ruby/object:Gem::Version
112
112
  version: '0'
113
113
  - !ruby/object:Gem::Dependency
114
114
  name: coffee-rails
115
115
  requirement: !ruby/object:Gem::Requirement
116
116
  requirements:
117
- - - '>='
117
+ - - ! '>='
118
118
  - !ruby/object:Gem::Version
119
119
  version: '0'
120
120
  type: :development
121
121
  prerelease: false
122
122
  version_requirements: !ruby/object:Gem::Requirement
123
123
  requirements:
124
- - - '>='
124
+ - - ! '>='
125
125
  - !ruby/object:Gem::Version
126
126
  version: '0'
127
127
  description: AB Test framework for Rails
@@ -152,6 +152,9 @@ files:
152
152
  - lib/experimental/source/cache.rb
153
153
  - lib/experimental/source/configuration.rb
154
154
  - lib/experimental/source.rb
155
+ - lib/experimental/test/cucumber.rb
156
+ - lib/experimental/test/rspec.rb
157
+ - lib/experimental/test/unit.rb
155
158
  - lib/experimental/test.rb
156
159
  - lib/experimental/version.rb
157
160
  - lib/experimental.rb
@@ -173,17 +176,17 @@ require_paths:
173
176
  - lib
174
177
  required_ruby_version: !ruby/object:Gem::Requirement
175
178
  requirements:
176
- - - '>='
179
+ - - ! '>='
177
180
  - !ruby/object:Gem::Version
178
181
  version: '0'
179
182
  required_rubygems_version: !ruby/object:Gem::Requirement
180
183
  requirements:
181
- - - '>='
184
+ - - ! '>='
182
185
  - !ruby/object:Gem::Version
183
186
  version: '0'
184
187
  requirements: []
185
188
  rubyforge_project:
186
- rubygems_version: 2.1.9
189
+ rubygems_version: 2.0.3
187
190
  signing_key:
188
191
  specification_version: 4
189
192
  summary: Adds support for database-backed AB tests in Rails apps