split 4.0.1 → 4.0.2

Sign up to get free protection for your applications and to get access to all the features.
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
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c6b66f4b21c4201228d9622d5e00ff2a2e957714edfce11316316a2ca3e405ce
4
- data.tar.gz: 6a441cf39a14ef9e36b805e7728f34029db7f7d1e1e90f3389168942b7b77f60
3
+ metadata.gz: f1c97063d4d1ccf4c2cd5dfd2e83b98b3f55a934b9dfa9b5862ede3ee5b8c58c
4
+ data.tar.gz: 28e30003a6d2059baf91482f5ac9a97b0b7d2e37c61a425710cbf1adf21a4a83
5
5
  SHA512:
6
- metadata.gz: bc46df4b6f301b8bdaf99ba4648f7363ad2c1234b3be7586e078b9772fec9a2bae3c9e15335c0c207e88c45113a1348a0dcd608a9dcfee654846753ba59c6696
7
- data.tar.gz: 53dffc60d0f0617f1a1e943170f7702eff6ec5d00381b9d3b19380ef50aaef4c76956974a94a645bfb288eddd75486f24c2c2d3c56e7465f85f68791f1aeda31
6
+ metadata.gz: 988f115f0f96870188221552cca45f6a7207f548500dbf2a5446abaa47ac7365571644a5a231443ca7616182b68c3139f8d62fdcf18d1593fca8898092a332e2
7
+ data.tar.gz: b6a668159d8b6fe9529bae5bc650f120b9de1bdf593bc89d0d949a2e07e8cfda7c96b4c12e5e4615696cf31b845215f95ce60b4abcb9ff3d7ef056669a4ae51d
@@ -34,8 +34,8 @@ jobs:
34
34
  - gemfile: 7.0.gemfile
35
35
  ruby: '3.0'
36
36
 
37
- # - gemfile: 7.0.gemfile
38
- # ruby: '3.1'
37
+ - gemfile: 7.0.gemfile
38
+ ruby: '3.1'
39
39
 
40
40
 
41
41
  runs-on: ubuntu-latest
@@ -51,7 +51,7 @@ jobs:
51
51
  --health-retries 5
52
52
 
53
53
  steps:
54
- - uses: actions/checkout@v2
54
+ - uses: actions/checkout@v3
55
55
 
56
56
  - uses: ruby/setup-ruby@v1
57
57
  with:
@@ -69,3 +69,6 @@ jobs:
69
69
  run: bundle exec rspec
70
70
  env:
71
71
  REDIS_URL: redis:6379
72
+
73
+ - name: Rubocop
74
+ run: bundle exec rubocop
data/.rubocop.yml CHANGED
@@ -1,12 +1,9 @@
1
- inherit_from: .rubocop_todo.yml
2
-
3
1
  AllCops:
4
2
  TargetRubyVersion: 2.5
5
3
  DisabledByDefault: true
4
+ SuggestExtensions: false
6
5
  Exclude:
7
- - 'Appraisals'
8
6
  - 'gemfiles/**/*'
9
- - 'spec/**/*.rb'
10
7
 
11
8
  Style/AndOr:
12
9
  Enabled: true
@@ -114,7 +111,7 @@ Layout/SpaceInsideParens:
114
111
  Enabled: true
115
112
 
116
113
  Style/StringLiterals:
117
- Enabled: false
114
+ Enabled: true
118
115
  EnforcedStyle: double_quotes
119
116
 
120
117
  Layout/IndentationStyle:
data/CHANGELOG.md CHANGED
@@ -1,3 +1,26 @@
1
+ # 4.0.2 (December 2nd, 2022)
2
+
3
+ Bugfixes:
4
+ - Stop crashing on non-hash json (@knarewski, #697)
5
+ - Handle when Rails is partially loaded as a Gem (@TSMMark, #687)
6
+
7
+ Features:
8
+ - Add support for redis-client, which does not automatically cast types to strings (@knarewski, #696)
9
+ - Add ability to initialize experiments (@robin-phung, #673)
10
+
11
+ Misc:
12
+ - Fix default branch name and gem metadata indentation (@ursm, #693)
13
+ - Update actions/checkout to v3 (@andrehjr, #683)
14
+ - Enforce double quotes (@andrehjr, #682)
15
+ - Fix Rubocop Style/* Offenses (@andrehjr, #681)
16
+ - Enable rubocop on Github Actions (@andrehjr, #680)
17
+ - Fix all Layout issues on the project (@andrehjr, #679)
18
+ - Fix Style/HashSyntax offenses (@andrehjr, #678)
19
+ - Remove usage of deprecated implicit block expectation from specs (@andrehjr, #677)
20
+ - Remove appraisals configuration (@andrehjr, #676)
21
+ - Add Ruby 3.1 (@andrehjr, #675)
22
+ - Encapsulate Split::Algorithms at our own module to avoid explicit calling rubystats everywhere (@andrehjr, #674)
23
+
1
24
  ## 4.0.1 (December 30th, 2021)
2
25
 
3
26
  Bugfixes:
data/CONTRIBUTING.md CHANGED
@@ -25,7 +25,7 @@ Want to contribute to Split? That's great! Here are a couple of guidelines that
25
25
 
26
26
  ## Setup instructions
27
27
 
28
- You can find in-depth instructions to install in our [README](https://github.com/splitrb/split/blob/master/README.md).
28
+ You can find in-depth instructions to install in our [README](https://github.com/splitrb/split/blob/main/README.md).
29
29
 
30
30
  *Note*: Split requires Ruby 1.9.2 or higher.
31
31
 
data/Gemfile CHANGED
@@ -4,5 +4,6 @@ source "https://rubygems.org"
4
4
 
5
5
  gemspec
6
6
 
7
- gem "appraisal"
7
+ gem "rubocop", require: false
8
+ gem "matrix"
8
9
  gem "codeclimate-test-reporter"
data/README.md CHANGED
@@ -19,11 +19,13 @@ Split is designed to be hacker friendly, allowing for maximum customisation and
19
19
 
20
20
  ### Requirements
21
21
 
22
- Split currently requires Ruby 1.9.3 or higher. If your project requires compatibility with Ruby 1.8.x and Rails 2.3, please use v0.8.0.
22
+ Split v4.0+ is currently tested with Ruby >= 2.5 and Rails >= 5.2.
23
+
24
+ If your project requires compatibility with Ruby 2.4.x or older Rails versions. You can try v3.0 or v0.8.0(for Ruby 1.9.3)
23
25
 
24
26
  Split uses Redis as a datastore.
25
27
 
26
- Split only supports Redis 2.0 or greater.
28
+ Split only supports Redis 4.0 or greater.
27
29
 
28
30
  If you're on OS X, Homebrew is the simplest way to install Redis:
29
31
 
data/Rakefile CHANGED
@@ -1,10 +1,9 @@
1
1
  #!/usr/bin/env rake
2
2
  # frozen_string_literal: true
3
3
 
4
- require 'bundler/gem_tasks'
5
- require 'rspec/core/rake_task'
6
- require 'appraisal'
4
+ require "bundler/gem_tasks"
5
+ require "rspec/core/rake_task"
7
6
 
8
- RSpec::Core::RakeTask.new('spec')
7
+ RSpec::Core::RakeTask.new("spec")
9
8
 
10
- task :default => :spec
9
+ task default: :spec
data/gemfiles/5.2.gemfile CHANGED
@@ -1,8 +1,6 @@
1
- # This file was generated by Appraisal
2
-
3
1
  source "https://rubygems.org"
4
2
 
5
- gem "appraisal"
3
+ gem "rubocop", require: false
6
4
  gem "codeclimate-test-reporter"
7
5
  gem "rails", "~> 5.2"
8
6
 
data/gemfiles/6.0.gemfile CHANGED
@@ -1,8 +1,6 @@
1
- # This file was generated by Appraisal
2
-
3
1
  source "https://rubygems.org"
4
2
 
5
- gem "appraisal"
3
+ gem "rubocop", require: false
6
4
  gem "codeclimate-test-reporter"
7
5
  gem "rails", "~> 6.0"
8
6
 
data/gemfiles/6.1.gemfile CHANGED
@@ -1,8 +1,6 @@
1
- # This file was generated by Appraisal
2
-
3
1
  source "https://rubygems.org"
4
2
 
5
- gem "appraisal"
3
+ gem "rubocop", require: false
6
4
  gem "codeclimate-test-reporter"
7
5
  gem "rails", "~> 6.1"
8
6
 
data/gemfiles/7.0.gemfile CHANGED
@@ -1,9 +1,8 @@
1
- # This file was generated by Appraisal
2
-
3
1
  source "https://rubygems.org"
4
2
 
5
- gem "appraisal"
3
+ gem "rubocop", require: false
6
4
  gem "codeclimate-test-reporter"
7
5
  gem "rails", "~> 7.0"
6
+ gem "matrix"
8
7
 
9
8
  gemspec path: "../"
@@ -12,12 +12,11 @@ module Split
12
12
  end
13
13
 
14
14
  private
15
-
16
- def minimum_participant_alternatives(alternatives)
17
- alternatives_by_count = alternatives.group_by(&:participant_count)
18
- min_group = alternatives_by_count.min_by { |k, v| k }
19
- min_group.last
20
- end
15
+ def minimum_participant_alternatives(alternatives)
16
+ alternatives_by_count = alternatives.group_by(&:participant_count)
17
+ min_group = alternatives_by_count.min_by { |k, v| k }
18
+ min_group.last
19
+ end
21
20
  end
22
21
  end
23
22
  end
@@ -2,7 +2,6 @@
2
2
 
3
3
  # A multi-armed bandit implementation inspired by
4
4
  # @aaronsw and victorykit/whiplash
5
- require 'rubystats'
6
5
 
7
6
  module Split
8
7
  module Algorithms
@@ -13,26 +12,25 @@ module Split
13
12
  end
14
13
 
15
14
  private
15
+ def arm_guess(participants, completions)
16
+ a = [participants, 0].max
17
+ b = [participants-completions, 0].max
18
+ Split::Algorithms.beta_distribution_rng(a + fairness_constant, b + fairness_constant)
19
+ end
16
20
 
17
- def arm_guess(participants, completions)
18
- a = [participants, 0].max
19
- b = [participants-completions, 0].max
20
- Rubystats::BetaDistribution.new(a+fairness_constant, b+fairness_constant).rng
21
- end
22
-
23
- def best_guess(alternatives)
24
- guesses = {}
25
- alternatives.each do |alternative|
26
- guesses[alternative.name] = arm_guess(alternative.participant_count, alternative.all_completed_count)
21
+ def best_guess(alternatives)
22
+ guesses = {}
23
+ alternatives.each do |alternative|
24
+ guesses[alternative.name] = arm_guess(alternative.participant_count, alternative.all_completed_count)
25
+ end
26
+ gmax = guesses.values.max
27
+ best = guesses.keys.select { |name| guesses[name] == gmax }
28
+ best.sample
27
29
  end
28
- gmax = guesses.values.max
29
- best = guesses.keys.select { |name| guesses[name] == gmax }
30
- best.sample
31
- end
32
30
 
33
- def fairness_constant
34
- 7
35
- end
31
+ def fairness_constant
32
+ 7
33
+ end
36
34
  end
37
35
  end
38
36
  end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ begin
4
+ require "matrix"
5
+ rescue LoadError => error
6
+ if error.message.match?(/matrix/)
7
+ $stderr.puts "You don't have matrix installed in your application. Please add it to your Gemfile and run bundle install"
8
+ raise
9
+ end
10
+ end
11
+
12
+ require "rubystats"
13
+
14
+ module Split
15
+ module Algorithms
16
+ class << self
17
+ def beta_distribution_rng(a, b)
18
+ Rubystats::BetaDistribution.new(a, b).rng
19
+ end
20
+ end
21
+ end
22
+ end
@@ -38,11 +38,11 @@ module Split
38
38
  end
39
39
 
40
40
  def participant_count
41
- Split.redis.hget(key, 'participant_count').to_i
41
+ Split.redis.hget(key, "participant_count").to_i
42
42
  end
43
43
 
44
44
  def participant_count=(count)
45
- Split.redis.hset(key, 'participant_count', count.to_i)
45
+ Split.redis.hset(key, "participant_count", count.to_i)
46
46
  end
47
47
 
48
48
  def completed_count(goal = nil)
@@ -67,13 +67,13 @@ module Split
67
67
  def set_field(goal)
68
68
  field = "completed_count"
69
69
  field += ":" + goal unless goal.nil?
70
- return field
70
+ field
71
71
  end
72
72
 
73
73
  def set_prob_field(goal)
74
74
  field = "p_winner"
75
75
  field += ":" + goal unless goal.nil?
76
- return field
76
+ field
77
77
  end
78
78
 
79
79
  def set_completed_count(count, goal = nil)
@@ -82,7 +82,7 @@ module Split
82
82
  end
83
83
 
84
84
  def increment_participation
85
- Split.redis.hincrby key, 'participant_count', 1
85
+ Split.redis.hincrby key, "participant_count", 1
86
86
  end
87
87
 
88
88
  def increment_completion(goal = nil)
@@ -112,7 +112,7 @@ module Split
112
112
  control = experiment.control
113
113
  alternative = self
114
114
 
115
- return 'N/A' if control.name == alternative.name
115
+ return "N/A" if control.name == alternative.name
116
116
 
117
117
  p_a = alternative.conversion_rate(goal)
118
118
  p_c = control.conversion_rate(goal)
@@ -121,13 +121,13 @@ module Split
121
121
  n_c = control.participant_count
122
122
 
123
123
  # can't calculate zscore for P(x) > 1
124
- return 'N/A' if p_a > 1 || p_c > 1
124
+ return "N/A" if p_a > 1 || p_c > 1
125
125
 
126
126
  Split::Zscore.calculate(p_a, n_a, p_c, n_c)
127
127
  end
128
128
 
129
129
  def extra_info
130
- data = Split.redis.hget(key, 'recorded_info')
130
+ data = Split.redis.hget(key, "recorded_info")
131
131
  if data && data.length > 1
132
132
  begin
133
133
  JSON.parse(data)
@@ -149,24 +149,24 @@ module Split
149
149
  @recorded_info[k] = value
150
150
  end
151
151
 
152
- Split.redis.hset key, 'recorded_info', (@recorded_info || {}).to_json
152
+ Split.redis.hset key, "recorded_info", (@recorded_info || {}).to_json
153
153
  end
154
154
 
155
155
  def save
156
- Split.redis.hsetnx key, 'participant_count', 0
157
- Split.redis.hsetnx key, 'completed_count', 0
158
- Split.redis.hsetnx key, 'p_winner', p_winner
159
- Split.redis.hsetnx key, 'recorded_info', (@recorded_info || {}).to_json
156
+ Split.redis.hsetnx key, "participant_count", 0
157
+ Split.redis.hsetnx key, "completed_count", 0
158
+ Split.redis.hsetnx key, "p_winner", p_winner
159
+ Split.redis.hsetnx key, "recorded_info", (@recorded_info || {}).to_json
160
160
  end
161
161
 
162
162
  def validate!
163
163
  unless String === @name || hash_with_correct_values?(@name)
164
- raise ArgumentError, 'Alternative must be a string'
164
+ raise ArgumentError, "Alternative must be a string"
165
165
  end
166
166
  end
167
167
 
168
168
  def reset
169
- Split.redis.hmset key, 'participant_count', 0, 'completed_count', 0, 'recorded_info', nil
169
+ Split.redis.hmset key, "participant_count", 0, "completed_count", 0, "recorded_info", ""
170
170
  unless goals.empty?
171
171
  goals.each do |g|
172
172
  field = "completed_count:#{g}"
@@ -180,13 +180,12 @@ module Split
180
180
  end
181
181
 
182
182
  private
183
+ def hash_with_correct_values?(name)
184
+ Hash === name && String === name.keys.first && Float(name.values.first) rescue false
185
+ end
183
186
 
184
- def hash_with_correct_values?(name)
185
- Hash === name && String === name.keys.first && Float(name.values.first) rescue false
186
- end
187
-
188
- def key
189
- "#{experiment_name}:#{name}"
190
- end
187
+ def key
188
+ "#{experiment_name}:#{name}"
189
+ end
191
190
  end
192
191
  end
data/lib/split/cache.rb CHANGED
@@ -2,7 +2,6 @@
2
2
 
3
3
  module Split
4
4
  class Cache
5
-
6
5
  def self.clear
7
6
  @cache = nil
8
7
  end
@@ -29,10 +29,10 @@ module Split
29
29
  end
30
30
 
31
31
  def find_combined_experiment(metric_descriptor)
32
- raise(Split::InvalidExperimentsFormatError, 'Invalid descriptor class (String or Symbol required)') unless metric_descriptor.class == String || metric_descriptor.class == Symbol
33
- raise(Split::InvalidExperimentsFormatError, 'Enable configuration') unless Split.configuration.enabled
34
- raise(Split::InvalidExperimentsFormatError, 'Enable `allow_multiple_experiments`') unless Split.configuration.allow_multiple_experiments
35
- Split::configuration.experiments[metric_descriptor.to_sym]
32
+ raise(Split::InvalidExperimentsFormatError, "Invalid descriptor class (String or Symbol required)") unless metric_descriptor.class == String || metric_descriptor.class == Symbol
33
+ raise(Split::InvalidExperimentsFormatError, "Enable configuration") unless Split.configuration.enabled
34
+ raise(Split::InvalidExperimentsFormatError, "Enable `allow_multiple_experiments`") unless Split.configuration.allow_multiple_experiments
35
+ Split.configuration.experiments[metric_descriptor.to_sym]
36
36
  end
37
37
  end
38
38
  end
@@ -39,83 +39,83 @@ module Split
39
39
  def bots
40
40
  @bots ||= {
41
41
  # Indexers
42
- 'AdsBot-Google' => 'Google Adwords',
43
- 'Baidu' => 'Chinese search engine',
44
- 'Baiduspider' => 'Chinese search engine',
45
- 'bingbot' => 'Microsoft bing bot',
46
- 'Butterfly' => 'Topsy Labs',
47
- 'Gigabot' => 'Gigabot spider',
48
- 'Googlebot' => 'Google spider',
49
- 'MJ12bot' => 'Majestic-12 spider',
50
- 'msnbot' => 'Microsoft bot',
51
- 'rogerbot' => 'SeoMoz spider',
52
- 'PaperLiBot' => 'PaperLi is another content curation service',
53
- 'Slurp' => 'Yahoo spider',
54
- 'Sogou' => 'Chinese search engine',
55
- 'spider' => 'generic web spider',
56
- 'UnwindFetchor' => 'Gnip crawler',
57
- 'WordPress' => 'WordPress spider',
58
- 'YandexAccessibilityBot' => 'Yandex accessibility spider',
59
- 'YandexBot' => 'Yandex spider',
60
- 'YandexMobileBot' => 'Yandex mobile spider',
61
- 'ZIBB' => 'ZIBB spider',
42
+ "AdsBot-Google" => "Google Adwords",
43
+ "Baidu" => "Chinese search engine",
44
+ "Baiduspider" => "Chinese search engine",
45
+ "bingbot" => "Microsoft bing bot",
46
+ "Butterfly" => "Topsy Labs",
47
+ "Gigabot" => "Gigabot spider",
48
+ "Googlebot" => "Google spider",
49
+ "MJ12bot" => "Majestic-12 spider",
50
+ "msnbot" => "Microsoft bot",
51
+ "rogerbot" => "SeoMoz spider",
52
+ "PaperLiBot" => "PaperLi is another content curation service",
53
+ "Slurp" => "Yahoo spider",
54
+ "Sogou" => "Chinese search engine",
55
+ "spider" => "generic web spider",
56
+ "UnwindFetchor" => "Gnip crawler",
57
+ "WordPress" => "WordPress spider",
58
+ "YandexAccessibilityBot" => "Yandex accessibility spider",
59
+ "YandexBot" => "Yandex spider",
60
+ "YandexMobileBot" => "Yandex mobile spider",
61
+ "ZIBB" => "ZIBB spider",
62
62
 
63
63
  # HTTP libraries
64
- 'Apache-HttpClient' => 'Java http library',
65
- 'AppEngine-Google' => 'Google App Engine',
66
- 'curl' => 'curl unix CLI http client',
67
- 'ColdFusion' => 'ColdFusion http library',
68
- 'EventMachine HttpClient' => 'Ruby http library',
69
- 'Go http package' => 'Go http library',
70
- 'Go-http-client' => 'Go http library',
71
- 'Java' => 'Generic Java http library',
72
- 'libwww-perl' => 'Perl client-server library loved by script kids',
73
- 'lwp-trivial' => 'Another Perl library loved by script kids',
74
- 'Python-urllib' => 'Python http library',
75
- 'PycURL' => 'Python http library',
76
- 'Test Certificate Info' => 'C http library?',
77
- 'Typhoeus' => 'Ruby http library',
78
- 'Wget' => 'wget unix CLI http client',
64
+ "Apache-HttpClient" => "Java http library",
65
+ "AppEngine-Google" => "Google App Engine",
66
+ "curl" => "curl unix CLI http client",
67
+ "ColdFusion" => "ColdFusion http library",
68
+ "EventMachine HttpClient" => "Ruby http library",
69
+ "Go http package" => "Go http library",
70
+ "Go-http-client" => "Go http library",
71
+ "Java" => "Generic Java http library",
72
+ "libwww-perl" => "Perl client-server library loved by script kids",
73
+ "lwp-trivial" => "Another Perl library loved by script kids",
74
+ "Python-urllib" => "Python http library",
75
+ "PycURL" => "Python http library",
76
+ "Test Certificate Info" => "C http library?",
77
+ "Typhoeus" => "Ruby http library",
78
+ "Wget" => "wget unix CLI http client",
79
79
 
80
80
  # URL expanders / previewers
81
- 'awe.sm' => 'Awe.sm URL expander',
82
- 'bitlybot' => 'bit.ly bot',
83
- 'bot@linkfluence.net' => 'Linkfluence bot',
84
- 'facebookexternalhit' => 'facebook bot',
85
- 'Facebot' => 'Facebook crawler',
86
- 'Feedfetcher-Google' => 'Google Feedfetcher',
87
- 'https://developers.google.com/+/web/snippet' => 'Google+ Snippet Fetcher',
88
- 'LinkedInBot' => 'LinkedIn bot',
89
- 'LongURL' => 'URL expander service',
90
- 'NING' => 'NING - Yet Another Twitter Swarmer',
91
- 'Pinterestbot' => 'Pinterest Bot',
92
- 'redditbot' => 'Reddit Bot',
93
- 'ShortLinkTranslate' => 'Link shortener',
94
- 'Slackbot' => 'Slackbot link expander',
95
- 'TweetmemeBot' => 'TweetMeMe Crawler',
96
- 'Twitterbot' => 'Twitter URL expander',
97
- 'UnwindFetch' => 'Gnip URL expander',
98
- 'vkShare' => 'VKontake Sharer',
81
+ "awe.sm" => "Awe.sm URL expander",
82
+ "bitlybot" => "bit.ly bot",
83
+ "bot@linkfluence.net" => "Linkfluence bot",
84
+ "facebookexternalhit" => "facebook bot",
85
+ "Facebot" => "Facebook crawler",
86
+ "Feedfetcher-Google" => "Google Feedfetcher",
87
+ "https://developers.google.com/+/web/snippet" => "Google+ Snippet Fetcher",
88
+ "LinkedInBot" => "LinkedIn bot",
89
+ "LongURL" => "URL expander service",
90
+ "NING" => "NING - Yet Another Twitter Swarmer",
91
+ "Pinterestbot" => "Pinterest Bot",
92
+ "redditbot" => "Reddit Bot",
93
+ "ShortLinkTranslate" => "Link shortener",
94
+ "Slackbot" => "Slackbot link expander",
95
+ "TweetmemeBot" => "TweetMeMe Crawler",
96
+ "Twitterbot" => "Twitter URL expander",
97
+ "UnwindFetch" => "Gnip URL expander",
98
+ "vkShare" => "VKontake Sharer",
99
99
 
100
100
  # Uptime monitoring
101
- 'check_http' => 'Nagios monitor',
102
- 'GoogleStackdriverMonitoring' => 'Google Cloud monitor',
103
- 'NewRelicPinger' => 'NewRelic monitor',
104
- 'Panopta' => 'Monitoring service',
105
- 'Pingdom' => 'Pingdom monitoring',
106
- 'SiteUptime' => 'Site monitoring services',
107
- 'UptimeRobot' => 'Monitoring service',
101
+ "check_http" => "Nagios monitor",
102
+ "GoogleStackdriverMonitoring" => "Google Cloud monitor",
103
+ "NewRelicPinger" => "NewRelic monitor",
104
+ "Panopta" => "Monitoring service",
105
+ "Pingdom" => "Pingdom monitoring",
106
+ "SiteUptime" => "Site monitoring services",
107
+ "UptimeRobot" => "Monitoring service",
108
108
 
109
109
  # ???
110
- 'DigitalPersona Fingerprint Software' => 'HP Fingerprint scanner',
111
- 'ShowyouBot' => 'Showyou iOS app spider',
112
- 'ZyBorg' => 'Zyborg? Hmmm....',
113
- 'ELB-HealthChecker' => 'ELB Health Check'
110
+ "DigitalPersona Fingerprint Software" => "HP Fingerprint scanner",
111
+ "ShowyouBot" => "Showyou iOS app spider",
112
+ "ZyBorg" => "Zyborg? Hmmm....",
113
+ "ELB-HealthChecker" => "ELB Health Check"
114
114
  }
115
115
  end
116
116
 
117
- def experiments= experiments
118
- raise InvalidExperimentsFormatError.new('Experiments must be a Hash') unless experiments.respond_to?(:keys)
117
+ def experiments=(experiments)
118
+ raise InvalidExperimentsFormatError.new("Experiments must be a Hash") unless experiments.respond_to?(:keys)
119
119
  @experiments = experiments
120
120
  end
121
121
 
@@ -157,8 +157,8 @@ module Split
157
157
 
158
158
  @experiments.each do |experiment_name, settings|
159
159
  alternatives = if (alts = value_for(settings, :alternatives))
160
- normalize_alternatives(alts)
161
- end
160
+ normalize_alternatives(alts)
161
+ end
162
162
 
163
163
  experiment_data = {
164
164
  alternatives: alternatives,
@@ -213,14 +213,14 @@ module Split
213
213
 
214
214
  def initialize
215
215
  @ignore_ip_addresses = []
216
- @ignore_filter = proc{ |request| is_robot? || is_ignored_ip_address? }
216
+ @ignore_filter = proc { |request| is_robot? || is_ignored_ip_address? }
217
217
  @db_failover = false
218
- @db_failover_on_db_error = proc{|error|} # e.g. use Rails logger here
219
- @on_experiment_reset = proc{|experiment|}
220
- @on_experiment_delete = proc{|experiment|}
221
- @on_before_experiment_reset = proc{|experiment|}
222
- @on_before_experiment_delete = proc{|experiment|}
223
- @on_experiment_winner_choose = proc{|experiment|}
218
+ @db_failover_on_db_error = proc { |error| } # e.g. use Rails logger here
219
+ @on_experiment_reset = proc { |experiment| }
220
+ @on_experiment_delete = proc { |experiment| }
221
+ @on_before_experiment_reset = proc { |experiment| }
222
+ @on_before_experiment_delete = proc { |experiment| }
223
+ @on_experiment_winner_choose = proc { |experiment| }
224
224
  @db_failover_allow_parameter_override = false
225
225
  @allow_multiple_experiments = false
226
226
  @enabled = true
@@ -232,20 +232,19 @@ module Split
232
232
  @include_rails_helper = true
233
233
  @beta_probability_simulations = 10000
234
234
  @winning_alternative_recalculation_interval = 60 * 60 * 24 # 1 day
235
- @redis = ENV.fetch(ENV.fetch('REDIS_PROVIDER', 'REDIS_URL'), 'redis://localhost:6379')
235
+ @redis = ENV.fetch(ENV.fetch("REDIS_PROVIDER", "REDIS_URL"), "redis://localhost:6379")
236
236
  @dashboard_pagination_default_per_page = 10
237
237
  end
238
238
 
239
239
  private
240
-
241
- def value_for(hash, key)
242
- if hash.kind_of?(Hash)
243
- hash.has_key?(key.to_s) ? hash[key.to_s] : hash[key.to_sym]
240
+ def value_for(hash, key)
241
+ if hash.kind_of?(Hash)
242
+ hash.has_key?(key.to_s) ? hash[key.to_s] : hash[key.to_sym]
243
+ end
244
244
  end
245
- end
246
245
 
247
- def escaped_bots
248
- bots.map { |key, _| Regexp.escape(key) }
249
- end
246
+ def escaped_bots
247
+ bots.map { |key, _| Regexp.escape(key) }
248
+ end
250
249
  end
251
250
  end