split 1.2.1 → 1.3.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: b771c2496cd674b0512e956fcdb3bf67768ba4a8
4
- data.tar.gz: cd3ac62720dbaa5968d58be74ebc689854fd0fac
3
+ metadata.gz: 9fa1bd87e254e6e0bc2f244f3fd6e479d40e096f
4
+ data.tar.gz: c50789065bf80c9b850bdc0851d1b6dbcd330183
5
5
  SHA512:
6
- metadata.gz: f94c6eca1509241995790fefc2407ae8cdc546ceae8aad2a4fa4975c47dd4370f5cc835b630a9c91a1cd7682a24bf49c34af422a31f576af70162003717f396e
7
- data.tar.gz: 9e47de4c77fa41c39d525c2c79448c3d1e5fdc564dfa340d00857a91cedd11517fc3e871b7f4bb208eab9a5dfe29e2a026dcd40139569d471e146d68bfbc982c
6
+ metadata.gz: d1ce3cc70e83f014d69136754658030b310aaff9450d6ad8750011202d071f44a0157c824e79a0a4dd7938e2534090949e6f138c913c799caec02ba01b2b277c
7
+ data.tar.gz: db2e2a14bdd4bfb3e8620c211e74cf649dbfe9c67a0555e1304f79ab2e8c9da707c5798816d90887c4f2d1f7ab2ad87d99157d00125801eb29afb8026033983b
@@ -1,3 +1,21 @@
1
+ ## 1.3.0 (October 20th, 2015)
2
+
3
+ Features
4
+
5
+ - allow for custom redis_url different from ENV variable (@davidgrieser, #323)
6
+ - add ability to change the length of the persistence cookie (@peterylai, #335)
7
+
8
+ Bugfixes:
9
+
10
+ - Rescue from Redis::BaseError instead of Redis::CannotConnectError (@nfm, #342)
11
+ - Fix active experiments when experiment is on a later version (@ndrisso, #331)
12
+ - Fix caching of winning alternative (@nfm, #329)
13
+
14
+ Misc:
15
+
16
+ - Remove duplication from Experiment#save (@pakallis, #333)
17
+ - Remove unnecessary argument from Experiment#write_to_alternative (@t4deu, #332)
18
+
1
19
  ## 1.2.1 (May 17th, 2015)
2
20
 
3
21
  Features
data/README.md CHANGED
@@ -23,47 +23,29 @@ Split only supports redis 2.0 or greater.
23
23
  If you're on OS X, Homebrew is the simplest way to install Redis:
24
24
 
25
25
  ```bash
26
- $ brew install redis
27
- $ redis-server /usr/local/etc/redis.conf
26
+ brew install redis
27
+ redis-server /usr/local/etc/redis.conf
28
28
  ```
29
29
 
30
30
  You now have a Redis daemon running on 6379.
31
31
 
32
32
  ## Setup
33
33
 
34
- If you are using bundler add split to your Gemfile:
35
-
36
- ``` ruby
37
- gem 'split'
38
- ```
39
-
40
- Then run:
41
-
42
- ```bash
43
- $ bundle install
44
- ```
45
-
46
- Otherwise install the gem:
47
-
48
34
  ```bash
49
- $ gem install split
50
- ```
51
-
52
- and require it in your project:
53
-
54
- ```ruby
55
- require 'split'
35
+ gem install split
56
36
  ```
57
37
 
58
- ### Rails 3
38
+ ### Rails
59
39
 
60
- Split is autoloaded when rails starts up, as long as you've configured redis it will 'just work'.
40
+ Adding `gem 'split'` to your Gemfile will autoloaded it when rails starts up, as long as you've configured redis it will 'just work'.
61
41
 
62
42
  ### Sinatra
63
43
 
64
44
  To configure sinatra with Split you need to enable sessions and mix in the helper methods. Add the following lines at the top of your sinatra app:
65
45
 
66
46
  ```ruby
47
+ require 'split'
48
+
67
49
  class MySinatraApp < Sinatra::Base
68
50
  enable :sessions
69
51
  helpers Split::Helper
@@ -86,8 +68,8 @@ It can be used to render different templates, show different text or any other c
86
68
  Example: View
87
69
 
88
70
  ```erb
89
- <% ab_test("login_button", "/images/button1.jpg", "/images/button2.jpg") do |button_file| %>
90
- <%= image_tag(button_file, :alt => "Login!") %>
71
+ <% ab_test(:login_button, "/images/button1.jpg", "/images/button2.jpg") do |button_file| %>
72
+ <%= image_tag(button_file, alt: "Login!") %>
91
73
  <% end %>
92
74
  ```
93
75
 
@@ -96,7 +78,7 @@ Example: Controller
96
78
  ```ruby
97
79
  def register_new_user
98
80
  # See what level of free points maximizes users' decision to buy replacement points.
99
- @starter_points = ab_test("new_user_free_points", '100', '200', '300')
81
+ @starter_points = ab_test(:new_user_free_points, '100', '200', '300')
100
82
  end
101
83
  ```
102
84
 
@@ -105,14 +87,14 @@ Example: Conversion tracking (in a controller!)
105
87
  ```ruby
106
88
  def buy_new_points
107
89
  # some business logic
108
- finished("new_user_free_points")
90
+ finished(:new_user_free_points)
109
91
  end
110
92
  ```
111
93
 
112
94
  Example: Conversion tracking (in a view)
113
95
 
114
96
  ```erb
115
- Thanks for signing up, dude! <% finished("signup_page_redesign") %>
97
+ Thanks for signing up, dude! <% finished(:signup_page_redesign) %>
116
98
  ```
117
99
 
118
100
  You can find more examples, tutorials and guides on the [wiki](https://github.com/splitrb/split/wiki).
@@ -139,11 +121,11 @@ Perhaps you only want to show an alternative to 10% of your visitors because it
139
121
  To do this you can pass a weight with each alternative in the following ways:
140
122
 
141
123
  ```ruby
142
- ab_test('homepage design', {'Old' => 20}, {'New' => 2})
124
+ ab_test(:homepage_design, {'Old' => 18}, {'New' => 2})
143
125
 
144
- ab_test('homepage design', 'Old', {'New' => 0.1})
126
+ ab_test(:homepage_design, 'Old', {'New' => 1.0/9})
145
127
 
146
- ab_test('homepage design', {'Old' => 10}, 'New')
128
+ ab_test(:homepage_design', {'Old' => 9}, 'New')
147
129
  ```
148
130
 
149
131
  This will only show the new alternative to visitors 1 in 10 times, the default weight for an alternative is 1.
@@ -161,7 +143,7 @@ will always have red buttons. This won't be stored in your session or count towa
161
143
 
162
144
  In the event you want to disable all tests without having to know the individual experiment names, add a `SPLIT_DISABLE` query parameter.
163
145
 
164
- http://myawesomesite.com?SPLIT_DISABLE=trues
146
+ http://myawesomesite.com?SPLIT_DISABLE=true
165
147
 
166
148
  It is not required to send `SPLIT_DISABLE=false` to activate Split.
167
149
 
@@ -179,7 +161,7 @@ When a user completes a test their session is reset so that they may start the t
179
161
  To stop this behaviour you can pass the following option to the `finished` method:
180
162
 
181
163
  ```ruby
182
- finished('experiment_name', :reset => false)
164
+ finished(:experiment_name, reset: false)
183
165
  ```
184
166
 
185
167
  The user will then always see the alternative they started with.
@@ -212,6 +194,15 @@ Split.configure do |config|
212
194
  end
213
195
  ```
214
196
 
197
+ By default, cookies will expire in 1 year. To change that, set the `persistence_cookie_length` in the configuration (unit of time in seconds).
198
+
199
+ ```ruby
200
+ Split.configure do |config|
201
+ config.persistence = :cookie
202
+ config.persistence_cookie_length = 2592000 # 30 days
203
+ end
204
+ ```
205
+
215
206
  __Note:__ Using cookies depends on `ActionDispatch::Cookies` or any identical API
216
207
 
217
208
  #### Redis
@@ -220,9 +211,9 @@ Using Redis will allow ab_users to persist across sessions or machines.
220
211
 
221
212
  ```ruby
222
213
  Split.configure do |config|
223
- config.persistence = Split::Persistence::RedisAdapter.with_config(:lookup_by => proc { |context| context.current_user_id })
214
+ config.persistence = Split::Persistence::RedisAdapter.with_config(lookup_by: -> (context) { context.current_user_id })
224
215
  # Equivalent
225
- # config.persistence = Split::Persistence::RedisAdapter.with_config(:lookup_by => :current_user_id }
216
+ # config.persistence = Split::Persistence::RedisAdapter.with_config(lookup_by: :current_user_id)
226
217
  end
227
218
  ```
228
219
 
@@ -233,7 +224,7 @@ Options:
233
224
  #### Custom Adapter
234
225
 
235
226
  Your custom adapter needs to implement the same API as existing adapters.
236
- See `Split::Persistance::CookieAdapter` or `Split::Persistence::SessionAdapter` for a starting point.
227
+ See `Split::Persistence::CookieAdapter` or `Split::Persistence::SessionAdapter` for a starting point.
237
228
 
238
229
  ```ruby
239
230
  Split.configure do |config|
@@ -294,8 +285,8 @@ For example:
294
285
 
295
286
  ``` ruby
296
287
  Split.configure do |config|
297
- config.on_experiment_reset = proc{ |experiment| # Do something on reset }
298
- config.on_experiment_delete = proc{ |experiment| # Do something else on delete }
288
+ config.on_experiment_reset = -> (example) { # Do something on reset }
289
+ config.on_experiment_delete = -> (experiment) { # Do something else on delete }
299
290
  end
300
291
  ```
301
292
 
@@ -316,13 +307,13 @@ run Rack::URLMap.new \
316
307
  However, if you are using Rails 3: You can mount this inside your app routes by first adding this to the Gemfile:
317
308
 
318
309
  ```ruby
319
- gem 'split', :require => 'split/dashboard'
310
+ gem 'split', require: 'split/dashboard'
320
311
  ```
321
312
 
322
313
  Then adding this to config/routes.rb
323
314
 
324
315
  ```ruby
325
- mount Split::Dashboard, :at => 'split'
316
+ mount Split::Dashboard, at: 'split'
326
317
  ```
327
318
 
328
319
  You may want to password protect that page, you can do so with `Rack::Auth::Basic` (in your split initializer file)
@@ -335,11 +326,11 @@ end
335
326
 
336
327
  You can even use Devise or any other Warden-based authentication method to authorize users. Just replace `mount Split::Dashboard, :at => 'split'` in `config/routes.rb` with the following:
337
328
  ```ruby
338
- match "/split" => Split::Dashboard, :anchor => false, :via => [:get, :post], :constraints => lambda { |request|
329
+ match "/split" => Split::Dashboard, anchor: false, via: [:get, :post, :delete], constraints: -> (request) do
339
330
  request.env['warden'].authenticated? # are we authenticated?
340
331
  request.env['warden'].authenticate! # authenticate if not already
341
332
  # or even check any other condition such as request.env['warden'].user.is_admin?
342
- }
333
+ end
343
334
  ```
344
335
 
345
336
  More information on this [here](http://steve.dynedge.co.uk/2011/12/09/controlling-access-to-routes-and-rack-apps-in-rails-3-with-devise-and-warden/)
@@ -355,16 +346,17 @@ You can override the default configuration options of Split like so:
355
346
  ```ruby
356
347
  Split.configure do |config|
357
348
  config.db_failover = true # handle redis errors gracefully
358
- config.db_failover_on_db_error = proc{|error| Rails.logger.error(error.message) }
349
+ config.db_failover_on_db_error = -> (error) { Rails.logger.error(error.message) }
359
350
  config.allow_multiple_experiments = true
360
351
  config.enabled = true
361
352
  config.persistence = Split::Persistence::SessionAdapter
362
353
  #config.start_manually = false ## new test will have to be started manually from the admin panel. default false
363
354
  config.include_rails_helper = true
355
+ config.redis_url = "custom.redis.url:6380"
364
356
  end
365
357
  ```
366
358
 
367
- You can set different Redis host via environment variable ```REDIS_URL```.
359
+ Split looks for the Redis host in the environment variable ```REDIS_URL``` then defaults to ```localhost:6379``` if not specified by configure block.
368
360
 
369
361
  ### Filtering
370
362
 
@@ -381,7 +373,7 @@ Split.configure do |config|
381
373
  config.ignore_ip_addresses << '81.19.48.130' # or regex: /81\.19\.48\.[0-9]+/
382
374
 
383
375
  # or provide your own filter functionality, the default is proc{ |request| is_robot? || is_ignored_ip_address? }
384
- config.ignore_filter = proc{ |request| CustomExcludeLogic.excludes?(request) }
376
+ config.ignore_filter = -> (request) { CustomExcludeLogic.excludes?(request) }
385
377
  end
386
378
  ```
387
379
 
@@ -394,15 +386,15 @@ algorithm and if the experiment resets once finished:
394
386
  ```ruby
395
387
  Split.configure do |config|
396
388
  config.experiments = {
397
- "my_first_experiment" => {
398
- :alternatives => ["a", "b"],
399
- :resettable => false
389
+ my_first_experiment: {
390
+ alternatives: ["a", "b"],
391
+ resettable: false
400
392
  },
401
- "my_second_experiment" => {
402
- :algorithm => 'Split::Algorithms::Whiplash',
403
- :alternatives => [
404
- { :name => "a", :percent => 67 },
405
- { :name => "b", :percent => 33 }
393
+ :my_second_experiment => {
394
+ algorithm: 'Split::Algorithms::Whiplash',
395
+ alternatives: [
396
+ { name: "a", percent: 67 },
397
+ { name: "b", percent: 33 }
406
398
  ]
407
399
  }
408
400
  }
@@ -436,27 +428,41 @@ my_second_experiment:
436
428
  This simplifies the calls from your code:
437
429
 
438
430
  ```ruby
439
- ab_test("my_first_experiment")
431
+ ab_test(:my_first_experiment)
440
432
  ```
441
433
 
442
434
  and:
443
435
 
444
436
  ```ruby
445
- finished("my_first_experiment")
437
+ finished(:my_first_experiment)
446
438
  ```
447
439
 
448
440
  You can also add meta data for each experiment, very useful when you need more than an alternative name to change behaviour:
449
441
 
442
+ ```ruby
443
+ Split.configure do |config|
444
+ config.experiments = {
445
+ my_first_experiment: {
446
+ alternatives: ["a", "b"],
447
+ metadata: {
448
+ "a" => {"text" => "Have a fantastic day"},
449
+ "b" => {"text" => "Don't get hit by a bus"},
450
+ }
451
+ },
452
+ }
453
+ end
454
+ ```
455
+
450
456
  ```yaml
451
457
  my_first_experiment:
452
458
  alternatives:
453
459
  - a
454
460
  - b
455
- meta:
456
- a:
457
- text: "Have a fantastic day"
458
- b:
459
- text: "Don't get hit by a bus"
461
+ metadata:
462
+ a:
463
+ text: "Have a fantastic day"
464
+ b:
465
+ text: "Don't get hit by a bus"
460
466
  ```
461
467
 
462
468
  This allows for some advanced experiment configuration using methods like:
@@ -486,9 +492,9 @@ the `:metric` option.
486
492
  ```ruby
487
493
  Split.configure do |config|
488
494
  config.experiments = {
489
- "my_first_experiment" => {
490
- :alternatives => ["a", "b"],
491
- :metric => :my_metric,
495
+ my_first_experiment: {
496
+ alternatives: ["a", "b"],
497
+ metric: :my_metric,
492
498
  }
493
499
  }
494
500
  end
@@ -514,7 +520,7 @@ You might wish to allow an experiment to have multiple, distinguishable goals.
514
520
  The API to define goals for an experiment is this:
515
521
 
516
522
  ```ruby
517
- ab_test({"link_color" => ["purchase", "refund"]}, "red", "blue")
523
+ ab_test({link_color: ["purchase", "refund"]}, "red", "blue")
518
524
  ```
519
525
 
520
526
  or you can you can define them in a configuration file:
@@ -522,9 +528,9 @@ or you can you can define them in a configuration file:
522
528
  ```ruby
523
529
  Split.configure do |config|
524
530
  config.experiments = {
525
- "link_color" => {
526
- :alternatives => ["red", "blue"],
527
- :goals => ["purchase", "refund"]
531
+ link_color: {
532
+ alternatives: ["red", "blue"],
533
+ goals: ["purchase", "refund"]
528
534
  }
529
535
  }
530
536
  end
@@ -533,7 +539,7 @@ end
533
539
  To complete a goal conversion, you do it like:
534
540
 
535
541
  ```ruby
536
- finished("link_color" => "purchase")
542
+ finished(link_color: "purchase")
537
543
  ```
538
544
 
539
545
  **NOTE:** This does not mean that a single experiment can have/complete progressive goals.
@@ -53,7 +53,7 @@ module Split
53
53
  # create a new one.
54
54
  def redis
55
55
  return @redis if @redis
56
- self.redis = ENV.fetch('REDIS_URL', 'localhost:6379')
56
+ self.redis = self.configuration.redis_url
57
57
  self.redis
58
58
  end
59
59
 
@@ -10,6 +10,7 @@ module Split
10
10
  attr_accessor :allow_multiple_experiments
11
11
  attr_accessor :enabled
12
12
  attr_accessor :persistence
13
+ attr_accessor :persistence_cookie_length
13
14
  attr_accessor :algorithm
14
15
  attr_accessor :store_override
15
16
  attr_accessor :start_manually
@@ -19,6 +20,7 @@ module Split
19
20
  attr_accessor :on_experiment_delete
20
21
  attr_accessor :include_rails_helper
21
22
  attr_accessor :beta_probability_simulations
23
+ attr_accessor :redis_url
22
24
 
23
25
  attr_reader :experiments
24
26
 
@@ -201,9 +203,11 @@ module Split
201
203
  @enabled = true
202
204
  @experiments = {}
203
205
  @persistence = Split::Persistence::SessionAdapter
206
+ @persistence_cookie_length = 31536000 # One year from now
204
207
  @algorithm = Split::Algorithms::WeightedSample
205
208
  @include_rails_helper = true
206
209
  @beta_probability_simulations = 10000
210
+ @redis_url = ENV.fetch('REDIS_URL', 'localhost:6379')
207
211
  end
208
212
 
209
213
  private
@@ -4,9 +4,7 @@
4
4
  <% experiment_class = "experiment" %>
5
5
  <% end %>
6
6
 
7
- <% unless experiment.calc_time == Time.now.day %>
8
- <% experiment.estimate_winning_alternative %>
9
- <% end %>
7
+ <% experiment.calc_winning_alternatives %>
10
8
 
11
9
  <div class="<%= experiment_class %>">
12
10
  <div class="experiment-header">
@@ -83,7 +83,8 @@ module Split
83
83
  Split.redis.sadd(:experiments, name)
84
84
  start unless Split.configuration.start_manually
85
85
  @alternatives.reverse.each {|a| Split.redis.lpush(name, a.name)}
86
- @goals.reverse.each {|a| Split.redis.lpush(goals_key, a)} unless @goals.nil?
86
+ save_goals
87
+ save_metadata
87
88
  Split.redis.set(metadata_key, @metadata.to_json) unless @metadata.nil?
88
89
  else
89
90
  existing_alternatives = load_alternatives_from_redis
@@ -96,8 +97,8 @@ module Split
96
97
  delete_metadata
97
98
  Split.redis.del(@name)
98
99
  @alternatives.reverse.each {|a| Split.redis.lpush(name, a.name)}
99
- @goals.reverse.each {|a| Split.redis.lpush(goals_key, a)} unless @goals.nil?
100
- Split.redis.set(metadata_key, @metadata.to_json) unless @metadata.nil?
100
+ save_goals
101
+ save_metadata
101
102
  end
102
103
  end
103
104
 
@@ -274,17 +275,22 @@ module Split
274
275
  end
275
276
 
276
277
  def calc_winning_alternatives
277
- if goals.empty?
278
- self.estimate_winning_alternative
279
- else
280
- goals.each do |goal|
281
- self.estimate_winning_alternative(goal)
278
+ # Super simple cache so that we only recalculate winning alternatives once per day
279
+ days_since_epoch = Time.now.utc.to_i / 86400
280
+
281
+ if self.calc_time != days_since_epoch
282
+ if goals.empty?
283
+ self.estimate_winning_alternative
284
+ else
285
+ goals.each do |goal|
286
+ self.estimate_winning_alternative(goal)
287
+ end
282
288
  end
283
- end
284
289
 
285
- calc_time = Time.now.day
290
+ self.calc_time = days_since_epoch
286
291
 
287
- self.save
292
+ self.save
293
+ end
288
294
  end
289
295
 
290
296
  def estimate_winning_alternative(goal = nil)
@@ -309,12 +315,12 @@ module Split
309
315
 
310
316
  @alternative_probabilities = calc_alternative_probabilities(winning_counts, Split.configuration.beta_probability_simulations)
311
317
 
312
- write_to_alternatives(@alternative_probabilities, goal)
318
+ write_to_alternatives(goal)
313
319
 
314
320
  self.save
315
321
  end
316
322
 
317
- def write_to_alternatives(alternative_probabilities, goal = nil)
323
+ def write_to_alternatives(goal = nil)
318
324
  alternatives.each do |alternative|
319
325
  alternative.set_p_winner(@alternative_probabilities[alternative], goal)
320
326
  end
@@ -390,7 +396,7 @@ module Split
390
396
  end
391
397
 
392
398
  def calc_time
393
- Split.redis.hget(experiment_config_key, :calc_time)
399
+ Split.redis.hget(experiment_config_key, :calc_time).to_i
394
400
  end
395
401
 
396
402
  def jstring(goal = nil)
@@ -451,5 +457,13 @@ module Split
451
457
  end
452
458
  end
453
459
 
460
+ def save_goals
461
+ @goals.reverse.each {|a| Split.redis.lpush(goals_key, a)} unless @goals.nil?
462
+ end
463
+
464
+ def save_metadata
465
+ Split.redis.set(metadata_key, @metadata.to_json) unless @metadata.nil?
466
+ end
467
+
454
468
  end
455
469
  end
@@ -16,7 +16,7 @@ module Split
16
16
  else
17
17
  control_variable(experiment.control)
18
18
  end
19
- rescue Errno::ECONNREFUSED, Redis::CannotConnectError, SocketError => e
19
+ rescue Errno::ECONNREFUSED, Redis::BaseError, SocketError => e
20
20
  raise(e) unless Split.configuration.db_failover
21
21
  Split.configuration.db_failover_on_db_error.call(e)
22
22
 
@@ -116,9 +116,10 @@ module Split
116
116
  def active_experiments
117
117
  experiment_pairs = {}
118
118
  ab_user.keys.each do |key|
119
- Metric.possible_experiments(key).each do |experiment|
119
+ key_without_version = key.split(/\:\d(?!\:)/)[0]
120
+ Metric.possible_experiments(key_without_version).each do |experiment|
120
121
  if !experiment.has_winner?
121
- experiment_pairs[key] = ab_user[key]
122
+ experiment_pairs[key_without_version] = ab_user[key]
122
123
  end
123
124
  end
124
125
  end
@@ -4,10 +4,9 @@ module Split
4
4
  module Persistence
5
5
  class CookieAdapter
6
6
 
7
- EXPIRES = Time.now + 31536000 # One year from now
8
-
9
7
  def initialize(context)
10
8
  @cookies = context.send(:cookies)
9
+ @expires = Time.now + cookie_length_config
11
10
  end
12
11
 
13
12
  def [](key)
@@ -31,7 +30,7 @@ module Split
31
30
  def set_cookie(value)
32
31
  @cookies[:split] = {
33
32
  :value => JSON.generate(value),
34
- :expires => EXPIRES
33
+ :expires => @expires
35
34
  }
36
35
  end
37
36
 
@@ -47,6 +46,10 @@ module Split
47
46
  end
48
47
  end
49
48
 
49
+ def cookie_length_config
50
+ Split.configuration.persistence_cookie_length
51
+ end
52
+
50
53
  end
51
54
  end
52
55
  end
@@ -1,6 +1,6 @@
1
1
  module Split
2
2
  MAJOR = 1
3
- MINOR = 2
4
- PATCH = 1
3
+ MINOR = 3
4
+ PATCH = 0
5
5
  VERSION = [MAJOR, MINOR, PATCH].join('.')
6
6
  end
@@ -210,4 +210,34 @@ describe Split::Configuration do
210
210
 
211
211
  expect(@config.normalized_experiments).to eq({:my_experiment=>{:alternatives=>[{"control_opt"=>0.67}, [{"second_opt"=>0.1}, {"third_opt"=>0.23}]]}})
212
212
  end
213
+
214
+ context "configuration URL" do
215
+ it "should default to local redis server" do
216
+ expect(@config.redis_url).to eq("localhost:6379")
217
+ end
218
+
219
+ it "should allow for redis url to be configured" do
220
+ @config.redis_url = "custom_redis_url"
221
+ expect(@config.redis_url).to eq("custom_redis_url")
222
+ end
223
+
224
+ context "provided REDIS_URL environment variable" do
225
+ it "should use the ENV variable" do
226
+ ENV['REDIS_URL'] = "env_redis_url"
227
+ expect(Split::Configuration.new.redis_url).to eq("env_redis_url")
228
+ end
229
+ end
230
+ end
231
+
232
+ context "persistence cookie length" do
233
+ it "should default to 1 year" do
234
+ expect(@config.persistence_cookie_length).to eq(31536000)
235
+ end
236
+
237
+ it "should allow the persistence cookie length to be configured" do
238
+ @config.persistence_cookie_length = 2592000
239
+ expect(@config.persistence_cookie_length).to eq(2592000)
240
+ end
241
+ end
242
+
213
243
  end
@@ -428,6 +428,13 @@ describe Split::Experiment do
428
428
  p_goal2 = alt.p_winner(goal2)
429
429
  expect(p_goal1).not_to be_within(0.04).of(p_goal2)
430
430
  end
431
+
432
+ it "should return nil and not re-calculate probabilities if they have already been calculated today" do
433
+ experiment = Split::ExperimentCatalog.find_or_create({'link_color3' => ["purchase", "refund"]}, 'blue', 'red', 'green')
434
+ experiment_calc_time = Time.now.utc.to_i / 86400
435
+ experiment.calc_time = experiment_calc_time
436
+ expect(experiment.calc_winning_alternatives).to be nil
437
+ end
431
438
  end
432
439
 
433
440
  end
@@ -449,6 +449,14 @@ describe Split::Helper do
449
449
  expect(active_experiments.first[0]).to eq "def"
450
450
  expect(active_experiments.first[1]).to eq alternative
451
451
  end
452
+
453
+ it 'should show an active test when an experiment is on a later version' do
454
+ experiment.reset
455
+ expect(experiment.version).to eq(1)
456
+ ab_test('link_color', 'blue', 'red')
457
+ expect(active_experiments.count).to eq 1
458
+ expect(active_experiments.first[0]).to eq "link_color"
459
+ end
452
460
 
453
461
  it 'should show multiple tests' do
454
462
  Split.configure do |config|
@@ -10,7 +10,7 @@ Gem::Specification.new do |s|
10
10
  s.licenses = ['MIT']
11
11
  s.email = ["andrewnez@gmail.com"]
12
12
  s.homepage = "https://github.com/splitrb/split"
13
- s.summary = %q{Rack based split testing framework}
13
+ s.summary = "Rack based split testing framework"
14
14
 
15
15
  s.required_ruby_version = '>= 1.9.2'
16
16
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: split
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.2.1
4
+ version: 1.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andrew Nesbitt
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-05-17 00:00:00.000000000 Z
11
+ date: 2015-10-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: redis
@@ -229,7 +229,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
229
229
  version: '0'
230
230
  requirements: []
231
231
  rubyforge_project: split
232
- rubygems_version: 2.4.5
232
+ rubygems_version: 2.4.8
233
233
  signing_key:
234
234
  specification_version: 4
235
235
  summary: Rack based split testing framework
@@ -252,3 +252,4 @@ test_files:
252
252
  - spec/spec_helper.rb
253
253
  - spec/support/cookies_mock.rb
254
254
  - spec/trial_spec.rb
255
+ has_rdoc: