split 3.3.0 → 4.0.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.
Files changed (73) hide show
  1. checksums.yaml +4 -4
  2. data/.eslintrc +1 -1
  3. data/.github/FUNDING.yml +1 -0
  4. data/.github/ISSUE_TEMPLATE/bug_report.md +24 -0
  5. data/.github/dependabot.yml +7 -0
  6. data/.github/workflows/ci.yml +71 -0
  7. data/.rspec +1 -0
  8. data/.rubocop.yml +71 -1044
  9. data/.rubocop_todo.yml +226 -0
  10. data/Appraisals +4 -0
  11. data/CHANGELOG.md +116 -0
  12. data/CODE_OF_CONDUCT.md +3 -3
  13. data/Gemfile +2 -0
  14. data/README.md +63 -26
  15. data/Rakefile +2 -0
  16. data/gemfiles/{4.2.gemfile → 6.0.gemfile} +1 -1
  17. data/gemfiles/6.1.gemfile +9 -0
  18. data/gemfiles/7.0.gemfile +9 -0
  19. data/lib/split/algorithms/block_randomization.rb +2 -0
  20. data/lib/split/algorithms/weighted_sample.rb +2 -1
  21. data/lib/split/algorithms/whiplash.rb +3 -2
  22. data/lib/split/alternative.rb +4 -3
  23. data/lib/split/cache.rb +28 -0
  24. data/lib/split/combined_experiments_helper.rb +3 -2
  25. data/lib/split/configuration.rb +17 -14
  26. data/lib/split/dashboard/helpers.rb +3 -2
  27. data/lib/split/dashboard/pagination_helpers.rb +4 -4
  28. data/lib/split/dashboard/paginator.rb +1 -0
  29. data/lib/split/dashboard/public/dashboard.js +10 -0
  30. data/lib/split/dashboard/public/style.css +5 -0
  31. data/lib/split/dashboard/views/_controls.erb +13 -0
  32. data/lib/split/dashboard/views/layout.erb +1 -1
  33. data/lib/split/dashboard.rb +19 -1
  34. data/lib/split/encapsulated_helper.rb +3 -2
  35. data/lib/split/engine.rb +7 -4
  36. data/lib/split/exceptions.rb +1 -0
  37. data/lib/split/experiment.rb +98 -65
  38. data/lib/split/experiment_catalog.rb +1 -3
  39. data/lib/split/extensions/string.rb +1 -0
  40. data/lib/split/goals_collection.rb +2 -0
  41. data/lib/split/helper.rb +30 -10
  42. data/lib/split/metric.rb +2 -1
  43. data/lib/split/persistence/cookie_adapter.rb +6 -1
  44. data/lib/split/persistence/dual_adapter.rb +54 -12
  45. data/lib/split/persistence/redis_adapter.rb +5 -0
  46. data/lib/split/persistence/session_adapter.rb +1 -0
  47. data/lib/split/persistence.rb +4 -2
  48. data/lib/split/redis_interface.rb +9 -28
  49. data/lib/split/trial.rb +25 -17
  50. data/lib/split/user.rb +20 -4
  51. data/lib/split/version.rb +2 -4
  52. data/lib/split/zscore.rb +1 -0
  53. data/lib/split.rb +16 -3
  54. data/spec/alternative_spec.rb +1 -1
  55. data/spec/cache_spec.rb +88 -0
  56. data/spec/configuration_spec.rb +17 -15
  57. data/spec/dashboard/pagination_helpers_spec.rb +3 -1
  58. data/spec/dashboard_helpers_spec.rb +2 -2
  59. data/spec/dashboard_spec.rb +78 -17
  60. data/spec/encapsulated_helper_spec.rb +2 -2
  61. data/spec/experiment_spec.rb +116 -12
  62. data/spec/goals_collection_spec.rb +1 -1
  63. data/spec/helper_spec.rb +191 -112
  64. data/spec/persistence/cookie_adapter_spec.rb +1 -1
  65. data/spec/persistence/dual_adapter_spec.rb +160 -68
  66. data/spec/persistence/redis_adapter_spec.rb +9 -0
  67. data/spec/redis_interface_spec.rb +0 -69
  68. data/spec/spec_helper.rb +5 -6
  69. data/spec/trial_spec.rb +65 -19
  70. data/spec/user_spec.rb +45 -3
  71. data/split.gemspec +9 -9
  72. metadata +38 -29
  73. data/.travis.yml +0 -53
