split 4.0.1 → 4.0.2

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.
Files changed (76) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ci.yml +6 -3
  3. data/.rubocop.yml +2 -5
  4. data/CHANGELOG.md +23 -0
  5. data/CONTRIBUTING.md +1 -1
  6. data/Gemfile +2 -1
  7. data/README.md +4 -2
  8. data/Rakefile +4 -5
  9. data/gemfiles/5.2.gemfile +1 -3
  10. data/gemfiles/6.0.gemfile +1 -3
  11. data/gemfiles/6.1.gemfile +1 -3
  12. data/gemfiles/7.0.gemfile +2 -3
  13. data/lib/split/algorithms/block_randomization.rb +5 -6
  14. data/lib/split/algorithms/whiplash.rb +16 -18
  15. data/lib/split/algorithms.rb +22 -0
  16. data/lib/split/alternative.rb +21 -22
  17. data/lib/split/cache.rb +0 -1
  18. data/lib/split/combined_experiments_helper.rb +4 -4
  19. data/lib/split/configuration.rb +83 -84
  20. data/lib/split/dashboard/helpers.rb +6 -7
  21. data/lib/split/dashboard/pagination_helpers.rb +53 -54
  22. data/lib/split/dashboard/public/style.css +5 -2
  23. data/lib/split/dashboard/views/index.erb +19 -4
  24. data/lib/split/dashboard.rb +29 -23
  25. data/lib/split/encapsulated_helper.rb +4 -6
  26. data/lib/split/experiment.rb +84 -88
  27. data/lib/split/experiment_catalog.rb +6 -5
  28. data/lib/split/extensions/string.rb +1 -1
  29. data/lib/split/goals_collection.rb +8 -10
  30. data/lib/split/helper.rb +19 -19
  31. data/lib/split/metric.rb +4 -5
  32. data/lib/split/persistence/cookie_adapter.rb +44 -47
  33. data/lib/split/persistence/dual_adapter.rb +7 -8
  34. data/lib/split/persistence/redis_adapter.rb +2 -3
  35. data/lib/split/persistence/session_adapter.rb +0 -2
  36. data/lib/split/persistence.rb +4 -4
  37. data/lib/split/redis_interface.rb +1 -2
  38. data/lib/split/trial.rb +23 -24
  39. data/lib/split/user.rb +12 -13
  40. data/lib/split/version.rb +1 -1
  41. data/lib/split/zscore.rb +1 -3
  42. data/lib/split.rb +26 -25
  43. data/spec/algorithms/block_randomization_spec.rb +6 -5
  44. data/spec/algorithms/weighted_sample_spec.rb +6 -5
  45. data/spec/algorithms/whiplash_spec.rb +4 -5
  46. data/spec/alternative_spec.rb +35 -36
  47. data/spec/cache_spec.rb +15 -19
  48. data/spec/combined_experiments_helper_spec.rb +18 -17
  49. data/spec/configuration_spec.rb +32 -38
  50. data/spec/dashboard/pagination_helpers_spec.rb +69 -67
  51. data/spec/dashboard/paginator_spec.rb +10 -9
  52. data/spec/dashboard_helpers_spec.rb +19 -18
  53. data/spec/dashboard_spec.rb +67 -35
  54. data/spec/encapsulated_helper_spec.rb +12 -14
  55. data/spec/experiment_catalog_spec.rb +14 -13
  56. data/spec/experiment_spec.rb +121 -123
  57. data/spec/goals_collection_spec.rb +17 -15
  58. data/spec/helper_spec.rb +379 -382
  59. data/spec/metric_spec.rb +14 -14
  60. data/spec/persistence/cookie_adapter_spec.rb +23 -8
  61. data/spec/persistence/dual_adapter_spec.rb +71 -71
  62. data/spec/persistence/redis_adapter_spec.rb +25 -26
  63. data/spec/persistence/session_adapter_spec.rb +2 -3
  64. data/spec/persistence_spec.rb +1 -2
  65. data/spec/redis_interface_spec.rb +16 -14
  66. data/spec/spec_helper.rb +15 -13
  67. data/spec/split_spec.rb +11 -11
  68. data/spec/support/cookies_mock.rb +1 -2
  69. data/spec/trial_spec.rb +61 -60
  70. data/spec/user_spec.rb +36 -36
  71. data/split.gemspec +20 -20
  72. metadata +7 -10
  73. data/.rubocop_todo.yml +0 -226
  74. data/Appraisals +0 -19
  75. data/gemfiles/5.0.gemfile +0 -9
  76. data/gemfiles/5.1.gemfile +0 -9
