split 3.3.1 → 3.4.0

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.
data/.travis.yml CHANGED
@@ -3,18 +3,18 @@ rvm:
3
3
  - 1.9.3
4
4
  - 2.0
5
5
  - 2.1.10
6
- - 2.2.0
7
6
  - 2.2.2
8
- - 2.4.5
9
- - 2.5.3
10
- - 2.6.0
7
+ - 2.3.8
8
+ - 2.4.9
9
+ - 2.5.7
10
+ - 2.6.5
11
11
 
12
12
  gemfile:
13
13
  - gemfiles/4.2.gemfile
14
14
  - gemfiles/5.0.gemfile
15
15
  - gemfiles/5.1.gemfile
16
16
  - gemfiles/5.2.gemfile
17
-
17
+ - gemfiles/6.0.gemfile
18
18
 
19
19
  matrix:
20
20
  exclude:
@@ -24,27 +24,33 @@ matrix:
24
24
  gemfile: gemfiles/5.1.gemfile
25
25
  - rvm: 1.9.3
26
26
  gemfile: gemfiles/5.2.gemfile
27
+ - rvm: 1.9.3
28
+ gemfile: gemfiles/6.0.gemfile
27
29
  - rvm: 2.0
28
30
  gemfile: gemfiles/5.0.gemfile
29
31
  - rvm: 2.0
30
32
  gemfile: gemfiles/5.1.gemfile
31
33
  - rvm: 2.0
32
34
  gemfile: gemfiles/5.2.gemfile
35
+ - rvm: 2.0
36
+ gemfile: gemfiles/6.0.gemfile
33
37
  - rvm: 2.1.10
34
38
  gemfile: gemfiles/5.0.gemfile
35
39
  - rvm: 2.1.10
36
40
  gemfile: gemfiles/5.1.gemfile
37
41
  - rvm: 2.1.10
38
42
  gemfile: gemfiles/5.2.gemfile
39
- - rvm: 2.2.0
40
- gemfile: gemfiles/5.0.gemfile
41
- - rvm: 2.2.0
42
- gemfile: gemfiles/5.1.gemfile
43
- - rvm: 2.2.0
44
- gemfile: gemfiles/5.2.gemfile
45
-
43
+ - rvm: 2.1.10
44
+ gemfile: gemfiles/6.0.gemfile
45
+ - rvm: 2.2.2
46
+ gemfile: gemfiles/6.0.gemfile
47
+ - rvm: 2.3.8
48
+ gemfile: gemfiles/6.0.gemfile
49
+ - rvm: 2.4.9
50
+ gemfile: gemfiles/6.0.gemfile
46
51
 
47
52
  before_install:
53
+ - gem uninstall -v '>= 2' -i $(rvm gemdir)@global -ax bundler || true
48
54
  - gem install bundler --version=1.17.3
49
55
 
50
56
  script:
data/Appraisals CHANGED
@@ -13,3 +13,7 @@ end
13
13
  appraise "5.2" do
14
14
  gem "rails", "~> 5.2"
15
15
  end
