split 4.0.2 → 4.0.3

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f1c97063d4d1ccf4c2cd5dfd2e83b98b3f55a934b9dfa9b5862ede3ee5b8c58c
4
- data.tar.gz: 28e30003a6d2059baf91482f5ac9a97b0b7d2e37c61a425710cbf1adf21a4a83
3
+ metadata.gz: 746dd3b526b5464f12e01e2f00f8ff62b71ac6483527632f6f0bca7bc5242e8c
4
+ data.tar.gz: bb40ca355a1aa9eec9cfb4067e6e2b3c381072830cffadffe414f8d7a4af043f
5
5
  SHA512:
6
- metadata.gz: 988f115f0f96870188221552cca45f6a7207f548500dbf2a5446abaa47ac7365571644a5a231443ca7616182b68c3139f8d62fdcf18d1593fca8898092a332e2
7
- data.tar.gz: b6a668159d8b6fe9529bae5bc650f120b9de1bdf593bc89d0d949a2e07e8cfda7c96b4c12e5e4615696cf31b845215f95ce60b4abcb9ff3d7ef056669a4ae51d
6
+ metadata.gz: 70466ddfe57955a43dda0506c4a23806f6bdab154b344e495879027ae2baebec93d59f34018e78a3e83ef945c776c7a2ddcf2b40cd71998fb0bc9207ed60df61
7
+ data.tar.gz: db1d46d7e7e1826aacf80ec1c8634f0502bd07d4b58d488e57f4917a8843954d568b4cd20c9e2db09ac2ff80811b14ec68a3158b870d091eeabf4e426af8172d
@@ -37,6 +37,8 @@ jobs:
37
37
  - gemfile: 7.0.gemfile
38
38
  ruby: '3.1'
39
39
 
40
+ - gemfile: 7.0.gemfile
41
+ ruby: '3.2'
40
42
 
41
43
  runs-on: ubuntu-latest
42
44
 
@@ -51,7 +53,7 @@ jobs:
51
53
  --health-retries 5
52
54
 
53
55
  steps:
54
- - uses: actions/checkout@v3
56
+ - uses: actions/checkout@v4
55
57
 
56
58
  - uses: ruby/setup-ruby@v1
57
59
  with:
data/CHANGELOG.md CHANGED
@@ -1,3 +1,18 @@
1
+ # 4.0.3 (November 15rd, 2023)
2
+
3
+ Bugfixes:
4
+ - Do not throw error if alternativas have data that can lead to negative numbers for probability calculation (@andrehjr, #703)
5
+ - Do not persist invalid extra_info on ab_record_extra_info. (@trostli @andrehjr, #717)
6
+ - CROSSSLOT keys issue fix when using redis cluster (@naveen-chidhambaram, #710)
7
+ - Convert value to string before saving it in RedisAdapter (@Jealrock, #714)
8
+ - Fix deprecation warning with Redis 4.8.0 (@martingregoire, #701)
9
+
10
+ Misc:
11
+ - Add matrix as a default dependency (@andrehjr, #705)
12
+ - Add Ruby 3.2 to Github Actions (@andrehjr, #702)
13
+ - Update documentation regarding finding users outside a web session (@andrehjr, #716)
14
+ - Update actions/checkout to v4 (@andrehjr, #718)
15
+
1
16
  # 4.0.2 (December 2nd, 2022)
2
17
 
3
18
  Bugfixes:
data/Gemfile CHANGED
@@ -5,5 +5,4 @@ source "https://rubygems.org"
5
5
  gemspec
6
6
 
7
7
  gem "rubocop", require: false
8
- gem "matrix"
9
8
  gem "codeclimate-test-reporter"
data/README.md CHANGED
@@ -807,10 +807,16 @@ conduct experiments that are not tied to a web session.
807
807
  ```ruby
808
808
  # create a new experiment
809
809
  experiment = Split::ExperimentCatalog.find_or_create('color', 'red', 'blue')
810
+
811
+ # find the user
812
+ user = Split::User.find(user_id, :redis)
813
+
810
814
  # create a new trial
811
- trial = Split::Trial.new(:experiment => experiment)
815
+ trial = Split::Trial.new(user: user, experiment: experiment)
816
+
812
817
  # run trial
813
818
  trial.choose!
819
+
814
820
  # get the result, returns either red or blue
815
821
  trial.alternative.name
816
822
 
data/gemfiles/7.0.gemfile CHANGED
@@ -3,6 +3,5 @@ source "https://rubygems.org"
3
3
  gem "rubocop", require: false
4
4
  gem "codeclimate-test-reporter"
5
5
  gem "rails", "~> 7.0"
6
- gem "matrix"
7
6
 
8
7
  gemspec path: "../"
@@ -1,14 +1,6 @@
1
1
  # frozen_string_literal: true
2
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
-
3
+ require "matrix"
12
4
  require "rubystats"
13
5
 
14
6
  module Split
@@ -16,7 +16,8 @@
16
16
  summary_texts = {}
17
17
  extra_columns.each do |column|
18
18
  extra_infos = experiment.alternatives.map(&:extra_info).select{|extra_info| extra_info && extra_info[column] }
19
- if extra_infos[0][column].kind_of?(Numeric)
19
+
20
+ if extra_infos.length > 0 && extra_infos.all? { |extra_info| extra_info[column].kind_of?(Numeric) }
20
21
  summary_texts[column] = extra_infos.inject(0){|sum, extra_info| sum += extra_info[column]}
21
22
  else
22
23
  summary_texts[column] = "N/A"
@@ -270,7 +270,16 @@ module Split
270
270
  set_alternatives_and_options(options)
271
271
  end
272
272
 
273
+ def can_calculate_winning_alternatives?
274
+ self.alternatives.all? do |alternative|
275
+ alternative.participant_count >= 0 &&
276
+ (alternative.participant_count >= alternative.completed_count)
277
+ end
278
+ end
279
+
273
280
  def calc_winning_alternatives
281
+ return unless can_calculate_winning_alternatives?
282
+
274
283
  # Cache the winning alternatives so we recalculate them once per the specified interval.
275
284
  intervals_since_epoch =
276
285
  Time.now.utc.to_i / Split.configuration.winning_alternative_recalculation_interval
data/lib/split/helper.rb CHANGED
@@ -86,7 +86,7 @@ module Split
86
86
  end
87
87
 
88
88
  def ab_record_extra_info(metric_descriptor, key, value = 1)
89
- return if exclude_visitor? || Split.configuration.disabled?
89
+ return if exclude_visitor? || Split.configuration.disabled? || value.nil?
90
90
  metric_descriptor, _ = normalize_metric(metric_descriptor)
91
91
  experiments = Metric.possible_experiments(metric_descriptor)
92
92
 
@@ -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
@@ -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,10 +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
27
30
  attr_accessor :redis
31
+
32
+ def redis_namespace_used?
33
+ Redis.const_defined?("Namespace") && Split.redis.is_a?(Redis::Namespace)
34
+ end
28
35
  end
29
36
  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.2"
4
+ VERSION = "4.0.3"
5
5
  end
@@ -279,4 +279,16 @@ describe Split::Dashboard do
279
279
 
280
280
  expect(last_response.body).to include("<small>Unknown</small>")
281
281
  end
282
+
283
+ it "should be explode with experiments with invalid data" do
284
+ red_link.participant_count = 1
285
+ red_link.set_completed_count(10)
286
+
287
+ blue_link.participant_count = 3
288
+ blue_link.set_completed_count(2)
289
+
290
+ get "/"
291
+
292
+ expect(last_response).to be_ok
293
+ end
282
294
  end
@@ -576,6 +576,17 @@ describe Split::Experiment do
576
576
  expect(p_goal1).not_to be_within(0.04).of(p_goal2)
577
577
  end
578
578
 
579
+ it "should not calculate when data is not valid for beta distribution" do
580
+ experiment = Split::ExperimentCatalog.find_or_create("scientists", "einstein", "bohr")
581
+
582
+ experiment.alternatives.each do |alternative|
583
+ alternative.participant_count = 9
584
+ alternative.set_completed_count(10)
585
+ end
586
+
587
+ expect { experiment.calc_winning_alternatives }.to_not raise_error
588
+ end
589
+
579
590
  it "should return nil and not re-calculate probabilities if they have already been calculated today" do
580
591
  experiment = Split::ExperimentCatalog.find_or_create({ "link_color3" => ["purchase", "refund"] }, "blue", "red", "green")
581
592
  expect(experiment.calc_winning_alternatives).not_to be nil
data/spec/helper_spec.rb CHANGED
@@ -558,6 +558,42 @@ describe Split::Helper do
558
558
  end
559
559
  end
560
560
 
561
+
562
+ describe "ab_record_extra_info" do
563
+ context "for an experiment that the user participates in" do
564
+ before(:each) do
565
+ @experiment_name = "link_color"
566
+ @alternatives = ["blue", "red"]
567
+ @experiment = Split::ExperimentCatalog.find_or_create(@experiment_name, *@alternatives)
568
+ @alternative_name = ab_test(@experiment_name, *@alternatives)
569
+ end
570
+
571
+ it "records extra data for a given experiment" do
572
+ alternative = Split::Alternative.new(@alternative_name, "link_color")
573
+
574
+ ab_record_extra_info(@experiment_name, "some_data", 10)
575
+
576
+ expect(alternative.extra_info).to eql({ "some_data" => 10 })
577
+ end
578
+
579
+ it "records extra data for a given experiment" do
580
+ alternative = Split::Alternative.new(@alternative_name, "link_color")
581
+
582
+ ab_record_extra_info(@experiment_name, "some_data")
583
+
584
+ expect(alternative.extra_info).to eql({ "some_data" => 1 })
585
+ end
586
+
587
+ it "records extra data for a given experiment" do
588
+ alternative = Split::Alternative.new(@alternative_name, "link_color")
589
+
590
+ ab_record_extra_info(@experiment_name, "some_data", nil)
591
+
592
+ expect(alternative.extra_info).to eql({})
593
+ end
594
+ end
595
+ end
596
+
561
597
  describe "conversions" do
562
598
  it "should return a conversion rate for an alternative" do
563
599
  alternative_name = ab_test("link_color", "blue", "red")
@@ -73,9 +73,9 @@ describe Split::Persistence::RedisAdapter do
73
73
  before { Split::Persistence::RedisAdapter.with_config(lookup_by: "lookup") }
74
74
 
75
75
  describe "#[] and #[]=" do
76
- it "should set and return the value for given key" do
77
- subject["my_key"] = "my_value"
78
- expect(subject["my_key"]).to eq("my_value")
76
+ it "should convert to string, set and return the value for given key" do
77
+ subject["my_key"] = true
78
+ expect(subject["my_key"]).to eq("true")
79
79
  end
80
80
  end
81
81
 
@@ -40,5 +40,15 @@ describe Split::RedisInterface do
40
40
  add_to_set
41
41
  expect(Split.redis.sismember(set_name, "something")).to be true
42
42
  end
43
+
44
+ context "when a Redis version is used that supports the 'sadd?' method" do
45
+ before { expect(Split.redis).to receive(:respond_to?).with(:sadd?).and_return(true) }
46
+
47
+ it "will use this method instead of 'sadd'" do
48
+ expect(Split.redis).to receive(:sadd?).with(set_name, "something")
49
+ expect(Split.redis).not_to receive(:sadd).with(set_name, "something")
50
+ add_to_set
51
+ end
52
+ end
43
53
  end
44
54
  end
data/spec/spec_helper.rb CHANGED
@@ -11,6 +11,7 @@ SimpleCov.start
11
11
  require "split"
12
12
  require "ostruct"
13
13
  require "yaml"
14
+ require "pry"
14
15
 
15
16
  Dir["./spec/support/*.rb"].each { |f| require f }
16
17
 
data/split.gemspec CHANGED
@@ -33,6 +33,7 @@ Gem::Specification.new do |s|
33
33
  s.add_dependency "redis", ">= 4.2"
34
34
  s.add_dependency "sinatra", ">= 1.2.6"
35
35
  s.add_dependency "rubystats", ">= 0.3.0"
36
+ s.add_dependency "matrix"
36
37
 
37
38
  s.add_development_dependency "bundler", ">= 1.17"
38
39
  s.add_development_dependency "simplecov", "~> 0.15"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: split
3
3
  version: !ruby/object:Gem::Version
4
- version: 4.0.2
4
+ version: 4.0.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andrew Nesbitt
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-12-02 00:00:00.000000000 Z
11
+ date: 2023-11-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: redis
@@ -52,6 +52,20 @@ dependencies:
52
52
  - - ">="
53
53
  - !ruby/object:Gem::Version
54
54
  version: 0.3.0
55
+ - !ruby/object:Gem::Dependency
56
+ name: matrix
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
55
69
  - !ruby/object:Gem::Dependency
56
70
  name: bundler
57
71
  requirement: !ruby/object:Gem::Requirement
@@ -150,7 +164,7 @@ dependencies:
150
164
  - - ">="
151
165
  - !ruby/object:Gem::Version
152
166
  version: '5.0'
153
- description:
167
+ description:
154
168
  email:
155
169
  - andrewnez@gmail.com
156
170
  executables: []
@@ -260,7 +274,7 @@ metadata:
260
274
  bug_tracker_uri: https://github.com/splitrb/split/issues
261
275
  wiki_uri: https://github.com/splitrb/split/wiki
262
276
  mailing_list_uri: https://groups.google.com/d/forum/split-ruby
263
- post_install_message:
277
+ post_install_message:
264
278
  rdoc_options: []
265
279
  require_paths:
266
280
  - lib
@@ -275,8 +289,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
275
289
  - !ruby/object:Gem::Version
276
290
  version: 2.0.0
277
291
  requirements: []
278
- rubygems_version: 3.3.7
279
- signing_key:
292
+ rubygems_version: 3.1.6
293
+ signing_key:
280
294
  specification_version: 4
281
295
  summary: Rack based split testing framework
282
296
  test_files: