split 4.0.1 → 4.0.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (77) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ci.yml +8 -3
  3. data/.rubocop.yml +2 -5
  4. data/CHANGELOG.md +38 -0
  5. data/CONTRIBUTING.md +1 -1
  6. data/Gemfile +1 -1
  7. data/README.md +11 -3
  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 +1 -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 +14 -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/_experiment.erb +2 -1
  24. data/lib/split/dashboard/views/index.erb +19 -4
  25. data/lib/split/dashboard.rb +29 -23
  26. data/lib/split/encapsulated_helper.rb +4 -6
  27. data/lib/split/experiment.rb +93 -88
  28. data/lib/split/experiment_catalog.rb +6 -5
  29. data/lib/split/extensions/string.rb +1 -1
  30. data/lib/split/goals_collection.rb +8 -10
  31. data/lib/split/helper.rb +20 -20
  32. data/lib/split/metric.rb +4 -5
  33. data/lib/split/persistence/cookie_adapter.rb +44 -47
  34. data/lib/split/persistence/dual_adapter.rb +7 -8
  35. data/lib/split/persistence/redis_adapter.rb +3 -4
  36. data/lib/split/persistence/session_adapter.rb +0 -2
  37. data/lib/split/persistence.rb +4 -4
  38. data/lib/split/redis_interface.rb +7 -1
  39. data/lib/split/trial.rb +23 -24
  40. data/lib/split/user.rb +12 -13
  41. data/lib/split/version.rb +1 -1
  42. data/lib/split/zscore.rb +1 -3
  43. data/lib/split.rb +26 -25
  44. data/spec/algorithms/block_randomization_spec.rb +6 -5
  45. data/spec/algorithms/weighted_sample_spec.rb +6 -5
  46. data/spec/algorithms/whiplash_spec.rb +4 -5
  47. data/spec/alternative_spec.rb +35 -36
  48. data/spec/cache_spec.rb +15 -19
  49. data/spec/combined_experiments_helper_spec.rb +18 -17
  50. data/spec/configuration_spec.rb +32 -38
  51. data/spec/dashboard/pagination_helpers_spec.rb +69 -67
  52. data/spec/dashboard/paginator_spec.rb +10 -9
  53. data/spec/dashboard_helpers_spec.rb +19 -18
  54. data/spec/dashboard_spec.rb +79 -35
  55. data/spec/encapsulated_helper_spec.rb +12 -14
  56. data/spec/experiment_catalog_spec.rb +14 -13
  57. data/spec/experiment_spec.rb +132 -123
  58. data/spec/goals_collection_spec.rb +17 -15
  59. data/spec/helper_spec.rb +415 -382
  60. data/spec/metric_spec.rb +14 -14
  61. data/spec/persistence/cookie_adapter_spec.rb +23 -8
  62. data/spec/persistence/dual_adapter_spec.rb +71 -71
  63. data/spec/persistence/redis_adapter_spec.rb +28 -29
  64. data/spec/persistence/session_adapter_spec.rb +2 -3
  65. data/spec/persistence_spec.rb +1 -2
  66. data/spec/redis_interface_spec.rb +26 -14
  67. data/spec/spec_helper.rb +16 -13
  68. data/spec/split_spec.rb +11 -11
  69. data/spec/support/cookies_mock.rb +1 -2
  70. data/spec/trial_spec.rb +61 -60
  71. data/spec/user_spec.rb +36 -36
  72. data/split.gemspec +21 -20
  73. metadata +25 -14
  74. data/.rubocop_todo.yml +0 -226
  75. data/Appraisals +0 -19
  76. data/gemfiles/5.0.gemfile +0 -9
  77. data/gemfiles/5.1.gemfile +0 -9
@@ -5,7 +5,6 @@ require "json"
5
5
  module Split
6
6
  module Persistence
7
7
  class CookieAdapter
8
-
9
8
  def initialize(context)
10
9
  @context = context
11
10
  @request, @response = context.request, context.response
@@ -30,50 +29,49 @@ module Split
30
29
  end
31
30
 
32
31
  private