@@ -7,11 +7,11 @@ module Split
7
7
  end
8
8
 
9
9
  def url(*path_parts)
10
- [ path_prefix, path_parts ].join("/").squeeze('/')
10
+ [ path_prefix, path_parts ].join("/").squeeze("/")
11
11
  end
12
12
 
13
13
  def path_prefix
14
- request.env['SCRIPT_NAME']
14
+ request.env["SCRIPT_NAME"]
15
15
  end
16
16
 
17
17
  def number_to_percentage(number, precision = 2)
@@ -32,15 +32,14 @@ module Split
32
32
  z = round(z_score.to_s.to_f, 3).abs
33
33
 
34
34
  if z >= 2.58
35
- '99% confidence'
35
+ "99% confidence"
36
36
  elsif z >= 1.96
37
- '95% confidence'
37
+ "95% confidence"
38
38
  elsif z >= 1.65
39
- '90% confidence'
39
+ "90% confidence"
40
40
  else
41
- 'Insufficient confidence'
41
+ "Insufficient confidence"
42
42
  end
43
-
44
43
  end
45
44
  end
46
45
  end
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'split/dashboard/paginator'
3
+ require "split/dashboard/paginator"
4
4
 
5
5
  module Split
6
6
  module DashboardPaginationHelpers
@@ -30,58 +30,57 @@ module Split
30
30
  end
31
31
 
32
32
  private