16
+
17
+ appraise "6.0" do
18
+ gem 'rails', '~> 6.0'
19
+ end
data/CHANGELOG.md CHANGED
@@ -1,11 +1,55 @@
1
+ ## 3.4.0 (November 9th, 2019)
2
+
3
+ Features:
4
+ - Improve DualAdapter (@santib, #588), adds a new configuration for the DualAdapter, making it possible to keep consistency for logged_out/logged_in users. It's a opt-in flag. No Behavior was changed on this release.
5
+ - Make dashboard pagination default "per" param configurable (@alopatin, #597)
6
+
7
+ Bugfixes:
8
+ - Fix `force_alternative` for experiments with incremented version (@giraffate, #568)
9
+ - Persist alternative weights (@giraffate, #570)
10
+ - Combined experiment performance improvements (@gnanou, #575)
11
+ - Handle correctly case when ab_finished is called before ab_test for a user (@gnanou, #577)
12
+ - When loading active_experiments, it should not look into user's 'finished' keys (@andrehjr, #582)
13
+
14
+ Misc:
15
+ - Remove `rubyforge_project` from gemspec (@giraffate, #583)
16
+ - Fix URLs to replace http with https (@giraffate , #584)
17
+ - Lazily include split helpers in ActionController::Base (@hasghari, #586)
18
+ - Fix unused variable warnings (@andrehjr, #592)
19
+ - Fix ruby warnings (@andrehjr, #593)
20
+ - Update rubocop.yml config (@andrehjr, #594)
21
+ - Add frozen_string_literal to all files that were missing it (@andrehjr, #595)
22
+
23
+ ## 3.3.2 (April 12th, 2019)
24
+
25
+ Features:
26
+ - Added uptime robot to configuration.rb (@razel1982, #556)
27
+ - Check to see if being run in Rails application and run in before_initialize (@husteadrobert, #555)
28
+
29
+ Bugfixes:
30
+ - Fix error message interpolation (@hanibash, #553)
31
+ - Fix Bigdecimal warnings (@agraves, #551)
32
+ - Avoid hitting up on redis for robots/excluded users. (@andrehjr, #544)
33
+ - Checks for defined?(request) on Helper#exclude_visitor?. (@andrehjr)
34
+
35
+ Misc:
36
+ - Update travis to add Rails 6 (@edmilton, #559)
37
+ - Fix broken specs in developement environment (@dougpetronilio, #557)
38
+
1
39
  ## 3.3.1 (January 11th, 2019)
40
+
41
+ Features:
2
42
  - Filter some more bots (@janosch-x, #542)
43
+
44
+ Bugfixes:
3
45
  - Fix Dashboard Pagination Helper typo (@cattekin, #541)
4
- - Tweak RSpec instructions (@eliotsykes, #540)
5
46
  - Do not storage alternative in cookie if experiment has a winner (@sadhu89, #539)
6
- - Improve README regarding rspec usage (@vermaxik, #538)
7
47
  - fix user participating alternative not found (@NaturalHokke, #536)
8
48
 
49
+ Misc:
50
+ - Tweak RSpec instructions (@eliotsykes, #540)
51
+ - Improve README regarding rspec usage (@vermaxik, #538)
52
+
9
53
  ## 3.3.0 (August 13th, 2018)
10
54
 
11
55
  Features:
data/CODE_OF_CONDUCT.md CHANGED
@@ -68,7 +68,7 @@ members of the project's leadership.
68
68
  ## Attribution
69
69
 
70
70
  This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
71
- available at [http://contributor-covenant.org/version/1/4][version]
71
+ available at [https://contributor-covenant.org/version/1/4][version]
72
72
 
73
- [homepage]: http://contributor-covenant.org
74
- [version]: http://contributor-covenant.org/version/1/4/
73
+ [homepage]: https://contributor-covenant.org
74
+ [version]: https://contributor-covenant.org/version/1/4/
data/Gemfile CHANGED
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  source "https://rubygems.org"
2
3
 
3
4
  gemspec
data/README.md CHANGED
@@ -1,13 +1,13 @@
1
- # [Split](http://libraries.io/rubygems/split)
1
+ # [Split](https://libraries.io/rubygems/split)
2
2
 
3
3
  [![Gem Version](https://badge.fury.io/rb/split.svg)](http://badge.fury.io/rb/split)
4
- [![Build Status](https://secure.travis-ci.org/splitrb/split.svg?branch=master)](http://travis-ci.org/splitrb/split)
4
+ [![Build Status](https://secure.travis-ci.org/splitrb/split.svg?branch=master)](https://travis-ci.org/splitrb/split)
5
5
  [![Code Climate](https://codeclimate.com/github/splitrb/split/badges/gpa.svg)](https://codeclimate.com/github/splitrb/split)
6
6
  [![Test Coverage](https://codeclimate.com/github/splitrb/split/badges/coverage.svg)](https://codeclimate.com/github/splitrb/split/coverage)
7
7
  [![standard-readme compliant](https://img.shields.io/badge/readme%20style-standard-brightgreen.svg?style=flat-square)](https://github.com/RichardLitt/standard-readme)
8
8
  [![Open Source Helpers](https://www.codetriage.com/splitrb/split/badges/users.svg)](https://www.codetriage.com/splitrb/split)
9
9
 
10
- > 📈 The Rack Based A/B testing framework http://libraries.io/rubygems/split
10
+ > 📈 The Rack Based A/B testing framework https://libraries.io/rubygems/split
11
11
 
12
12
  Split is a rack based A/B testing framework designed to work with Rails, Sinatra or any other rack based app.
13
13
 
@@ -110,9 +110,9 @@ Split has two options for you to use to determine which alternative is the best.
110
110
 
111
111
  The first option (default on the dashboard) uses a z test (n>30) for the difference between your control and alternative conversion rates to calculate statistical significance. This test will tell you whether an alternative is better or worse than your control, but it will not distinguish between which alternative is the best in an experiment with multiple alternatives. Split will only tell you if your experiment is 90%, 95%, or 99% significant, and this test only works if you have more than 30 participants and 5 conversions for each branch.
112
112
 
113
- As per this [blog post](http://www.evanmiller.org/how-not-to-run-an-ab-test.html) on the pitfalls of A/B testing, it is highly recommended that you determine your requisite sample size for each branch before running the experiment. Otherwise, you'll have an increased rate of false positives (experiments which show a significant effect where really there is none).
113
+ As per this [blog post](https://www.evanmiller.org/how-not-to-run-an-ab-test.html) on the pitfalls of A/B testing, it is highly recommended that you determine your requisite sample size for each branch before running the experiment. Otherwise, you'll have an increased rate of false positives (experiments which show a significant effect where really there is none).
114
114
 
115
- [Here](http://www.evanmiller.org/ab-testing/sample-size.html) is a sample size calculator for your convenience.
115
+ [Here](https://www.evanmiller.org/ab-testing/sample-size.html) is a sample size calculator for your convenience.
116
116
 
117
117
  The second option uses simulations from a beta distribution to determine the probability that the given alternative is the winner compared to all other alternatives. You can view these probabilities by clicking on the drop-down menu labeled "Confidence." This option should be used when the experiment has more than just 1 control and 1 alternative. It can also be used for a simple, 2-alternative A/B test.
118
118
 
@@ -360,7 +360,7 @@ end
360
360
 
361
361
  If you are running `ab_test` from a view, you must define your event
362
362
  hook callback as a
363
- [helper_method](http://apidock.com/rails/AbstractController/Helpers/ClassMethods/helper_method)
363
+ [helper_method](https://apidock.com/rails/AbstractController/Helpers/ClassMethods/helper_method)
364
364
  in the controller:
365
365
 
366
366
  ``` ruby
@@ -446,7 +446,7 @@ match "/split" => Split::Dashboard, anchor: false, via: [:get, :post, :delete],
446
446
  end
447
447
  ```
448
448
 
449
- 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/)
449
+ More information on this [here](https://steve.dynedge.co.uk/2011/12/09/controlling-access-to-routes-and-rack-apps-in-rails-3-with-devise-and-warden/)
450
450
 
451
451
  ### Screenshot
452
452
 
@@ -556,7 +556,7 @@ and:
556
556
  ab_finished(:my_first_experiment)
557
557
  ```
558
558
 
559
- You can also add meta data for each experiment, very useful when you need more than an alternative name to change behaviour:
559
+ You can also add meta data for each experiment, which is very useful when you need more than an alternative name to change behaviour:
560
560
 
561
561
  ```ruby
562
562
  Split.configure do |config|
@@ -601,6 +601,8 @@ or in views:
601
601
  <% end %>
602
602
  ```
603
603
 
604
+ The keys used in meta data should be Strings
605
+
604
606
  #### Metrics
605
607
 
606
608
  You might wish to track generic metrics, such as conversions, and use
@@ -824,8 +826,8 @@ end
824
826
 
825
827
  ## Extensions
826
828
 
827
- - [Split::Export](http://github.com/splitrb/split-export) - Easily export A/B test data out of Split.
828
- - [Split::Analytics](http://github.com/splitrb/split-analytics) - Push test data to Google Analytics.
829
+ - [Split::Export](https://github.com/splitrb/split-export) - Easily export A/B test data out of Split.
830
+ - [Split::Analytics](https://github.com/splitrb/split-analytics) - Push test data to Google Analytics.
829
831
  - [Split::Mongoid](https://github.com/MongoHQ/split-mongoid) - Store experiment data in mongoid (still uses redis).
830
832
  - [Split::Cacheable](https://github.com/harrystech/split_cacheable) - Automatically create cache buckets per test.
831
833
  - [Split::Counters](https://github.com/bernardkroes/split-counters) - Add counters per experiment and alternative.
@@ -837,7 +839,7 @@ Ryan bates has produced an excellent 10 minute screencast about split on the Rai
837
839
 
838
840
  ## Blogposts
839
841
 
840
- * [Recipe: A/B testing with KISSMetrics and the split gem](http://robots.thoughtbot.com/post/9595887299/recipe-a-b-testing-with-kissmetrics-and-the-split-gem)
842
+ * [Recipe: A/B testing with KISSMetrics and the split gem](https://robots.thoughtbot.com/post/9595887299/recipe-a-b-testing-with-kissmetrics-and-the-split-gem)
841
843
  * [Rails A/B testing with Split on Heroku](http://blog.nathanhumbert.com/2012/02/rails-ab-testing-with-split-on-heroku.html)
842
844
 
843
845
  ## Backers
@@ -917,9 +919,9 @@ Please do! Over 70 different people have contributed to the project, you can see
917
919
 
918
920
  ### Development
919
921
 
920
- The source code is hosted at [GitHub](http://github.com/splitrb/split).
922
+ The source code is hosted at [GitHub](https://github.com/splitrb/split).
921
923
 
922
- Report issues and feature requests on [GitHub Issues](http://github.com/splitrb/split/issues).
924
+ Report issues and feature requests on [GitHub Issues](https://github.com/splitrb/split/issues).
923
925
 
924
926
  You can find a discussion form on [Google Groups](https://groups.google.com/d/forum/split-ruby).
925
927
 
@@ -950,4 +952,4 @@ Please note that this project is released with a [Contributor Code of Conduct](C
950
952
 
951
953
  ## Copyright
952
954
 
953
- [MIT License](LICENSE) © 2018 [Andrew Nesbitt](https://github.com/andrew).
955
+ [MIT License](LICENSE) © 2019 [Andrew Nesbitt](https://github.com/andrew).
data/Rakefile CHANGED
@@ -1,4 +1,5 @@
1
1
  #!/usr/bin/env rake
2
+ # frozen_string_literal: true
2
3
  require 'bundler/gem_tasks'
3
4
  require 'rspec/core/rake_task'
4
5
  require 'appraisal'
@@ -0,0 +1,9 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "appraisal"
6
+ gem "codeclimate-test-reporter"
7
+ gem "rails", "~> 6.0"
8
+
9
+ gemspec path: "../"
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  # Selects alternative with minimum count of participants
2
3
  # If all counts are even (i.e. all are minimum), samples from all possible alternatives
3
4
 
@@ -15,7 +15,7 @@ module Split
15
15
  @name = name
16
16
  @weight = 1
17
17
  end
18
- p_winner = 0.0
18
+ @p_winner = 0.0
19
19
  end
20
20
 
21
21
  def to_s
@@ -75,7 +75,7 @@ module Split
75
75
  return field
76
76
  end
77
77
 
78
- def set_completed_count (count, goal = nil)
78
+ def set_completed_count(count, goal = nil)
79
79
  field = set_field(goal)
80
80
  Split.redis.hset(key, field, count.to_i)
81
81
  end
@@ -122,7 +122,7 @@ module Split
122
122
  # can't calculate zscore for P(x) > 1
123
123
  return 'N/A' if p_a > 1 || p_c > 1
124
124
 
125
- z_score = Split::Zscore.calculate(p_a, n_a, p_c, n_c)
125
+ Split::Zscore.calculate(p_a, n_a, p_c, n_c)
126
126
  end
127
127
 
128
128
  def extra_info
@@ -3,7 +3,7 @@ module Split
3
3
  module CombinedExperimentsHelper
4
4
  def ab_combined_test(metric_descriptor, control = nil, *alternatives)
5
5
  return nil unless experiment = find_combined_experiment(metric_descriptor)
6
- raise(Split::InvalidExperimentsFormatError, 'Unable to find experiment #{metric_descriptor} in configuration') if experiment[:combined_experiments].nil?
6
+ raise(Split::InvalidExperimentsFormatError, "Unable to find experiment #{metric_descriptor} in configuration") if experiment[:combined_experiments].nil?
7
7
 
8
8
  alternative = nil
9
9
  weighted_alternatives = nil
@@ -31,7 +31,7 @@ module Split
31
31
  raise(Split::InvalidExperimentsFormatError, 'Invalid descriptor class (String or Symbol required)') unless metric_descriptor.class == String || metric_descriptor.class == Symbol
32
32
  raise(Split::InvalidExperimentsFormatError, 'Enable configuration') unless Split.configuration.enabled
33
33
  raise(Split::InvalidExperimentsFormatError, 'Enable `allow_multiple_experiments`') unless Split.configuration.allow_multiple_experiments
34
- experiment = Split::configuration.experiments[metric_descriptor.to_sym]
34
+ Split::configuration.experiments[metric_descriptor.to_sym]
35
35
  end
36
36
  end
37
37
  end
@@ -1,8 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
  module Split
3
3
  class Configuration
4
- attr_accessor :bots
5
- attr_accessor :robot_regex
6
4
  attr_accessor :ignore_ip_addresses
7
5
  attr_accessor :ignore_filter
8
6
  attr_accessor :db_failover
@@ -27,9 +25,13 @@ module Split
27
25
  attr_accessor :beta_probability_simulations
28
26
  attr_accessor :winning_alternative_recalculation_interval
29
27
  attr_accessor :redis
28
+ attr_accessor :dashboard_pagination_default_per_page
30
29
 
31
30
  attr_reader :experiments
32
31
 
32
+ attr_writer :bots
33
+ attr_writer :robot_regex
34
+
33
35
  def bots
34
36
  @bots ||= {
35
37
  # Indexers
@@ -98,6 +100,7 @@ module Split
98
100
  'Panopta' => 'Monitoring service',
99
101
  'Pingdom' => 'Pingdom monitoring',
100
102
  'SiteUptime' => 'Site monitoring services',
103
+ 'UptimeRobot' => 'Monitoring service',
101
104
 
102
105
  # ???
103
106
  'DigitalPersona Fingerprint Software' => 'HP Fingerprint scanner',
@@ -224,6 +227,7 @@ module Split
224
227
  @beta_probability_simulations = 10000
225
228
  @winning_alternative_recalculation_interval = 60 * 60 * 24 # 1 day
226
229
  @redis = ENV.fetch(ENV.fetch('REDIS_PROVIDER', 'REDIS_URL'), 'redis://localhost:6379')
230
+ @dashboard_pagination_default_per_page = 10
227
231
  end
228
232
 
229
233
  def redis_url=(value)
@@ -19,9 +19,9 @@ module Split
19
19
 
20
20
  def round(number, precision = 2)
21
21
  begin
22
- BigDecimal.new(number.to_s)
22
+ BigDecimal(number.to_s)
23
23
  rescue ArgumentError
24
- BigDecimal.new(0)
24
+ BigDecimal(0)
25
25
  end.round(precision).to_f
26
26
  end
27
27
 
@@ -3,10 +3,9 @@ require 'split/dashboard/paginator'
3
3
 
4
4
  module Split
5
5
  module DashboardPaginationHelpers
6
- DEFAULT_PER = 10
7
-
8
6
  def pagination_per
9
- @pagination_per ||= (params[:per] || DEFAULT_PER).to_i
7
+ default_per_page = Split.configuration.dashboard_pagination_default_per_page
8
+ @pagination_per ||= (params[:per] || default_per_page).to_i
10
9
  end
11
10
 
12
11
  def page_number
@@ -21,7 +21,7 @@
21
21
  </div>
22
22
 
23
23
  <div id="footer">
24
- <p>Powered by <a href="http://github.com/splitrb/split">Split</a> v<%=Split::VERSION %></p>
24
+ <p>Powered by <a href="https://github.com/splitrb/split">Split</a> v<%=Split::VERSION %></p>
25
25
  </div>
26
26
  </body>
27
27
  </html>
@@ -33,7 +33,10 @@ module Split
33
33
  end
34
34
 
35
35
  post '/force_alternative' do
36
- Split::User.new(self)[params[:experiment]] = params[:alternative]
36
+ experiment = Split::ExperimentCatalog.find(params[:experiment])
37
+ alternative = Split::Alternative.new(params[:alternative], experiment.name)
38
+ alternative.increment_participation
39
+ Split::User.new(self)[experiment.key] = alternative.name
37
40
  redirect url('/')
38
41
  end
39
42
 
data/lib/split/engine.rb CHANGED
@@ -3,10 +3,12 @@ module Split
3
3
  class Engine < ::Rails::Engine
4
4
  initializer "split" do |app|
5
5
  if Split.configuration.include_rails_helper
6
- ActionController::Base.send :include, Split::Helper
7
- ActionController::Base.helper Split::Helper
8
- ActionController::Base.send :include, Split::CombinedExperimentsHelper
9
- ActionController::Base.helper Split::CombinedExperimentsHelper
6
+ ActiveSupport.on_load(:action_controller) do
7
+ include Split::Helper
8
+ helper Split::Helper
9
+ include Split::CombinedExperimentsHelper
10
+ helper Split::CombinedExperimentsHelper
11
+ end
10
12
  end
11
13
  end
12
14
  end
@@ -2,13 +2,13 @@
2
2
  module Split
3
3
  class Experiment
4
4
  attr_accessor :name
5
- attr_writer :algorithm
6
- attr_accessor :resettable
7
5
  attr_accessor :goals
8
- attr_accessor :alternatives
9
6
  attr_accessor :alternative_probabilities
10
7
  attr_accessor :metadata
11
8
 
9
+ attr_reader :alternatives
10
+ attr_reader :resettable
11
+
12
12
  DEFAULT_OPTIONS = {
13
13
  :resettable => true
14
14
  }
@@ -25,7 +25,7 @@ module Split
25
25
  alternatives: load_alternatives_from_configuration,
26
26
  goals: Split::GoalsCollection.new(@name).load_from_configuration,
27
27
  metadata: load_metadata_from_configuration,
28
- resettable: exp_config[:resettable],
28
+ resettable: exp_config.fetch(:resettable, true),
29
29
  algorithm: exp_config[:algorithm]
30
30
  }
31
31
  else
@@ -62,7 +62,7 @@ module Split
62
62
  alts = load_alternatives_from_configuration
63
63
  options[:goals] = Split::GoalsCollection.new(@name).load_from_configuration
64
64
  options[:metadata] = load_metadata_from_configuration
65
- options[:resettable] = exp_config[:resettable]
65
+ options[:resettable] = exp_config.fetch(:resettable, true)
66
66
  options[:algorithm] = exp_config[:algorithm]
67
67
  end
68
68
  end
@@ -81,12 +81,12 @@ module Split
81
81
 
82
82
  if new_record?
83
83
  start unless Split.configuration.start_manually
84
+ persist_experiment_configuration
84
85
  elsif experiment_configuration_has_changed?
85
86
  reset unless Split.configuration.reset_manually
87
+ persist_experiment_configuration
86
88
  end
87
89
 
88
- persist_experiment_configuration if new_record? || experiment_configuration_has_changed?
89
-
90
90
  redis.hset(experiment_config_key, :resettable, resettable)
91
91
  redis.hset(experiment_config_key, :algorithm, algorithm.to_s)
92
92
  self
@@ -144,11 +144,13 @@ module Split
144
144
  end
145
145
 
146
146
  def has_winner?
147
- !winner.nil?
147
+ return @has_winner if defined? @has_winner
148
+ @has_winner = !winner.nil?
148
149
  end
149
150
 
150
151
  def winner=(winner_name)
151
152
  redis.hset(:experiment_winner, name, winner_name.to_s)
153
+ @has_winner = true
152
154
  end
153
155
 
154
156
  def participant_count
@@ -161,6 +163,7 @@ module Split
161
163
 
162
164
  def reset_winner
163
165
  redis.hdel(:experiment_winner, name)
166
+ @has_winner = false
164
167
  end
165
168
 
166
169
  def start
@@ -420,14 +423,22 @@ module Split
420
423
  end
421
424
 
422
425
  def load_alternatives_from_redis
423
- case redis.type(@name)
424
- when 'set' # convert legacy sets to lists
425
- alts = redis.smembers(@name)
426
- redis.del(@name)
427
- alts.reverse.each {|a| redis.lpush(@name, a) }
428
- redis.lrange(@name, 0, -1)
429
- else
430
- redis.lrange(@name, 0, -1)
426
+ alternatives = case redis.type(@name)
427
+ when 'set' # convert legacy sets to lists
428
+ alts = redis.smembers(@name)
429
+ redis.del(@name)
430
+ alts.reverse.each {|a| redis.lpush(@name, a) }
431
+ redis.lrange(@name, 0, -1)
432
+ else
433
+ redis.lrange(@name, 0, -1)
434
+ end
435
+ alternatives.map do |alt|
436
+ alt = begin
437
+ JSON.parse(alt)
438
+ rescue
439
+ alt
440
+ end
441
+ Split::Alternative.new(alt, @name)
431
442
  end
432
443
  end
433
444
 
@@ -443,7 +454,7 @@ module Split
443
454
 
444
455
  def persist_experiment_configuration
445
456
  redis_interface.add_to_set(:experiments, name)
446
- redis_interface.persist_list(name, @alternatives.map(&:name))
457
+ redis_interface.persist_list(name, @alternatives.map{|alt| {alt.name => alt.weight}.to_json})
447
458
  goals_collection.save
448
459
  redis.set(metadata_key, @metadata.to_json) unless @metadata.nil?
449
460
  end
@@ -459,7 +470,7 @@ module Split
459
470
  existing_alternatives = load_alternatives_from_redis
460
471
  existing_goals = Split::GoalsCollection.new(@name).load_from_redis
461
472
  existing_metadata = load_metadata_from_redis
462
- existing_alternatives != @alternatives.map(&:name) ||
473
+ existing_alternatives.map(&:to_s) != @alternatives.map(&:to_s) ||
463
474
  existing_goals != @goals ||
464
475
  existing_metadata != @metadata
465
476
  end
@@ -1,3 +1,4 @@
1
+ # frozen_string_literal: true
1
2
  module Split
2
3
  class GoalsCollection
3
4
 
data/lib/split/helper.rb CHANGED
@@ -8,7 +8,7 @@ module Split
8
8
  def ab_test(metric_descriptor, control = nil, *alternatives)
9
9
  begin
10
10
  experiment = ExperimentCatalog.find_or_initialize(metric_descriptor, control, *alternatives)
11
- alternative = if Split.configuration.enabled
11
+ alternative = if Split.configuration.enabled && !exclude_visitor?
12
12
  experiment.save
13
13
  raise(Split::InvalidExperimentsFormatError) unless (Split.configuration.experiments || {}).fetch(experiment.name.to_sym, {})[:combined_experiments].nil?
14
14
  trial = Trial.new(:user => ab_user, :experiment => experiment,
@@ -44,6 +44,7 @@ module Split
44
44
  end
45
45
 
46
46
  def finish_experiment(experiment, options = {:reset => true})
47
+ return false if active_experiments[experiment.name].nil?
47
48
  return true if experiment.has_winner?
48
49
  should_reset = experiment.resettable? && options[:reset]
49
50
  if ab_user[experiment.finished_key] && !should_reset
@@ -79,7 +80,7 @@ module Split
79
80
 
80
81
  def ab_record_extra_info(metric_descriptor, key, value = 1)
81
82
  return if exclude_visitor? || Split.configuration.disabled?
82
- metric_descriptor, goals = normalize_metric(metric_descriptor)
83
+ metric_descriptor, _ = normalize_metric(metric_descriptor)
83
84
  experiments = Metric.possible_experiments(metric_descriptor)
84
85
 
85
86
  if experiments.any?
@@ -122,7 +123,7 @@ module Split
122
123
  end
123
124
 
124
125
  def exclude_visitor?
125
- instance_exec(request, &Split.configuration.ignore_filter) || is_ignored_ip_address? || is_robot? || is_preview?
126
+ defined?(request) && (instance_exec(request, &Split.configuration.ignore_filter) || is_ignored_ip_address? || is_robot? || is_preview?)
126
127
  end
127
128
 
128
129
  def is_robot?