32
+ def set_cookie(value = {})
33
+ cookie_key = :split.to_s
34
+ cookie_value = default_options.merge(value: JSON.generate(value))
35
+ if action_dispatch?
36
+ # The "send" is necessary when we call ab_test from the controller
37
+ # and thus @context is a rails controller, because then "cookies" is
38
+ # a private method.
39
+ @context.send(:cookies)[cookie_key] = cookie_value
40
+ else
41
+ set_cookie_via_rack(cookie_key, cookie_value)
42
+ end
43
+ end
33
44
 
34
- def set_cookie(value = {})
35
- cookie_key = :split.to_s
36
- cookie_value = default_options.merge(value: JSON.generate(value))
37
- if action_dispatch?
38
- # The "send" is necessary when we call ab_test from the controller
39
- # and thus @context is a rails controller, because then "cookies" is
40
- # a private method.
41
- @context.send(:cookies)[cookie_key] = cookie_value
42
- else
43
- set_cookie_via_rack(cookie_key, cookie_value)
45
+ def default_options
46
+ { expires: @expires, path: "/", domain: cookie_domain_config }.compact
44
47
  end
45
- end
46
48
 
47
- def default_options
48
- { expires: @expires, path: '/', domain: cookie_domain_config }.compact
49
- end
49
+ def set_cookie_via_rack(key, value)
50
+ delete_cookie_header!(@response.header, key, value)
51
+ Rack::Utils.set_cookie_header!(@response.header, key, value)
52
+ end
50
53
 
51
- def set_cookie_via_rack(key, value)
52
- delete_cookie_header!(@response.header, key, value)
53
- Rack::Utils.set_cookie_header!(@response.header, key, value)
54
- end
54
+ # Use Rack::Utils#make_delete_cookie_header after Rack 2.0.0
55
+ def delete_cookie_header!(header, key, value)
56
+ cookie_header = header["Set-Cookie"]
57
+ case cookie_header
58
+ when nil, ""
59
+ cookies = []
60
+ when String
61
+ cookies = cookie_header.split("\n")
62
+ when Array
63
+ cookies = cookie_header
64
+ end
55
65
 