33
-
34
- def show_first_page_tag?
35
- page_number > 2
36
- end
37
-
38
- def first_page_tag
39
- %Q(<a href="#{url.chop}?page=1&per=#{pagination_per}">1</a>)
40
- end
41
-
42
- def show_first_ellipsis_tag?
43
- page_number >= 4
44
- end
45
-
46
- def ellipsis_tag
47
- '<span>...</span>'
48
- end
49
-
50
- def show_prev_page_tag?
51
- page_number > 1
52
- end
53
-
54
- def prev_page_tag
55
- %Q(<a href="#{url.chop}?page=#{page_number - 1}&per=#{pagination_per}">#{page_number - 1}</a>)
56
- end
57
-
58
- def current_page_tag
59
- "<span><b>#{page_number}</b></span>"
60
- end
61
-
62
- def show_next_page_tag?(collection)
63
- (page_number * pagination_per) < collection.count
64
- end
65
-
66
- def next_page_tag
67
- %Q(<a href="#{url.chop}?page=#{page_number + 1}&per=#{pagination_per}">#{page_number + 1}</a>)
68
- end
69
-
70
- def show_last_ellipsis_tag?(collection)
71
- (total_pages(collection) - page_number) >= 3
72
- end
73
-
74
- def total_pages(collection)
75
- collection.count / pagination_per + ((collection.count % pagination_per).zero? ? 0 : 1)
76
- end
77
-
78
- def show_last_page_tag?(collection)
79
- page_number < (total_pages(collection) - 1)
80
- end
81
-
82
- def last_page_tag(collection)
83
- total = total_pages(collection)
84
- %Q(<a href="#{url.chop}?page=#{total}&per=#{pagination_per}">#{total}</a>)
85
- end
33
+ def show_first_page_tag?
34
+ page_number > 2
35
+ end
36
+
37
+ def first_page_tag
38
+ %Q(<a href="#{url.chop}?page=1&per=#{pagination_per}">1</a>)
39
+ end
40
+
41
+ def show_first_ellipsis_tag?
42
+ page_number >= 4
43
+ end
44
+
45
+ def ellipsis_tag
46
+ "<span>...</span>"
47
+ end
48
+
49
+ def show_prev_page_tag?
50
+ page_number > 1
51
+ end
52
+
53
+ def prev_page_tag
54
+ %Q(<a href="#{url.chop}?page=#{page_number - 1}&per=#{pagination_per}">#{page_number - 1}</a>)
55
+ end
56
+
57
+ def current_page_tag
58
+ "<span><b>#{page_number}</b></span>"
59
+ end
60
+
61
+ def show_next_page_tag?(collection)
62
+ (page_number * pagination_per) < collection.count
63
+ end
64
+
65
+ def next_page_tag
66
+ %Q(<a href="#{url.chop}?page=#{page_number + 1}&per=#{pagination_per}">#{page_number + 1}</a>)
67
+ end
68
+
69
+ def show_last_ellipsis_tag?(collection)
70
+ (total_pages(collection) - page_number) >= 3
71
+ end
72
+
73
+ def total_pages(collection)
74
+ collection.count / pagination_per + ((collection.count % pagination_per).zero? ? 0 : 1)
75
+ end
76
+
77
+ def show_last_page_tag?(collection)
78
+ page_number < (total_pages(collection) - 1)
79
+ end
80
+
81
+ def last_page_tag(collection)
82
+ total = total_pages(collection)
83
+ %Q(<a href="#{url.chop}?page=#{total}&per=#{pagination_per}">#{total}</a>)
84
+ end
86
85
  end
87
86
  end
@@ -258,7 +258,7 @@ body {
258
258
  color: #408C48;
259
259
  }
260
260
 
261
- a.button, button, input[type="submit"] {
261
+ .experiment a.button, .experiment button, .experiment input[type="submit"] {
262
262
  padding: 4px 10px;
263
263
  overflow: hidden;
264
264
  background: #d8dae0;
@@ -312,10 +312,13 @@ a.button.green:focus, button.green:focus, input[type="submit"].green:focus {
312
312
  background:#768E7A;
313
313
  }
314
314
 
315
- #filter, #clear-filter {
315
+ .dashboard-controls input, .dashboard-controls select {
316
316
  padding: 10px;
317
317
  }
318
318
 
319
+ .dashboard-controls-bottom {
320
+ margin-top: 10px;
321
+ }
319
322
 
320
323
  .pagination {
321
324
  text-align: center;
@@ -1,10 +1,12 @@
1
1
  <% if @experiments.any? %>
2
2
  <p class="intro">The list below contains all the registered experiments along with the number of test participants, completed and conversion rate currently in the system.</p>
3
3
 
4
- <input type="text" placeholder="Begin typing to filter" id="filter" />
5
- <input type="button" id="toggle-completed" value="Hide completed" />
6
- <input type="button" id="toggle-active" value="Hide active" />
7
- <input type="button" id="clear-filter" value="Clear filters" />
4
+ <div class="dashboard-controls">
5
+ <input type="text" placeholder="Begin typing to filter" id="filter" />
6
+ <input type="button" id="toggle-completed" value="Hide completed" />
7
+ <input type="button" id="toggle-active" value="Hide active" />
8
+ <input type="button" id="clear-filter" value="Clear filters" />
9
+ </div>
8
10
 
9
11
  <% paginated(@experiments).each do |experiment| %>
10
12
  <% if experiment.goals.empty? %>
@@ -24,3 +26,16 @@
24
26
  <p class="intro">No experiments have started yet, you need to define them in your code and introduce them to your users.</p>
25
27
  <p class="intro">Check out the <a href='https://github.com/splitrb/split#readme'>Readme</a> for more help getting started.</p>
26
28
  <% end %>
29
+
30
+ <div class="dashboard-controls dashboard-controls-bottom">
31
+ <form action="<%= url "/initialize_experiment" %>" method='post'>
32
+ <label>Add unregistered experiment: </label>
33
+ <select name="experiment" id="experiment-select">
34
+ <option selected disabled>experiment</option>
35
+ <% @unintialized_experiments.sort.each do |experiment_name| %>
36
+ <option value="<%= experiment_name %>"><%= experiment_name %></option>
37
+ <% end %>
38
+ </select>
39
+ <input type="submit" id="register-experiment-btn" value="register experiment"/>
40
+ </form>
41
+ <div>
@@ -1,10 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'sinatra/base'
4
- require 'split'
5
- require 'bigdecimal'
6
- require 'split/dashboard/helpers'
7
- require 'split/dashboard/pagination_helpers'
3
+ require "sinatra/base"
4
+ require "split"
5
+ require "bigdecimal"
6
+ require "split/dashboard/helpers"
7
+ require "split/dashboard/pagination_helpers"
8
8
 
9
9
  module Split
10
10
  class Dashboard < Sinatra::Base
@@ -18,14 +18,15 @@ module Split
18
18
  helpers Split::DashboardHelpers
19
19
  helpers Split::DashboardPaginationHelpers
20
20
 
21
- get '/' do
21
+ get "/" do
22
22
  # Display experiments without a winner at the top of the dashboard
23
23
  @experiments = Split::ExperimentCatalog.all_active_first
24
+ @unintialized_experiments = Split.configuration.experiments.keys - @experiments.map(&:name)
24
25
 
25
26
  @metrics = Split::Metric.all
26
27
 
27
28
  # Display Rails Environment mode (or Rack version if not using Rails)
28
- if Object.const_defined?('Rails')
29
+ if Object.const_defined?("Rails") && Rails.respond_to?(:env)
29
30
  @current_env = Rails.env.titlecase
30
31
  else
31
32
  @current_env = "Rack: #{Rack.version}"
@@ -33,43 +34,48 @@ module Split
33
34
  erb :index
34
35
  end
35
36
 
36
- post '/force_alternative' do
37
+ post "/initialize_experiment" do
38
+ Split::ExperimentCatalog.find_or_create(params[:experiment]) unless params[:experiment].nil? || params[:experiment].empty?
39
+ redirect url("/")
40
+ end
41
+
42
+ post "/force_alternative" do
37
43
  experiment = Split::ExperimentCatalog.find(params[:experiment])
38
44
  alternative = Split::Alternative.new(params[:alternative], experiment.name)
39
45
 
40
- cookies = JSON.parse(request.cookies['split_override']) rescue {}
46
+ cookies = JSON.parse(request.cookies["split_override"]) rescue {}
41
47
  cookies[experiment.name] = alternative.name
42
- response.set_cookie('split_override', { value: cookies.to_json, path: '/' })
48
+ response.set_cookie("split_override", { value: cookies.to_json, path: "/" })
43
49
 
44
- redirect url('/')
50
+ redirect url("/")
45
51
  end
46
52
 
47
- post '/experiment' do
53
+ post "/experiment" do
48
54
  @experiment = Split::ExperimentCatalog.find(params[:experiment])
49
55
  @alternative = Split::Alternative.new(params[:alternative], params[:experiment])
50
56
  @experiment.winner = @alternative.name
51
- redirect url('/')
57
+ redirect url("/")
52
58
  end
53
59
 
54
- post '/start' do
60
+ post "/start" do
55
61
  @experiment = Split::ExperimentCatalog.find(params[:experiment])
56
62
  @experiment.start
57
- redirect url('/')
63
+ redirect url("/")
58
64
  end
59
65
 
60
- post '/reset' do
66
+ post "/reset" do
61
67
  @experiment = Split::ExperimentCatalog.find(params[:experiment])
62
68
  @experiment.reset
63
- redirect url('/')
69
+ redirect url("/")
64
70
  end
65
71
 
66
- post '/reopen' do
72
+ post "/reopen" do
67
73
  @experiment = Split::ExperimentCatalog.find(params[:experiment])
68
74
  @experiment.reset_winner
69
- redirect url('/')
75
+ redirect url("/")
70
76
  end
71
77
 
72
- post '/update_cohorting' do
78
+ post "/update_cohorting" do
73
79
  @experiment = Split::ExperimentCatalog.find(params[:experiment])
74
80
  case params[:cohorting_action].downcase
75
81
  when "enable"
@@ -77,13 +83,13 @@ module Split
77
83
  when "disable"
78
84
  @experiment.disable_cohorting
79
85
  end
80
- redirect url('/')
86
+ redirect url("/")
81
87
  end
82
88
 
83
- delete '/experiment' do
89
+ delete "/experiment" do
84
90
  @experiment = Split::ExperimentCatalog.find(params[:experiment])
85
91
  @experiment.delete
86
- redirect url('/')
92
+ redirect url("/")
87
93
  end
88
94
  end
89
95
  end
@@ -15,7 +15,6 @@ require "split/helper"
15
15
  #
16
16
  module Split
17
17
  module EncapsulatedHelper
18
-
19
18
  class ContextShim
20
19
  include Split::Helper
21
20
  public :ab_test, :ab_finished
@@ -34,10 +33,9 @@ module Split
34
33
  end
35
34
 
36
35
  private
37
-
38
- # instantiate and memoize a context shim in case of multiple ab_test* calls
39
- def split_context_shim
40
- @split_context_shim ||= ContextShim.new(self)
41
- end
36
+ # instantiate and memoize a context shim in case of multiple ab_test* calls
37
+ def split_context_shim
38
+ @split_context_shim ||= ContextShim.new(self)
39
+ end
42
40
  end
43
41
  end
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'rubystats'
4
-
5
3
  module Split
6
4
  class Experiment
7
5
  attr_accessor :name
@@ -13,7 +11,7 @@ module Split
13
11
  attr_reader :resettable
14
12
 
15
13
  DEFAULT_OPTIONS = {
16
- :resettable => true
14
+ resettable: true
17
15
  }
18
16
 
19
17
  def self.find(name)
@@ -52,7 +50,7 @@ module Split
52
50
 
53
51
  if alts.length == 1
54
52
  if alts[0].is_a? Hash
55
- alts = alts[0].map{|k, v| {k => v} }
53
+ alts = alts[0].map { |k, v| { k => v } }
56
54
  end
57
55
  end
58
56
 
@@ -87,7 +85,7 @@ module Split
87
85
  persist_experiment_configuration
88
86
  end
89
87
 
90
- redis.hmset(experiment_config_key, :resettable, resettable,
88
+ redis.hmset(experiment_config_key, :resettable, resettable.to_s,
91
89
  :algorithm, algorithm.to_s)
92
90
  self
93
91
  end
@@ -96,7 +94,7 @@ module Split
96
94
  if @alternatives.empty? && Split.configuration.experiment_for(@name).nil?
97
95
  raise ExperimentNotFound.new("Experiment #{@name} not found")
98
96
  end
99
- @alternatives.each {|a| a.validate! }
97
+ @alternatives.each { |a| a.validate! }
100
98
  goals_collection.validate!
101
99
  end
102
100
 
@@ -109,7 +107,7 @@ module Split
109
107
  end
110
108
 
111
109
  def [](name)
112
- alternatives.find{|a| a.name == name}
110
+ alternatives.find { |a| a.name == name }
113
111
  end
114
112
 
115
113
  def algorithm
@@ -121,7 +119,7 @@ module Split
121
119
  end
122
120
 
123
121
  def resettable=(resettable)
124
- @resettable = resettable.is_a?(String) ? resettable == 'true' : resettable
122
+ @resettable = resettable.is_a?(String) ? resettable == "true" : resettable
125
123
  end
126
124
 
127
125
  def alternatives=(alts)
@@ -157,7 +155,7 @@ module Split
157
155
  end
158
156
 
159
157
  def participant_count
160
- alternatives.inject(0){|sum, a| sum + a.participant_count}
158
+ alternatives.inject(0) { |sum, a| sum + a.participant_count }
161
159
  end
162
160
 
163
161
  def control
@@ -262,8 +260,8 @@ module Split
262
260
  exp_config = redis.hgetall(experiment_config_key)
263
261
 
264
262
  options = {
265
- resettable: exp_config['resettable'],
266
- algorithm: exp_config['algorithm'],
263
+ resettable: exp_config["resettable"],
264
+ algorithm: exp_config["algorithm"],
267
265
  alternatives: load_alternatives_from_redis,
268
266
  goals: Split::GoalsCollection.new(@name).load_from_redis,
269
267
  metadata: load_metadata_from_redis
@@ -328,11 +326,11 @@ module Split
328
326
  winning_counts.each do |alternative, wins|
329
327
  alternative_probabilities[alternative] = wins / number_of_simulations.to_f
330
328
  end
331
- return alternative_probabilities
329
+ alternative_probabilities
332
330
  end
333
331
 
334
332
  def count_simulated_wins(winning_alternatives)
335
- # initialize a hash to keep track of winning alternative in simulations
333
+ # initialize a hash to keep track of winning alternative in simulations
336
334
  winning_counts = {}
337
335
  alternatives.each do |alternative|
338
336
  winning_counts[alternative] = 0
@@ -341,7 +339,7 @@ module Split
341
339
  winning_alternatives.each do |alternative|
342
340
  winning_counts[alternative] += 1
343
341
  end
344
- return winning_counts
342
+ winning_counts
345
343
  end
346
344
 
347
345
  def find_simulated_winner(simulated_cr_hash)
@@ -353,7 +351,7 @@ module Split
353
351
  end
354
352
  end
355
353
  winner = winning_pair[0]
356
- return winner
354
+ winner
357
355
  end
358
356
 
359
357
  def calc_simulated_conversion_rates(beta_params)
@@ -363,11 +361,11 @@ module Split
363
361
  beta_params.each do |alternative, params|
364
362
  alpha = params[0]
365
363
  beta = params[1]
366
- simulated_conversion_rate = Rubystats::BetaDistribution.new(alpha, beta).rng
364
+ simulated_conversion_rate = Split::Algorithms.beta_distribution_rng(alpha, beta)
367
365
  simulated_cr_hash[alternative] = simulated_conversion_rate
368
366
  end
369
367
 
370
- return simulated_cr_hash
368
+ simulated_cr_hash
371
369
  end
372
370
 
373
371
  def calc_beta_params(goal = nil)
@@ -381,7 +379,7 @@ module Split
381
379
 
382
380
  beta_params[alternative] = params
383
381
  end
384
- return beta_params
382
+ beta_params
385
383
  end
386
384
 
387
385
  def calc_time=(time)
@@ -394,11 +392,11 @@ module Split
394
392
 
395
393
  def jstring(goal = nil)
396
394
  js_id = if goal.nil?
397
- name
398
- else
399
- name + "-" + goal
400
- end
401
- js_id.gsub('/', '--')
395
+ name
396
+ else
397
+ name + "-" + goal
398
+ end
399
+ js_id.gsub("/", "--")
402
400
  end
403
401
 
404
402
  def cohorting_disabled?
@@ -410,95 +408,93 @@ module Split
410
408
 
411
409
  def disable_cohorting
412
410
  @cohorting_disabled = true
413
- redis.hset(experiment_config_key, :cohorting, true)
411
+ redis.hset(experiment_config_key, :cohorting, true.to_s)
414
412
  end
415
413
 
416
414
  def enable_cohorting
417
415
  @cohorting_disabled = false
418
- redis.hset(experiment_config_key, :cohorting, false)
416
+ redis.hset(experiment_config_key, :cohorting, false.to_s)
419
417
  end
420
418
 
421
419
  protected
420
+ def experiment_config_key
421
+ "experiment_configurations/#{@name}"
422
+ end
422
423
 
423
- def experiment_config_key
424
- "experiment_configurations/#{@name}"
425
- end
426
-
427
- def load_metadata_from_configuration
428
- Split.configuration.experiment_for(@name)[:metadata]
429
- end
424
+ def load_metadata_from_configuration
425
+ Split.configuration.experiment_for(@name)[:metadata]
426
+ end
430
427
 
431
- def load_metadata_from_redis
432
- meta = redis.get(metadata_key)
433
- JSON.parse(meta) unless meta.nil?
434
- end
428
+ def load_metadata_from_redis
429
+ meta = redis.get(metadata_key)
430
+ JSON.parse(meta) unless meta.nil?
431
+ end
435
432
 
436
- def load_alternatives_from_configuration
437
- alts = Split.configuration.experiment_for(@name)[:alternatives]
438
- raise ArgumentError, "Experiment configuration is missing :alternatives array" unless alts
439
- if alts.is_a?(Hash)
440
- alts.keys
441
- else
442
- alts.flatten
433
+ def load_alternatives_from_configuration
434
+ alts = Split.configuration.experiment_for(@name)[:alternatives]
435
+ raise ArgumentError, "Experiment configuration is missing :alternatives array" unless alts
436
+ if alts.is_a?(Hash)
437
+ alts.keys
438
+ else
439
+ alts.flatten
440
+ end
443
441
  end
444
- end
445
442
 
446
- def load_alternatives_from_redis
447
- alternatives = redis.lrange(@name, 0, -1)
448
- alternatives.map do |alt|
449
- alt = begin
450
- JSON.parse(alt)
451
- rescue
452
- alt
453
- end
454
- Split::Alternative.new(alt, @name)
443
+ def load_alternatives_from_redis
444
+ alternatives = redis.lrange(@name, 0, -1)
445
+ alternatives.map do |alt|
446
+ alt = begin
447
+ JSON.parse(alt)
448
+ rescue
449
+ alt
450
+ end
451
+ Split::Alternative.new(alt, @name)
452
+ end
455
453
  end
456
- end
457
454
 
458
455
  private
456
+ def redis
457
+ Split.redis
458
+ end
459
459
 
460
- def redis
461
- Split.redis
462
- end
460
+ def redis_interface
461
+ RedisInterface.new
462
+ end
463
463
 
464
- def redis_interface
465
- RedisInterface.new
466
- end
464
+ def persist_experiment_configuration
465
+ redis_interface.add_to_set(:experiments, name)
466
+ redis_interface.persist_list(name, @alternatives.map { |alt| { alt.name => alt.weight }.to_json })
467
+ goals_collection.save
467
468
 
468
- def persist_experiment_configuration
469
- redis_interface.add_to_set(:experiments, name)
470
- redis_interface.persist_list(name, @alternatives.map{|alt| {alt.name => alt.weight}.to_json})
471
- goals_collection.save
469
+ if @metadata
470
+ redis.set(metadata_key, @metadata.to_json)
471
+ else
472
+ delete_metadata
473
+ end
474
+ end
472
475
 
473
- if @metadata
474
- redis.set(metadata_key, @metadata.to_json)
475
- else
476
+ def remove_experiment_configuration
477
+ @alternatives.each(&:delete)
478
+ goals_collection.delete
476
479
  delete_metadata
480
+ redis.del(@name)
477
481
  end
478
- end
479
482
 
480
- def remove_experiment_configuration
481
- @alternatives.each(&:delete)
482
- goals_collection.delete
483
- delete_metadata
484
- redis.del(@name)
485
- end
483
+ def experiment_configuration_has_changed?
484
+ existing_experiment = Experiment.find(@name)
486
485
 
487
- def experiment_configuration_has_changed?
488
- existing_experiment = Experiment.find(@name)
489
-
490
- existing_experiment.alternatives.map(&:to_s) != @alternatives.map(&:to_s) ||
491
- existing_experiment.goals != @goals ||
492
- existing_experiment.metadata != @metadata
493
- end
486
+ existing_experiment.alternatives.map(&:to_s) != @alternatives.map(&:to_s) ||
487
+ existing_experiment.goals != @goals ||
488
+ existing_experiment.metadata != @metadata
489
+ end
494
490
 
495
- def goals_collection
496
- Split::GoalsCollection.new(@name, @goals)
497
- end
491
+ def goals_collection
492
+ Split::GoalsCollection.new(@name, @goals)
493
+ end
498
494
 
499
- def remove_experiment_cohorting
500
- @cohorting_disabled = false
501
- redis.hdel(experiment_config_key, :cohorting)
502
- end
495
+ def remove_experiment_cohorting
496
+ @cohorting_disabled = false
497
+ redis.hdel(experiment_config_key, :cohorting)
498
+ end
503
499
  end
504
500
  end