data/.rubocop_todo.yml ADDED
@@ -0,0 +1,226 @@
1
+ # This configuration was generated by
2
+ # `rubocop --auto-gen-config`
3
+ # on 2020-07-05 01:43:26 UTC using RuboCop version 0.86.0.
4
+ # The point is for the user to remove these configuration records
5
+ # one by one as the offenses are removed from the code base.
6
+ # Note that changes in the inspected code, or installation of new
7
+ # versions of RuboCop, may require this file to be generated again.
8
+
9
+ # Offense count: 1
10
+ # Cop supports --auto-correct.
11
+ Layout/CommentIndentation:
12
+ Exclude:
13
+ - 'lib/split/experiment.rb'
14
+
15
+ # Offense count: 1
16
+ # Cop supports --auto-correct.
17
+ Layout/ElseAlignment:
18
+ Exclude:
19
+ - 'lib/split/experiment.rb'
20
+
21
+ # Offense count: 14
22
+ # Cop supports --auto-correct.
23
+ # Configuration parameters: EnforcedStyle.
24
+ # SupportedStyles: around, only_before
25
+ Layout/EmptyLinesAroundAccessModifier:
26
+ Exclude:
27
+ - 'lib/split/algorithms/block_randomization.rb'
28
+ - 'lib/split/algorithms/whiplash.rb'
29
+ - 'lib/split/alternative.rb'
30
+ - 'lib/split/configuration.rb'
31
+ - 'lib/split/dashboard/pagination_helpers.rb'
32
+ - 'lib/split/encapsulated_helper.rb'
33
+ - 'lib/split/experiment.rb'
34
+ - 'lib/split/goals_collection.rb'
35
+ - 'lib/split/persistence/cookie_adapter.rb'
36
+ - 'lib/split/persistence/dual_adapter.rb'
37
+ - 'lib/split/redis_interface.rb'
38
+ - 'lib/split/trial.rb'
39
+ - 'lib/split/user.rb'
40
+
41
+ # Offense count: 8
42
+ # Cop supports --auto-correct.
43
+ # Configuration parameters: EnforcedStyle.
44
+ # SupportedStyles: empty_lines, empty_lines_except_namespace, empty_lines_special, no_empty_lines, beginning_only, ending_only
45
+ Layout/EmptyLinesAroundClassBody:
46
+ Exclude:
47
+ - 'lib/split/experiment_catalog.rb'
48
+ - 'lib/split/goals_collection.rb'
49
+ - 'lib/split/metric.rb'
50
+ - 'lib/split/persistence/cookie_adapter.rb'
51
+ - 'lib/split/persistence/redis_adapter.rb'
52
+ - 'lib/split/persistence/session_adapter.rb'
53
+ - 'lib/split/zscore.rb'
54
+
55
+ # Offense count: 2
56
+ # Cop supports --auto-correct.
57
+ Layout/EmptyLinesAroundMethodBody:
58
+ Exclude:
59
+ - 'lib/split/dashboard/helpers.rb'
60
+ - 'lib/split/zscore.rb'
61
+
62
+ # Offense count: 1
63
+ # Cop supports --auto-correct.
64
+ # Configuration parameters: EnforcedStyle.
65
+ # SupportedStyles: empty_lines, empty_lines_except_namespace, empty_lines_special, no_empty_lines
66
+ Layout/EmptyLinesAroundModuleBody:
67
+ Exclude:
68
+ - 'lib/split/encapsulated_helper.rb'
69
+
70
+ # Offense count: 4
71
+ # Cop supports --auto-correct.
72
+ # Configuration parameters: EnforcedStyleAlignWith, AutoCorrect, Severity.
73
+ # SupportedStylesAlignWith: keyword, variable, start_of_line
74
+ Layout/EndAlignment:
75
+ Exclude:
76
+ - 'lib/split/configuration.rb'
77
+ - 'lib/split/experiment.rb'
78
+ - 'lib/split/trial.rb'
79
+
80
+ # Offense count: 17
81
+ # Cop supports --auto-correct.
82
+ # Configuration parameters: Width, IgnoredPatterns.
83
+ Layout/IndentationWidth:
84
+ Exclude:
85
+ - 'lib/split/algorithms/block_randomization.rb'
86
+ - 'lib/split/algorithms/whiplash.rb'
87
+ - 'lib/split/alternative.rb'
88
+ - 'lib/split/configuration.rb'
89
+ - 'lib/split/dashboard/pagination_helpers.rb'
90
+ - 'lib/split/encapsulated_helper.rb'
91
+ - 'lib/split/experiment.rb'
92
+ - 'lib/split/goals_collection.rb'
93
+ - 'lib/split/persistence/cookie_adapter.rb'
94
+ - 'lib/split/persistence/dual_adapter.rb'
95
+ - 'lib/split/redis_interface.rb'
96
+ - 'lib/split/trial.rb'
97
+ - 'lib/split/user.rb'
98
+
99
+ # Offense count: 4
100
+ # Cop supports --auto-correct.
101
+ # Configuration parameters: EnforcedStyle.
102
+ # SupportedStyles: space, no_space
103
+ Layout/SpaceAroundEqualsInParameterDefault:
104
+ Exclude:
105
+ - 'lib/split/goals_collection.rb'
106
+ - 'lib/split/persistence/dual_adapter.rb'
107
+ - 'lib/split/persistence/redis_adapter.rb'
108
+ - 'lib/split/user.rb'
109
+
110
+ # Offense count: 15
111
+ # Cop supports --auto-correct.
112
+ # Configuration parameters: EnforcedStyle, EnforcedStyleForEmptyBraces.
113
+ # SupportedStyles: space, no_space
114
+ # SupportedStylesForEmptyBraces: space, no_space
115
+ Layout/SpaceBeforeBlockBraces:
116
+ Exclude:
117
+ - 'lib/split/configuration.rb'
118
+ - 'lib/split/experiment.rb'
119
+ - 'lib/split/experiment_catalog.rb'
120
+ - 'lib/split/helper.rb'
121
+ - 'lib/split/trial.rb'
122
+
123
+ # Offense count: 35
124
+ # Cop supports --auto-correct.
125
+ # Configuration parameters: EnforcedStyle, EnforcedStyleForEmptyBraces, SpaceBeforeBlockParameters.
126
+ # SupportedStyles: space, no_space
127
+ # SupportedStylesForEmptyBraces: space, no_space
128
+ Layout/SpaceInsideBlockBraces:
129
+ Exclude:
130
+ - 'lib/split.rb'
131
+ - 'lib/split/configuration.rb'
132
+ - 'lib/split/experiment.rb'
133
+ - 'lib/split/experiment_catalog.rb'
134
+ - 'lib/split/helper.rb'
135
+ - 'lib/split/trial.rb'
136
+ - 'lib/split/user.rb'
137
+
138
+ # Offense count: 10
139
+ # Cop supports --auto-correct.
140
+ # Configuration parameters: EnforcedStyle, EnforcedStyleForEmptyBraces.
141
+ # SupportedStyles: space, no_space, compact
142
+ # SupportedStylesForEmptyBraces: space, no_space
143
+ Layout/SpaceInsideHashLiteralBraces:
144
+ Exclude:
145
+ - 'lib/split/experiment.rb'
146
+ - 'lib/split/helper.rb'
147
+ - 'lib/split/persistence/redis_adapter.rb'
148
+
149
+ # Offense count: 1
150
+ # Cop supports --auto-correct.
151
+ # Configuration parameters: EnforcedStyle.
152
+ # SupportedStyles: final_newline, final_blank_line
153
+ Layout/TrailingEmptyLines:
154
+ Exclude:
155
+ - 'Rakefile'
156
+
157
+ # Offense count: 3
158
+ # Cop supports --auto-correct.
159
+ # Configuration parameters: AllowInHeredoc.
160
+ Layout/TrailingWhitespace:
161
+ Exclude:
162
+ - 'lib/split/helper.rb'
163
+
164
+ # Offense count: 1
165
+ Lint/UselessAssignment:
166
+ Exclude:
167
+ - 'lib/split/goals_collection.rb'
168
+
169
+ # Offense count: 1
170
+ # Cop supports --auto-correct.
171
+ # Configuration parameters: EnforcedStyle.
172
+ # SupportedStyles: always, conditionals
173
+ Style/AndOr:
174
+ Exclude:
175
+ - 'lib/split/experiment_catalog.rb'
176
+
177
+ # Offense count: 1
178
+ # Cop supports --auto-correct.
179
+ Style/ColonMethodCall:
180
+ Exclude:
181
+ - 'lib/split/combined_experiments_helper.rb'
182
+
183
+ # Offense count: 1
184
+ # Cop supports --auto-correct.
185
+ Style/DefWithParentheses:
186
+ Exclude:
187
+ - 'lib/split/helper.rb'
188
+
189
+ # Offense count: 23
190
+ # Cop supports --auto-correct.
191
+ # Configuration parameters: EnforcedStyle, UseHashRocketsWithSymbolValues, PreferHashRocketsForNonAlnumEndingSymbols.
192
+ # SupportedStyles: ruby19, hash_rockets, no_mixed_keys, ruby19_no_mixed_keys
193
+ Style/HashSyntax:
194
+ Exclude:
195
+ - 'Rakefile'
196
+ - 'lib/split/experiment.rb'
197
+ - 'lib/split/experiment_catalog.rb'
198
+ - 'lib/split/helper.rb'
199
+ - 'lib/split/metric.rb'
200
+ - 'lib/split/persistence.rb'
201
+ - 'lib/split/persistence/redis_adapter.rb'
202
+
203
+ # Offense count: 1
204
+ # Cop supports --auto-correct.
205
+ # Configuration parameters: EnforcedStyle.
206
+ # SupportedStyles: require_parentheses, require_no_parentheses, require_no_parentheses_except_multiline
207
+ Style/MethodDefParentheses:
208
+ Exclude:
209
+ - 'lib/split/configuration.rb'
210
+
211
+ # Offense count: 9
212
+ # Cop supports --auto-correct.
213
+ # Configuration parameters: AllowMultipleReturnValues.
214
+ Style/RedundantReturn:
215
+ Exclude:
216
+ - 'lib/split/alternative.rb'
217
+ - 'lib/split/experiment.rb'
218
+ - 'lib/split/helper.rb'
219
+ - 'lib/split/zscore.rb'
220
+
221
+ # Offense count: 258
222
+ # Cop supports --auto-correct.
223
+ # Configuration parameters: EnforcedStyle, ConsistentQuotesInMultiline.
224
+ # SupportedStyles: single_quotes, double_quotes
225
+ Style/StringLiterals:
226
+ Enabled: false
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,3 +1,119 @@
1
+ ## 4.0.1 (December 30th, 2021)
2
+
3
+ Bugfixes:
4
+ - ab_test must return metadata on error or if split is disabled/excluded user (@andrehjr, #622)
5
+ - Fix versioned experiments when used with allow_multiple_experiments=control (@andrehjr, #613)
6
+ - Only block Pinterest bot (@huoxito, #606)
7
+ - Respect experiment defaults when loading experiments in initializer. (@mattwd7, #599)
8
+ - Removes metadata key when it updated to nil (@andrehjr, #633)
9
+ - Force experiment does not count for metrics (@andrehjr, #637)
10
+ - Fix cleanup_old_versions! misbehaviour (@serggl, #661)
11
+
12
+ Features:
13
+ - Make goals accessible via on_trial_complete callbacks (@robin-phung, #625)
14
+ - Replace usage of SimpleRandom with RubyStats(Used for Beta Distribution RNG) (@andrehjr, #616)
15
+ - Introduce enable/disable experiment cohorting (@robin-phung, #615)
16
+ - Add on_experiment_winner_choose callback (@GenaMinenkov, #574)
17
+ - Add Split::Cache to reduce load on Redis (@rdh, #648)
18
+ - Caching based optimization in the experiment#save path (@amangup, #652)
19
+ - Adds config option for cookie domain (@joedelia, #664)
20
+
21
+ Misc:
22
+ - Drop support for Ruby < 2.5 (@andrehjr, #627)
23
+ - Drop support for Rails < 5 (@andrehjr, #607)
24
+ - Bump minimum required redis to 4.2 (@andrehjr, #628)
25
+ - Removed repeated loading from config (@robin-phung, #619)
26
+ - Simplify RedisInterface usage when persisting Experiment alternatives (@andrehjr, #632)
27
+ - Remove redis_url impl. Deprecated on version 2.2 (@andrehjr, #631)
28
+ - Remove thread_safe config as redis-rb is thread_safe by default (@andrehjr, #630)
29
+ - Fix typo of in `Split::Trial` class variable (TomasBarry, #644)
30
+ - Single HSET to update values, instead of multiple ones (@andrehjr, #640)
31
+ - Use Redis#hmset to keep compatibility with Redis < 4.0 (@andrehjr, #659)
32
+ - Remove 'set' parsing for alternatives. Sets were used as storage and deprecated on 0.x (@andrehjr, #639)
33
+ - Adding documentation related to what is stored on cookies. (@andrehjr, #634)
34
+ - Keep railtie defined under the Split gem namespace (@avit, #666)
35
+ - Update RSpec helper to support block syntax (@clowder, #665)
36
+
37
+ ## 3.4.1 (November 12th, 2019)
38
+
39
+ Bugfixes:
40
+ - Reference ActionController directly when including split helpers, to avoid breaking Rails API Controllers (@andrehjr, #602)
41
+
42
+ ## 3.4.0 (November 9th, 2019)
43
+
44
+ Features:
45
+ - 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.
46
+ - Make dashboard pagination default "per" param configurable (@alopatin, #597)
47
+
48
+ Bugfixes:
49
+ - Fix `force_alternative` for experiments with incremented version (@giraffate, #568)
50
+ - Persist alternative weights (@giraffate, #570)
51
+ - Combined experiment performance improvements (@gnanou, #575)
52
+ - Handle correctly case when ab_finished is called before ab_test for a user (@gnanou, #577)
53
+ - When loading active_experiments, it should not look into user's 'finished' keys (@andrehjr, #582)
54
+
55
+ Misc:
56
+ - Remove `rubyforge_project` from gemspec (@giraffate, #583)
57
+ - Fix URLs to replace http with https (@giraffate , #584)
58
+ - Lazily include split helpers in ActionController::Base (@hasghari, #586)
59
+ - Fix unused variable warnings (@andrehjr, #592)
60
+ - Fix ruby warnings (@andrehjr, #593)
61
+ - Update rubocop.yml config (@andrehjr, #594)
62
+ - Add frozen_string_literal to all files that were missing it (@andrehjr, #595)
63
+
64
+ ## 3.3.2 (April 12th, 2019)
65
+
66
+ Features:
67
+ - Added uptime robot to configuration.rb (@razel1982, #556)
68
+ - Check to see if being run in Rails application and run in before_initialize (@husteadrobert, #555)
69
+
70
+ Bugfixes:
71
+ - Fix error message interpolation (@hanibash, #553)
72
+ - Fix Bigdecimal warnings (@agraves, #551)
73
+ - Avoid hitting up on redis for robots/excluded users. (@andrehjr, #544)
74
+ - Checks for defined?(request) on Helper#exclude_visitor?. (@andrehjr)
75
+
76
+ Misc:
77
+ - Update travis to add Rails 6 (@edmilton, #559)
78
+ - Fix broken specs in developement environment (@dougpetronilio, #557)
79
+
80
+ ## 3.3.1 (January 11th, 2019)
81
+
82
+ Features:
83
+ - Filter some more bots (@janosch-x, #542)
84
+
85
+ Bugfixes:
86
+ - Fix Dashboard Pagination Helper typo (@cattekin, #541)
87
+ - Do not storage alternative in cookie if experiment has a winner (@sadhu89, #539)
88
+ - fix user participating alternative not found (@NaturalHokke, #536)
89
+
90
+ Misc:
91
+ - Tweak RSpec instructions (@eliotsykes, #540)
92
+ - Improve README regarding rspec usage (@vermaxik, #538)
93
+
94
+ ## 3.3.0 (August 13th, 2018)
95
+
96
+ Features:
97
+
98
+ - Added pagination for dashboard (@GeorgeGorbanev, #518)
99
+ - Add Facebot crawler to list of bots (@pfeiffer, #530)
100
+ - Ignore previewing requests (@pfeiffer, #531)
101
+ - Fix binding of ignore_filter (@pfeiffer, #533)
102
+
103
+ Bugfixes:
104
+
105
+ - Fix cookie header duplication (@andrehjr, #522)
106
+
107
+ Performance:
108
+
109
+ - Improve performance of RedisInterface#make_list_length by using LTRIM command (@mlovic, #509)
110
+
111
+ Misc:
112
+
113
+ - Update development dependencies
114
+ - test rails 5.2 on travis (@lostapathy, #524)
115
+ - update ruby versions for travis (@lostapathy, #525)
116
+
1
117
  ## 3.2.0 (September 21st, 2017)
2
118
 
3
119
  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,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  source "https://rubygems.org"
2
4
 
3
5
  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://github.com/splitrb/split/actions/workflows/ci.yml/badge.svg?branch=main)
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
 
@@ -159,15 +159,15 @@ In the event you want to disable all tests without having to know the individual
159
159
 
160
160
  It is not required to send `SPLIT_DISABLE=false` to activate Split.
161
161
 
162
- To aid testing with RSpec, write `split_helper.rb` and call `use_ab_test(alternatives_by_experiment)` in your specs as instructed below:
162
+
163
+ ### Rspec Helper
164
+ To aid testing with RSpec, write `spec/support/split_helper.rb` and call `use_ab_test(alternatives_by_experiment)` in your specs as instructed below:
163
165
 
164
166
  ```ruby
165
- # Recommended path for this file is 'spec/support/split_helper.rb', and you will need to ensure it
166
- # is `require`-d by rails_helper.rb or spec_helper.rb
167
+ # Create a file with these contents at 'spec/support/split_helper.rb'
168
+ # and ensure it is `require`d in your rails_helper.rb or spec_helper.rb
167
169
  module SplitHelper
168
170
 
169
- # Usage:
170
- #
171
171
  # Force a specific experiment alternative to always be returned:
172
172
  # use_ab_test(signup_form: "single_page")
173
173
  #
@@ -175,19 +175,29 @@ module SplitHelper
175
175
  # use_ab_test(signup_form: "single_page", pricing: "show_enterprise_prices")
176
176
  #
177
177
  def use_ab_test(alternatives_by_experiment)
178
- allow_any_instance_of(Split::Helper).to receive(:ab_test) do |_receiver, experiment|
179
- alternative =
180
- alternatives_by_experiment.fetch(experiment) { |key| raise "Unknown experiment '#{key}'" }
178
+ allow_any_instance_of(Split::Helper).to receive(:ab_test) do |_receiver, experiment, &block|
179
+ variant = alternatives_by_experiment.fetch(experiment) { |key| raise "Unknown experiment '#{key}'" }
180
+ block.call(variant) unless block.nil?
181
+ variant
181
182
  end
182
183
  end
183
184
  end
184
185
 
186
+ # Make the `use_ab_test` method available to all specs:
185
187
  RSpec.configure do |config|
186
- # Make the `use_ab_test` method available to all specs:
187
188
  config.include SplitHelper
188
189
  end
189
190
  ```
190
191
 
192
+ Now you can call `use_ab_test(alternatives_by_experiment)` in your specs, for example:
193
+ ```ruby
194
+ it "registers using experimental signup" do
195
+ use_ab_test experiment_name: "alternative_name"
196
+ post "/signups"
197
+ ...
198
+ end
199
+ ```
200
+
191
201
 
192
202
  ### Starting experiments manually
193
203
 
@@ -210,6 +220,12 @@ The user will then always see the alternative they started with.
210
220
 
211
221
  Any old unfinished experiment key will be deleted from the user's data storage if the experiment had been removed or is over and a winner had been chosen. This allows a user to enroll into any new experiment in cases when the `allow_multiple_experiments` config option is set to `false`.
212
222
 
223
+ ### Reset experiments manually
224
+
225
+ By default Split automatically resets the experiment whenever it detects the configuration for an experiment has changed (e.g. you call `ab_test` with different alternatives). You can prevent this by setting the option `reset_manually` to `true`.
226
+
227
+ You may want to do this when you want to change something, like the variants' names, the metadata about an experiment, etc. without resetting everything.
228
+
213
229
  ### Multiple experiments at once
214
230
 
215
231
  By default Split will avoid users participating in multiple experiments at once. This means you are less likely to skew results by adding in more variation to your tests.
@@ -249,7 +265,7 @@ Split.configure do |config|
249
265
  end
250
266
  ```
251
267
 
252
- By default, cookies will expire in 1 year. To change that, set the `persistence_cookie_length` in the configuration (unit of time in seconds).
268
+ When using the cookie persistence, Split stores data into an anonymous tracking cookie named 'split', which expires in 1 year. To change that, set the `persistence_cookie_length` in the configuration (unit of time in seconds).
253
269
 
254
270
  ```ruby
255
271
  Split.configure do |config|
@@ -258,6 +274,8 @@ Split.configure do |config|
258
274
  end
259
275
  ```
260
276
 
277
+ The data stored consists of the experiment name and the variants the user is in. Example: { "experiment_name" => "variant_a" }
278
+
261
279
  __Note:__ Using cookies depends on `ActionDispatch::Cookies` or any identical API
262
280
 
263
281
  #### Redis
@@ -346,7 +364,7 @@ end
346
364
 
347
365
  If you are running `ab_test` from a view, you must define your event
348
366
  hook callback as a
349
- [helper_method](http://apidock.com/rails/AbstractController/Helpers/ClassMethods/helper_method)
367
+ [helper_method](https://apidock.com/rails/AbstractController/Helpers/ClassMethods/helper_method)
350
368
  in the controller:
351
369
 
352
370
  ``` ruby
@@ -372,6 +390,8 @@ Split.configure do |config|
372
390
  # before experiment reset or deleted
373
391
  config.on_before_experiment_reset = -> (example) { # Do something on reset }
374
392
  config.on_before_experiment_delete = -> (experiment) { # Do something else on delete }
393
+ # after experiment winner had been set
394
+ config.on_experiment_winner_choose = -> (experiment) { # Do something on winner choose }
375
395
  end
376
396
  ```
377
397
 
@@ -432,7 +452,7 @@ match "/split" => Split::Dashboard, anchor: false, via: [:get, :post, :delete],
432
452
  end
433
453
  ```
434
454
 
435
- 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/)
455
+ 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/)
436
456
 
437
457
  ### Screenshot
438
458
 
@@ -450,6 +470,7 @@ Split.configure do |config|
450
470
  config.enabled = true
451
471
  config.persistence = Split::Persistence::SessionAdapter
452
472
  #config.start_manually = false ## new test will have to be started manually from the admin panel. default false
473
+ #config.reset_manually = false ## if true, it never resets the experiment data, even if the configuration changes
453
474
  config.include_rails_helper = true
454
475
  config.redis = "redis://custom.redis.url:6380"
455
476
  end
@@ -541,7 +562,7 @@ and:
541
562
  ab_finished(:my_first_experiment)
542
563
  ```
543
564
 
544
- You can also add meta data for each experiment, very useful when you need more than an alternative name to change behaviour:
565
+ You can also add meta data for each experiment, which is very useful when you need more than an alternative name to change behaviour:
545
566
 
546
567
  ```ruby
547
568
  Split.configure do |config|
@@ -586,6 +607,8 @@ or in views:
586
607
  <% end %>
587
608
  ```
588
609
 
610
+ The keys used in meta data should be Strings
611
+
589
612
  #### Metrics
590
613
 
591
614
  You might wish to track generic metrics, such as conversions, and use
@@ -627,7 +650,7 @@ The API to define goals for an experiment is this:
627
650
  ab_test({link_color: ["purchase", "refund"]}, "red", "blue")
628
651
  ```
629
652
 
630
- or you can you can define them in a configuration file:
653
+ or you can define them in a configuration file:
631
654
 
632
655
  ```ruby
633
656
  Split.configure do |config|
@@ -735,6 +758,20 @@ split_config = YAML.load_file(Rails.root.join('config', 'split.yml'))
735
758
  Split.redis = split_config[Rails.env]
736
759
  ```
737
760
 
761
+ ### Redis Caching (v4.0+)
762
+
763
+ In some high-volume usage scenarios, Redis load can be incurred by repeated
764
+ fetches for fairly static data. Enabling caching will reduce this load.
765
+
766
+ ```ruby
767
+ Split.configuration.cache = true
768
+ ````
769
+
770
+ This currently caches:
771
+ - `Split::ExperimentCatalog.find`
772
+ - `Split::Experiment.start_time`
773
+ - `Split::Experiment.winner`
774
+
738
775
  ## Namespaces
739
776
 
740
777
  If you're running multiple, separate instances of Split you may want
@@ -751,7 +788,7 @@ library. To configure Split to use `Redis::Namespace`, do the following:
751
788
  ```
752
789
 
753
790
  2. Configure `Split.redis` to use a `Redis::Namespace` instance (possible in an
754
- intializer):
791
+ initializer):
755
792
 
756
793
  ```ruby
757
794
  redis = Redis.new(url: ENV['REDIS_URL']) # or whatever config you want
@@ -809,8 +846,8 @@ end
809
846
 
810
847
  ## Extensions
811
848
 
812
- - [Split::Export](http://github.com/splitrb/split-export) - Easily export A/B test data out of Split.
813
- - [Split::Analytics](http://github.com/splitrb/split-analytics) - Push test data to Google Analytics.
849
+ - [Split::Export](https://github.com/splitrb/split-export) - Easily export A/B test data out of Split.
850
+ - [Split::Analytics](https://github.com/splitrb/split-analytics) - Push test data to Google Analytics.
814
851
  - [Split::Mongoid](https://github.com/MongoHQ/split-mongoid) - Store experiment data in mongoid (still uses redis).
815
852
  - [Split::Cacheable](https://github.com/harrystech/split_cacheable) - Automatically create cache buckets per test.
816
853
  - [Split::Counters](https://github.com/bernardkroes/split-counters) - Add counters per experiment and alternative.
@@ -822,7 +859,7 @@ Ryan bates has produced an excellent 10 minute screencast about split on the Rai
822
859
 
823
860
  ## Blogposts
824
861
 
825
- * [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)
862
+ * [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)
826
863
  * [Rails A/B testing with Split on Heroku](http://blog.nathanhumbert.com/2012/02/rails-ab-testing-with-split-on-heroku.html)
827
864
 
828
865
  ## Backers
@@ -902,9 +939,9 @@ Please do! Over 70 different people have contributed to the project, you can see
902
939
 
903
940
  ### Development
904
941
 
905
- The source code is hosted at [GitHub](http://github.com/splitrb/split).
942
+ The source code is hosted at [GitHub](https://github.com/splitrb/split).
906
943
 
907
- Report issues and feature requests on [GitHub Issues](http://github.com/splitrb/split/issues).
944
+ Report issues and feature requests on [GitHub Issues](https://github.com/splitrb/split/issues).
908
945
 
909
946
  You can find a discussion form on [Google Groups](https://groups.google.com/d/forum/split-ruby).
910
947
 
@@ -935,4 +972,4 @@ Please note that this project is released with a [Contributor Code of Conduct](C
935
972
 
936
973
  ## Copyright
937
974
 
938
- [MIT License](LICENSE) © 2018 [Andrew Nesbitt](https://github.com/andrew).
975
+ [MIT License](LICENSE) © 2019 [Andrew Nesbitt](https://github.com/andrew).
data/Rakefile CHANGED
@@ -1,4 +1,6 @@
1
1
  #!/usr/bin/env rake
2
+ # frozen_string_literal: true
3
+
2
4
  require 'bundler/gem_tasks'
3
5
  require 'rspec/core/rake_task'
4
6
  require 'appraisal'
@@ -4,6 +4,6 @@ source "https://rubygems.org"
4
4
 
5
5
  gem "appraisal"
6
6
  gem "codeclimate-test-reporter"
7
- gem "rails", "~> 4.2"
7
+ gem "rails", "~> 6.0"
8
8
 
9
9
  gemspec path: "../"
@@ -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.1"
8
+
9
+ gemspec path: "../"
@@ -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", "~> 7.0"
8
+
9
+ gemspec path: "../"
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # Selects alternative with minimum count of participants
2
4
  # If all counts are even (i.e. all are minimum), samples from all possible alternatives
3
5
 
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  module Split
3
4
  module Algorithms
4
5
  module WeightedSample
@@ -8,7 +9,7 @@ module Split
8
9
  total = weights.inject(:+)
9
10
  point = rand * total
10
11
 
11
- experiment.alternatives.zip(weights).each do |n,w|
12
+ experiment.alternatives.zip(weights).each do |n, w|
12
13
  return n if w >= point
13
14
  point -= w
14
15
  end