56
- # Use Rack::Utils#make_delete_cookie_header after Rack 2.0.0
57
- def delete_cookie_header!(header, key, value)
58
- cookie_header = header['Set-Cookie']
59
- case cookie_header
60
- when nil, ''
61
- cookies = []
62
- when String
63
- cookies = cookie_header.split("\n")
64
- when Array
65
- cookies = cookie_header
66
+ cookies.reject! { |cookie| cookie =~ /\A#{Rack::Utils.escape(key)}=/ }
67
+ header["Set-Cookie"] = cookies.join("\n")
66
68
  end
67
69
 
68
- cookies.reject! { |cookie| cookie =~ /\A#{Rack::Utils.escape(key)}=/ }
69
- header['Set-Cookie'] = cookies.join("\n")
70
- end
71
-
72
- def hash
73
- @hash ||= begin
74
- if cookies = @cookies[:split.to_s]
70
+ def hash
71
+ @hash ||= if cookies = @cookies[:split.to_s]
75
72
  begin
76
- JSON.parse(cookies)
73
+ parsed = JSON.parse(cookies)
74
+ parsed.is_a?(Hash) ? parsed : {}
77
75
  rescue JSON::ParserError
78
76
  {}
79
77
  end
@@ -81,19 +79,18 @@ module Split
81
79
  {}
82
80
  end
83
81
  end
84
- end
85
82
 
86
- def cookie_length_config
87
- Split.configuration.persistence_cookie_length
88
- end
83
+ def cookie_length_config
84
+ Split.configuration.persistence_cookie_length
85
+ end
89
86
 
90
- def cookie_domain_config
91
- Split.configuration.persistence_cookie_domain
92
- end
87
+ def cookie_domain_config
88
+ Split.configuration.persistence_cookie_domain
89
+ end
93
90
 
94
- def action_dispatch?
95
- defined?(Rails) && @response.is_a?(ActionDispatch::Response)
96
- end
91
+ def action_dispatch?
92
+ defined?(Rails) && @response.is_a?(ActionDispatch::Response)
93
+ end
97
94
  end
98
95
  end
99
96
  end
@@ -3,7 +3,7 @@
3
3
  module Split
4
4
  module Persistence
5
5
  class DualAdapter
6
- def self.with_config(options={})
6
+ def self.with_config(options = {})
7
7
  self.config.merge!(options)
8
8
  self
9
9
  end
@@ -72,14 +72,13 @@ module Split
72
72
  end
73
73
 
74
74
  private
75
+ def decrement_participation?(old_value, value)
76
+ !old_value.nil? && !value.nil? && old_value != value
77
+ end
75
78
 
76
- def decrement_participation?(old_value, value)
77
- !old_value.nil? && !value.nil? && old_value != value
78
- end
79
-
80
- def decrement_participation(key, value)
81
- Split.redis.hincrby("#{key}:#{value}", 'participant_count', -1)
82
- end
79
+ def decrement_participation(key, value)
80
+ Split.redis.hincrby("#{key}:#{value}", "participant_count", -1)
81
+ end
83
82
  end
84
83
  end
85
84
  end
@@ -3,7 +3,7 @@
3
3
  module Split
4
4
  module Persistence
5
5
  class RedisAdapter
6
- DEFAULT_CONFIG = {:namespace => 'persistence'}.freeze
6
+ DEFAULT_CONFIG = { namespace: "persistence" }.freeze
7
7
 
8
8
  attr_reader :redis_key
9
9
 
@@ -27,7 +27,7 @@ module Split
27
27
  end
28
28
 
29
29
  def []=(field, value)
30
- Split.redis.hset(redis_key, field, value)
30
+ Split.redis.hset(redis_key, field, value.to_s)
31
31
  expire_seconds = self.class.config[:expire_seconds]
32
32
  Split.redis.expire(redis_key, expire_seconds) if expire_seconds
33
33
  end
@@ -44,7 +44,7 @@ module Split
44
44
  new(nil, user_id)
45
45
  end
46
46
 
47
- def self.with_config(options={})
47
+ def self.with_config(options = {})
48
48
  self.config.merge!(options)
49
49
  self
50
50
  end
@@ -56,7 +56,6 @@ module Split
56
56
  def self.reset_config!
57
57
  @config = DEFAULT_CONFIG.dup
58
58
  end
59
-
60
59
  end
61
60
  end
62
61
  end
@@ -3,7 +3,6 @@
3
3
  module Split
4
4
  module Persistence
5
5
  class SessionAdapter
6
-
7
6
  def initialize(context)
8
7
  @session = context.session
9
8
  @session[:split] ||= {}
@@ -24,7 +23,6 @@ module Split
24
23
  def keys
25
24
  @session[:split].keys
26
25
  end
27
-
28
26
  end
29
27
  end
30
28
  end
@@ -2,10 +2,10 @@
2
2
 
3
3
  module Split
4
4
  module Persistence
5
- require 'split/persistence/cookie_adapter'
6
- require 'split/persistence/dual_adapter'
7
- require 'split/persistence/redis_adapter'
8
- require 'split/persistence/session_adapter'
5
+ require "split/persistence/cookie_adapter"
6
+ require "split/persistence/dual_adapter"
7
+ require "split/persistence/redis_adapter"
8
+ require "split/persistence/session_adapter"
9
9
 
10
10
  ADAPTERS = {
11
11
  cookie: Split::Persistence::CookieAdapter,
@@ -11,6 +11,7 @@ module Split
11
11
  if list_values.length > 0
12
12
  redis.multi do |multi|
13
13
  tmp_list = "#{list_name}_tmp"
14
+ tmp_list += redis_namespace_used? ? "{#{Split.redis.namespace}:#{list_name}}" : "{#{list_name}}"
14
15
  multi.rpush(tmp_list, list_values)
15
16
  multi.rename(tmp_list, list_name)
16
17
  end
@@ -20,11 +21,16 @@ module Split
20
21
  end
21
22
 
22
23
  def add_to_set(set_name, value)
24
+ return redis.sadd?(set_name, value) if redis.respond_to?(:sadd?)
25
+
23
26
  redis.sadd(set_name, value)
24
27
  end
25
28
 
26
29
  private
30
+ attr_accessor :redis
27
31
 
28
- attr_accessor :redis
32
+ def redis_namespace_used?
33
+ Redis.const_defined?("Namespace") && Split.redis.is_a?(Redis::Namespace)
34
+ end
29
35
  end
30
36
  end
data/lib/split/trial.rb CHANGED
@@ -24,15 +24,15 @@ module Split
24
24
 
25
25
  def alternative
26
26
  @alternative ||= if @experiment.has_winner?
27
- @experiment.winner
28
- end
27
+ @experiment.winner
28
+ end
29
29
  end
30
30
 
31
31
  def alternative=(alternative)
32
32
  @alternative = if alternative.kind_of?(Split::Alternative)
33
33
  alternative
34
34
  else
35
- @experiment.alternatives.find{|a| a.name == alternative }
35
+ @experiment.alternatives.find { |a| a.name == alternative }
36
36
  end
37
37
  end
38
38
 
@@ -41,7 +41,7 @@ module Split
41
41
  if Array(goals).empty?
42
42
  alternative.increment_completion
43
43
  else
44
- Array(goals).each {|g| alternative.increment_completion(g) }
44
+ Array(goals).each { |g| alternative.increment_completion(g) }
45
45
  end
46
46
 
47
47
  run_callback context, Split.configuration.on_trial_complete
@@ -97,31 +97,30 @@ module Split
97
97
  end
98
98
 
99
99
  private
100
+ def run_callback(context, callback_name)
101
+ context.send(callback_name, self) if callback_name && context.respond_to?(callback_name, true)
102
+ end
100
103
 
101
- def run_callback(context, callback_name)
102
- context.send(callback_name, self) if callback_name && context.respond_to?(callback_name, true)
103
- end
104
-
105
- def override_is_alternative?
106
- @experiment.alternatives.map(&:name).include?(@options[:override])
107
- end
104
+ def override_is_alternative?
105
+ @experiment.alternatives.map(&:name).include?(@options[:override])
106
+ end
108
107
 
109
- def should_store_alternative?
110
- if @options[:override] || @options[:disabled]
111
- Split.configuration.store_override
112
- else
113
- !exclude_user?
108
+ def should_store_alternative?
109
+ if @options[:override] || @options[:disabled]
110
+ Split.configuration.store_override
111
+ else
112
+ !exclude_user?
113
+ end
114
114
  end
115
- end
116
115
 
117
- def cleanup_old_versions
118
- if @experiment.version > 0
119
- @user.cleanup_old_versions!(@experiment)
116
+ def cleanup_old_versions
117
+ if @experiment.version > 0
118
+ @user.cleanup_old_versions!(@experiment)
119
+ end
120
120
  end
121
- end
122
121
 
123
- def exclude_user?
124
- @options[:exclude] || @experiment.start_time.nil? || @user.max_experiments_reached?(@experiment.key)
125
- end
122
+ def exclude_user?
123
+ @options[:exclude] || @experiment.start_time.nil? || @user.max_experiments_reached?(@experiment.key)
124
+ end
126
125
  end
127
126
  end
data/lib/split/user.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'forwardable'
3
+ require "forwardable"
4
4
 
5
5
  module Split
6
6
  class User
@@ -26,10 +26,10 @@ module Split
26
26
  end
27
27
 
28
28
  def max_experiments_reached?(experiment_key)
29
- if Split.configuration.allow_multiple_experiments == 'control'
29
+ if Split.configuration.allow_multiple_experiments == "control"
30
30
  experiments = active_experiments
31
31
  experiment_key_without_version = key_without_version(experiment_key)
32
- count_control = experiments.count {|k, v| k == experiment_key_without_version || v == 'control'}
32
+ count_control = experiments.count { |k, v| k == experiment_key_without_version || v == "control" }
33
33
  experiments.size > count_control
34
34
  else
35
35
  !Split.configuration.allow_multiple_experiments &&
@@ -65,17 +65,16 @@ module Split
65
65
  end
66
66
 
67
67
  private
68
+ def keys_without_experiment(keys, experiment_key)
69
+ keys.reject { |k| k.match(Regexp.new("^#{experiment_key}(:finished)?$")) }
70
+ end
68
71
 
69
- def keys_without_experiment(keys, experiment_key)
70
- keys.reject { |k| k.match(Regexp.new("^#{experiment_key}(:finished)?$")) }
71
- end
72
-
73
- def keys_without_finished(keys)
74
- keys.reject { |k| k.include?(":finished") }
75
- end
72
+ def keys_without_finished(keys)
73
+ keys.reject { |k| k.include?(":finished") }
74
+ end
76
75
 
77
- def key_without_version(key)
78
- key.split(/\:\d(?!\:)/)[0]
79
- end
76
+ def key_without_version(key)
77
+ key.split(/\:\d(?!\:)/)[0]
78
+ end
80
79
  end
81
80
  end
data/lib/split/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Split
4
- VERSION = "4.0.1"
4
+ VERSION = "4.0.3"
5
5
  end
data/lib/split/zscore.rb CHANGED
@@ -2,7 +2,6 @@
2
2
 
3
3
  module Split
4
4
  class Zscore
5
-
6
5
  include Math
7
6
 
8
7
  def self.calculate(p1, n1, p2, n2)
@@ -51,8 +50,7 @@ module Split
51
50
  # Calculate z-score
52
51
  z_score = (p_1 - p_2)/(se)
53
52
 
54
- return z_score
55
-
53
+ z_score
56
54
  end
57
55
  end
58
56
  end
data/lib/split.rb CHANGED
@@ -1,29 +1,30 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'redis'
3
+ require "redis"
4
4
 
5
- require 'split/algorithms/block_randomization'
6
- require 'split/algorithms/weighted_sample'
7
- require 'split/algorithms/whiplash'
8
- require 'split/alternative'
9
- require 'split/cache'
10
- require 'split/configuration'
11
- require 'split/encapsulated_helper'
12
- require 'split/exceptions'
13
- require 'split/experiment'
14
- require 'split/experiment_catalog'
15
- require 'split/extensions/string'
16
- require 'split/goals_collection'
17
- require 'split/helper'
18
- require 'split/combined_experiments_helper'
19
- require 'split/metric'
20
- require 'split/persistence'
21
- require 'split/redis_interface'
22
- require 'split/trial'
23
- require 'split/user'
24
- require 'split/version'
25
- require 'split/zscore'
26
- require 'split/engine' if defined?(Rails)
5
+ require "split/algorithms"
6
+ require "split/algorithms/block_randomization"
7
+ require "split/algorithms/weighted_sample"
8
+ require "split/algorithms/whiplash"
9
+ require "split/alternative"
10
+ require "split/cache"
11
+ require "split/configuration"
12
+ require "split/encapsulated_helper"
13
+ require "split/exceptions"
14
+ require "split/experiment"
15
+ require "split/experiment_catalog"
16
+ require "split/extensions/string"
17
+ require "split/goals_collection"
18
+ require "split/helper"
19
+ require "split/combined_experiments_helper"
20
+ require "split/metric"
21
+ require "split/persistence"
22
+ require "split/redis_interface"
23
+ require "split/trial"
24
+ require "split/user"
25
+ require "split/version"
26
+ require "split/zscore"
27
+ require "split/engine" if defined?(Rails)
27
28
 
28
29
  module Split
29
30
  extend self
@@ -75,8 +76,8 @@ end
75
76
  # Check to see if being run in a Rails application. If so, wait until before_initialize to run configuration so Gems that create ENV variables have the chance to initialize first.
76
77
  if defined?(::Rails)
77
78
  class Split::Railtie < Rails::Railtie
78
- config.before_initialize { Split.configure {} }
79
+ config.before_initialize { Split.configure { } }
79
80
  end
80
81
  else
81
- Split.configure {}
82
+ Split.configure { }
82
83
  end
@@ -1,11 +1,12 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "spec_helper"
2
4
 
3
5
  describe Split::Algorithms::BlockRandomization do
4
-
5
- let(:experiment) { Split::Experiment.new 'experiment' }
6
- let(:alternative_A) { Split::Alternative.new 'A', 'experiment' }
7
- let(:alternative_B) { Split::Alternative.new 'B', 'experiment' }
8
- let(:alternative_C) { Split::Alternative.new 'C', 'experiment' }
6
+ let(:experiment) { Split::Experiment.new "experiment" }
7
+ let(:alternative_A) { Split::Alternative.new "A", "experiment" }
8
+ let(:alternative_B) { Split::Alternative.new "B", "experiment" }
9
+ let(:alternative_C) { Split::Alternative.new "C", "experiment" }
9
10
 
10
11
  before :each do
11
12
  allow(experiment).to receive(:alternatives) { [alternative_A, alternative_B, alternative_C] }
@@ -1,19 +1,20 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  require "spec_helper"
3
4
 
4
5
  describe Split::Algorithms::WeightedSample do
5
6
  it "should return an alternative" do
6
- experiment = Split::ExperimentCatalog.find_or_create('link_color', {'blue' => 100}, {'red' => 0 })
7
+ experiment = Split::ExperimentCatalog.find_or_create("link_color", { "blue" => 100 }, { "red" => 0 })
7
8
  expect(Split::Algorithms::WeightedSample.choose_alternative(experiment).class).to eq(Split::Alternative)
8
9
  end
9
10
 
10
11
  it "should always return a heavily weighted option" do
11
- experiment = Split::ExperimentCatalog.find_or_create('link_color', {'blue' => 100}, {'red' => 0 })
12
- expect(Split::Algorithms::WeightedSample.choose_alternative(experiment).name).to eq('blue')
12
+ experiment = Split::ExperimentCatalog.find_or_create("link_color", { "blue" => 100 }, { "red" => 0 })
13
+ expect(Split::Algorithms::WeightedSample.choose_alternative(experiment).name).to eq("blue")
13
14
  end
14
15
 
15
16
  it "should return one of the results" do
16
- experiment = Split::ExperimentCatalog.find_or_create('link_color', {'blue' => 1}, {'red' => 1 })
17
- expect(['red', 'blue']).to include Split::Algorithms::WeightedSample.choose_alternative(experiment).name
17
+ experiment = Split::ExperimentCatalog.find_or_create("link_color", { "blue" => 1 }, { "red" => 1 })
18
+ expect(["red", "blue"]).to include Split::Algorithms::WeightedSample.choose_alternative(experiment).name
18
19
  end
19
20
  end
@@ -1,16 +1,16 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  require "spec_helper"
3
4
 
4
5
  describe Split::Algorithms::Whiplash do
5
-
6
6
  it "should return an algorithm" do
7
- experiment = Split::ExperimentCatalog.find_or_create('link_color', {'blue' => 1}, {'red' => 1 })
7
+ experiment = Split::ExperimentCatalog.find_or_create("link_color", { "blue" => 1 }, { "red" => 1 })
8
8
  expect(Split::Algorithms::Whiplash.choose_alternative(experiment).class).to eq(Split::Alternative)
9
9
  end
10
10
 
11
11
  it "should return one of the results" do
12
- experiment = Split::ExperimentCatalog.find_or_create('link_color', {'blue' => 1}, {'red' => 1 })
13
- expect(['red', 'blue']).to include Split::Algorithms::Whiplash.choose_alternative(experiment).name
12
+ experiment = Split::ExperimentCatalog.find_or_create("link_color", { "blue" => 1 }, { "red" => 1 })
13
+ expect(["red", "blue"]).to include Split::Algorithms::Whiplash.choose_alternative(experiment).name
14
14
  end
15
15
 
16
16
  it "should guess floats" do
@@ -20,5 +20,4 @@ describe Split::Algorithms::Whiplash do
20
20
  expect(Split::Algorithms::Whiplash.send(:arm_guess, 1000, 5).class).to eq(Float)
21
21
  expect(Split::Algorithms::Whiplash.send(:arm_guess, 10, -2).class).to eq(Float)
22
22
  end
23
-
24
23
  end