split 3.2.0 → 4.0.5

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 (87) hide show
  1. checksums.yaml +5 -5
  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 +63 -0
  7. data/.rspec +1 -0
  8. data/.rubocop.yml +67 -1043
  9. data/CHANGELOG.md +174 -0
  10. data/CODE_OF_CONDUCT.md +3 -3
  11. data/CONTRIBUTING.md +1 -1
  12. data/Gemfile +6 -1
  13. data/README.md +79 -33
  14. data/Rakefile +6 -5
  15. data/lib/split/algorithms/block_randomization.rb +7 -6
  16. data/lib/split/algorithms/weighted_sample.rb +2 -1
  17. data/lib/split/algorithms/whiplash.rb +17 -18
  18. data/lib/split/algorithms.rb +14 -0
  19. data/lib/split/alternative.rb +25 -25
  20. data/lib/split/cache.rb +27 -0
  21. data/lib/split/combined_experiments_helper.rb +6 -5
  22. data/lib/split/configuration.rb +94 -91
  23. data/lib/split/dashboard/helpers.rb +9 -9
  24. data/lib/split/dashboard/pagination_helpers.rb +86 -0
  25. data/lib/split/dashboard/paginator.rb +17 -0
  26. data/lib/split/dashboard/public/dashboard.js +10 -0
  27. data/lib/split/dashboard/public/style.css +19 -2
  28. data/lib/split/dashboard/views/_controls.erb +13 -0
  29. data/lib/split/dashboard/views/_experiment.erb +2 -1
  30. data/lib/split/dashboard/views/index.erb +24 -5
  31. data/lib/split/dashboard/views/layout.erb +1 -1
  32. data/lib/split/dashboard.rb +47 -20
  33. data/lib/split/encapsulated_helper.rb +15 -8
  34. data/lib/split/engine.rb +7 -4
  35. data/lib/split/exceptions.rb +1 -0
  36. data/lib/split/experiment.rb +160 -122
  37. data/lib/split/experiment_catalog.rb +7 -8
  38. data/lib/split/extensions/string.rb +2 -1
  39. data/lib/split/goals_collection.rb +10 -10
  40. data/lib/split/helper.rb +56 -24
  41. data/lib/split/metric.rb +6 -6
  42. data/lib/split/persistence/cookie_adapter.rb +52 -15
  43. data/lib/split/persistence/dual_adapter.rb +53 -12
  44. data/lib/split/persistence/redis_adapter.rb +8 -4
  45. data/lib/split/persistence/session_adapter.rb +1 -2
  46. data/lib/split/persistence.rb +8 -6
  47. data/lib/split/redis_interface.rb +16 -31
  48. data/lib/split/trial.rb +48 -41
  49. data/lib/split/user.rb +30 -15
  50. data/lib/split/version.rb +2 -4
  51. data/lib/split/zscore.rb +2 -3
  52. data/lib/split.rb +39 -25
  53. data/spec/algorithms/block_randomization_spec.rb +6 -5
  54. data/spec/algorithms/weighted_sample_spec.rb +6 -5
  55. data/spec/algorithms/whiplash_spec.rb +4 -5
  56. data/spec/alternative_spec.rb +35 -36
  57. data/spec/cache_spec.rb +84 -0
  58. data/spec/combined_experiments_helper_spec.rb +18 -17
  59. data/spec/configuration_spec.rb +41 -45
  60. data/spec/dashboard/pagination_helpers_spec.rb +202 -0
  61. data/spec/dashboard/paginator_spec.rb +38 -0
  62. data/spec/dashboard_helpers_spec.rb +19 -18
  63. data/spec/dashboard_spec.rb +153 -48
  64. data/spec/encapsulated_helper_spec.rb +47 -23
  65. data/spec/experiment_catalog_spec.rb +14 -13
  66. data/spec/experiment_spec.rb +224 -111
  67. data/spec/goals_collection_spec.rb +18 -16
  68. data/spec/helper_spec.rb +539 -419
  69. data/spec/metric_spec.rb +14 -14
  70. data/spec/persistence/cookie_adapter_spec.rb +105 -27
  71. data/spec/persistence/dual_adapter_spec.rb +158 -66
  72. data/spec/persistence/redis_adapter_spec.rb +35 -27
  73. data/spec/persistence/session_adapter_spec.rb +2 -3
  74. data/spec/persistence_spec.rb +1 -2
  75. data/spec/redis_interface_spec.rb +25 -82
  76. data/spec/spec_helper.rb +38 -24
  77. data/spec/split_spec.rb +18 -18
  78. data/spec/support/cookies_mock.rb +1 -2
  79. data/spec/trial_spec.rb +117 -70
  80. data/spec/user_spec.rb +69 -27
  81. data/split.gemspec +26 -22
  82. metadata +85 -37
  83. data/.travis.yml +0 -41
  84. data/Appraisals +0 -13
  85. data/gemfiles/4.2.gemfile +0 -9
  86. data/gemfiles/5.0.gemfile +0 -10
  87. data/gemfiles/5.1.gemfile +0 -10
data/spec/metric_spec.rb CHANGED
@@ -1,31 +1,31 @@
1
1
  # frozen_string_literal: true
2
- require 'spec_helper'
3
- require 'split/metric'
2
+
3
+ require "spec_helper"
4
+ require "split/metric"
4
5
 
5
6
  describe Split::Metric do
6
- describe 'possible experiments' do
7
+ describe "possible experiments" do
7
8
  it "should load the experiment if there is one, but no metric" do
8
- experiment = Split::ExperimentCatalog.find_or_create('color', 'red', 'blue')
9
- expect(Split::Metric.possible_experiments('color')).to eq([experiment])
9
+ experiment = Split::ExperimentCatalog.find_or_create("color", "red", "blue")
10
+ expect(Split::Metric.possible_experiments("color")).to eq([experiment])
10
11
  end
11
12
 
12
13
  it "should load the experiments in a metric" do
13
- experiment1 = Split::ExperimentCatalog.find_or_create('color', 'red', 'blue')
14
- experiment2 = Split::ExperimentCatalog.find_or_create('size', 'big', 'small')
14
+ experiment1 = Split::ExperimentCatalog.find_or_create("color", "red", "blue")
15
+ experiment2 = Split::ExperimentCatalog.find_or_create("size", "big", "small")
15
16
 
16
- metric = Split::Metric.new(:name => 'purchase', :experiments => [experiment1, experiment2])
17
+ metric = Split::Metric.new(name: "purchase", experiments: [experiment1, experiment2])
17
18
  metric.save
18
- expect(Split::Metric.possible_experiments('purchase')).to include(experiment1, experiment2)
19
+ expect(Split::Metric.possible_experiments("purchase")).to include(experiment1, experiment2)
19
20
  end
20
21
 
21
22
  it "should load both the metric experiments and an experiment with the same name" do
22
- experiment1 = Split::ExperimentCatalog.find_or_create('purchase', 'red', 'blue')
23
- experiment2 = Split::ExperimentCatalog.find_or_create('size', 'big', 'small')
23
+ experiment1 = Split::ExperimentCatalog.find_or_create("purchase", "red", "blue")
24
+ experiment2 = Split::ExperimentCatalog.find_or_create("size", "big", "small")
24
25
 
25
- metric = Split::Metric.new(:name => 'purchase', :experiments => [experiment2])
26
+ metric = Split::Metric.new(name: "purchase", experiments: [experiment2])
26
27
  metric.save
27
- expect(Split::Metric.possible_experiments('purchase')).to include(experiment1, experiment2)
28
+ expect(Split::Metric.possible_experiments("purchase")).to include(experiment1, experiment2)
28
29
  end
29
30
  end
30
-
31
31
  end
@@ -1,43 +1,121 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  require "spec_helper"
3
- require 'rack/test'
4
+ require "rack/test"
4
5
 
5
6
  describe Split::Persistence::CookieAdapter do
7
+ subject { described_class.new(context) }
8
+
9
+ shared_examples "sets cookies correctly" do
10
+ describe "#[] and #[]=" do
11
+ it "set and return the value for given key" do
12
+ subject["my_key"] = "my_value"
13
+ expect(subject["my_key"]).to eq("my_value")
14
+ end
15
+
16
+ it "handles invalid JSON" do
17
+ context.request.cookies["split"] = "{\"foo\":2,"
18
+
19
+ expect(subject["my_key"]).to be_nil
20
+ subject["my_key"] = "my_value"
21
+ expect(subject["my_key"]).to eq("my_value")
22
+ end
23
+
24
+ it "ignores valid JSON of invalid type (integer)" do
25
+ context.request.cookies["split"] = "2"
26
+
27
+ expect(subject["my_key"]).to be_nil
28
+ subject["my_key"] = "my_value"
29
+ expect(subject["my_key"]).to eq("my_value")
30
+ end
6
31
 
7
- let(:env) { Rack::MockRequest.env_for("http://example.com:8080/") }
8
- let(:request) { Rack::Request.new(env) }
9
- let(:response) { Rack::MockResponse.new(200, {}, "") }
10
- let(:context) { double(request: request, response: response) }
11
- subject { Split::Persistence::CookieAdapter.new(context) }
32
+ it "ignores valid JSON of invalid type (array)" do
33
+ context.request.cookies["split"] = "[\"foo\", \"bar\"]"
12
34
 
13
- describe "#[] and #[]=" do
14
- it "should set and return the value for given key" do
15
- subject["my_key"] = "my_value"
16
- expect(subject["my_key"]).to eq("my_value")
35
+ expect(subject["my_key"]).to be_nil
36
+ subject["my_key"] = "my_value"
37
+ expect(subject["my_key"]).to eq("my_value")
38
+ end
17
39
  end
18
- end
19
40
 
20
- describe "#delete" do
21
- it "should delete the given key" do
22
- subject["my_key"] = "my_value"
23
- subject.delete("my_key")
24
- expect(subject["my_key"]).to be_nil
41
+ describe "#delete" do
42
+ it "should delete the given key" do
43
+ subject["my_key"] = "my_value"
44
+ subject.delete("my_key")
45
+ expect(subject["my_key"]).to be_nil
46
+ end
25
47
  end
26
- end
27
48
 
28
- describe "#keys" do
29
- it "should return an array of the session's stored keys" do
30
- subject["my_key"] = "my_value"
31
- subject["my_second_key"] = "my_second_value"
32
- expect(subject.keys).to match(["my_key", "my_second_key"])
49
+ describe "#keys" do
50
+ it "should return an array of the session's stored keys" do
51
+ subject["my_key"] = "my_value"
52
+ subject["my_second_key"] = "my_second_value"
53
+ expect(subject.keys).to match(["my_key", "my_second_key"])
54
+ end
33
55
  end
34
56
  end
35
57
 
36
- it "handles invalid JSON" do
37
- context.request.cookies[:split] = { :value => '{"foo":2,', :expires => Time.now }
38
- expect(subject["my_key"]).to be_nil
39
- subject["my_key"] = "my_value"
40
- expect(subject["my_key"]).to eq("my_value")
58
+
59
+ context "when using Rack" do
60
+ let(:env) { Rack::MockRequest.env_for("http://example.com:8080/") }
61
+ let(:request) { Rack::Request.new(env) }
62
+ let(:response) { Rack::MockResponse.new(200, {}, "") }
63
+ let(:context) { double(request: request, response: response, cookies: CookiesMock.new) }
64
+
65
+ include_examples "sets cookies correctly"
66
+
67
+ it "puts multiple experiments in a single cookie" do
68
+ subject["foo"] = "FOO"
69
+ subject["bar"] = "BAR"
70
+ expect(Array(context.response.headers["Set-Cookie"])).to include(/\Asplit=%7B%22foo%22%3A%22FOO%22%2C%22bar%22%3A%22BAR%22%7D; path=\/; expires=[a-zA-Z]{3}, \d{2} [a-zA-Z]{3} \d{4} \d{2}:\d{2}:\d{2} [A-Z]{3}\Z/)
71
+ end
72
+
73
+ it "ensure other added cookies are not overriden" do
74
+ context.response.set_cookie "dummy", "wow"
75
+ subject["foo"] = "FOO"
76
+ expect(Array(context.response.headers["Set-Cookie"])).to include(/dummy=wow/)
77
+ expect(Array(context.response.headers["Set-Cookie"])).to include(/split=/)
78
+ end
41
79
  end
42
80
 
81
+ context "when @context is an ActionController::Base" do
82
+ before :context do
83
+ require "rails"
84
+ require "action_controller/railtie"
85
+ end
86
+
87
+ let(:context) do
88
+ controller = controller_class.new
89
+ if controller.respond_to?(:set_request!)
90
+ controller.set_request!(ActionDispatch::Request.new({}))
91
+ else # Before rails 5.0
92
+ controller.send(:"request=", ActionDispatch::Request.new({}))
93
+ end
94
+
95
+ response = ActionDispatch::Response.new(200, {}, "").tap do |res|
96
+ res.request = controller.request
97
+ end
98
+
99
+ if controller.respond_to?(:set_response!)
100
+ controller.set_response!(response)
101
+ else # Before rails 5.0
102
+ controller.send(:set_response!, response)
103
+ end
104
+ controller
105
+ end
106
+
107
+ let(:controller_class) { Class.new(ActionController::Base) }
108
+
109
+ include_examples "sets cookies correctly"
110
+
111
+ it "puts multiple experiments in a single cookie" do
112
+ subject["foo"] = "FOO"
113
+ subject["bar"] = "BAR"
114
+ expect(subject.keys).to eq(["foo", "bar"])
115
+ expect(subject["foo"]).to eq("FOO")
116
+ expect(subject["bar"]).to eq("BAR")
117
+ cookie_jar = context.request.env["action_dispatch.cookies"]
118
+ expect(cookie_jar["split"]).to eq('{"foo":"FOO","bar":"BAR"}')
119
+ end
120
+ end
43
121
  end
@@ -1,102 +1,194 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  require "spec_helper"
3
4
 
4
5
  describe Split::Persistence::DualAdapter do
6
+ let(:context) { "some context" }
5
7
 
6
- let(:context){ "some context" }
7
-
8
- let(:just_adapter){ Class.new }
9
- let(:selected_adapter_instance){ double }
10
- let(:selected_adapter){
11
- c = Class.new
12
- expect(c).to receive(:new){ selected_adapter_instance }
13
- c
14
- }
15
- let(:not_selected_adapter){
16
- c = Class.new
17
- expect(c).not_to receive(:new)
18
- c
19
- }
20
-
21
- shared_examples_for "forwarding calls" do
22
- it "#[]=" do
23
- expect(selected_adapter_instance).to receive(:[]=).with('my_key', 'my_value')
24
- expect_any_instance_of(not_selected_adapter).not_to receive(:[]=)
25
- subject["my_key"] = "my_value"
26
- end
8
+ let(:logged_in_adapter_instance) { double }
9
+ let(:logged_in_adapter) do
10
+ Class.new.tap { |c| allow(c).to receive(:new) { logged_in_adapter_instance } }
11
+ end
12
+ let(:logged_out_adapter_instance) { double }
13
+ let(:logged_out_adapter) do
14
+ Class.new.tap { |c| allow(c).to receive(:new) { logged_out_adapter_instance } }
15
+ end
27
16
 
28
- it "#[]" do
29
- expect(selected_adapter_instance).to receive(:[]).with('my_key'){'my_value'}
30
- expect_any_instance_of(not_selected_adapter).not_to receive(:[])
31
- expect(subject["my_key"]).to eq('my_value')
32
- end
17
+ context "when fallback_to_logged_out_adapter is false" do
18
+ context "when logged in" do
19
+ subject do
20
+ described_class.with_config(
21
+ logged_in: lambda { |context| true },
22
+ logged_in_adapter: logged_in_adapter,
23
+ logged_out_adapter: logged_out_adapter,
24
+ fallback_to_logged_out_adapter: false
25
+ ).new(context)
26
+ end
27
+
28
+ it "#[]=" do
29
+ expect(logged_in_adapter_instance).to receive(:[]=).with("my_key", "my_value")
30
+ expect_any_instance_of(logged_out_adapter).not_to receive(:[]=)
31
+ subject["my_key"] = "my_value"
32
+ end
33
+
34
+ it "#[]" do
35
+ expect(logged_in_adapter_instance).to receive(:[]).with("my_key") { "my_value" }
36
+ expect_any_instance_of(logged_out_adapter).not_to receive(:[])
37
+ expect(subject["my_key"]).to eq("my_value")
38
+ end
33
39
 
34
- it "#delete" do
35
- expect(selected_adapter_instance).to receive(:delete).with('my_key'){'my_value'}
36
- expect_any_instance_of(not_selected_adapter).not_to receive(:delete)
37
- expect(subject.delete("my_key")).to eq('my_value')
40
+ it "#delete" do
41
+ expect(logged_in_adapter_instance).to receive(:delete).with("my_key") { "my_value" }
42
+ expect_any_instance_of(logged_out_adapter).not_to receive(:delete)
43
+ expect(subject.delete("my_key")).to eq("my_value")
44
+ end
45
+
46
+ it "#keys" do
47
+ expect(logged_in_adapter_instance).to receive(:keys) { ["my_value"] }
48
+ expect_any_instance_of(logged_out_adapter).not_to receive(:keys)
49
+ expect(subject.keys).to eq(["my_value"])
50
+ end
38
51
  end
39
52
 
40
- it "#keys" do
41
- expect(selected_adapter_instance).to receive(:keys){'my_value'}
42
- expect_any_instance_of(not_selected_adapter).not_to receive(:keys)
43
- expect(subject.keys).to eq('my_value')
53
+ context "when logged out" do
54
+ subject do
55
+ described_class.with_config(
56
+ logged_in: lambda { |context| false },
57
+ logged_in_adapter: logged_in_adapter,
58
+ logged_out_adapter: logged_out_adapter,
59
+ fallback_to_logged_out_adapter: false
60
+ ).new(context)
61
+ end
62
+
63
+ it "#[]=" do
64
+ expect_any_instance_of(logged_in_adapter).not_to receive(:[]=)
65
+ expect(logged_out_adapter_instance).to receive(:[]=).with("my_key", "my_value")
66
+ subject["my_key"] = "my_value"
67
+ end
68
+
69
+ it "#[]" do
70
+ expect_any_instance_of(logged_in_adapter).not_to receive(:[])
71
+ expect(logged_out_adapter_instance).to receive(:[]).with("my_key") { "my_value" }
72
+ expect(subject["my_key"]).to eq("my_value")
73
+ end
74
+
75
+ it "#delete" do
76
+ expect_any_instance_of(logged_in_adapter).not_to receive(:delete)
77
+ expect(logged_out_adapter_instance).to receive(:delete).with("my_key") { "my_value" }
78
+ expect(subject.delete("my_key")).to eq("my_value")
79
+ end
80
+
81
+ it "#keys" do
82
+ expect_any_instance_of(logged_in_adapter).not_to receive(:keys)
83
+ expect(logged_out_adapter_instance).to receive(:keys) { ["my_value", "my_value2"] }
84
+ expect(subject.keys).to eq(["my_value", "my_value2"])
85
+ end
44
86
  end
45
87
  end
46
88
 
47
- context "when logged in" do
48
- subject {
49
- described_class.with_config(
50
- logged_in: lambda { |context| true },
51
- logged_in_adapter: selected_adapter,
52
- logged_out_adapter: not_selected_adapter
89
+ context "when fallback_to_logged_out_adapter is true" do
90
+ context "when logged in" do
91
+ subject do
92
+ described_class.with_config(
93
+ logged_in: lambda { |context| true },
94
+ logged_in_adapter: logged_in_adapter,
95
+ logged_out_adapter: logged_out_adapter,
96
+ fallback_to_logged_out_adapter: true
53
97
  ).new(context)
54
- }
98
+ end
55
99
 
56
- it_should_behave_like "forwarding calls"
57
- end
100
+ it "#[]=" do
101
+ expect(logged_in_adapter_instance).to receive(:[]=).with("my_key", "my_value")
102
+ expect(logged_out_adapter_instance).to receive(:[]=).with("my_key", "my_value")
103
+ expect(logged_out_adapter_instance).to receive(:[]).with("my_key") { nil }
104
+ subject["my_key"] = "my_value"
105
+ end
106
+
107
+ it "#[]" do
108
+ expect(logged_in_adapter_instance).to receive(:[]).with("my_key") { "my_value" }
109
+ expect_any_instance_of(logged_out_adapter).not_to receive(:[])
110
+ expect(subject["my_key"]).to eq("my_value")
111
+ end
112
+
113
+ it "#delete" do
114
+ expect(logged_in_adapter_instance).to receive(:delete).with("my_key") { "my_value" }
115
+ expect(logged_out_adapter_instance).to receive(:delete).with("my_key") { "my_value" }
116
+ expect(subject.delete("my_key")).to eq("my_value")
117
+ end
118
+
119
+ it "#keys" do
120
+ expect(logged_in_adapter_instance).to receive(:keys) { ["my_value"] }
121
+ expect(logged_out_adapter_instance).to receive(:keys) { ["my_value", "my_value2"] }
122
+ expect(subject.keys).to eq(["my_value", "my_value2"])
123
+ end
124
+ end
58
125
 
59
- context "when not logged in" do
60
- subject {
61
- described_class.with_config(
62
- logged_in: lambda { |context| false },
63
- logged_in_adapter: not_selected_adapter,
64
- logged_out_adapter: selected_adapter
126
+ context "when logged out" do
127
+ subject do
128
+ described_class.with_config(
129
+ logged_in: lambda { |context| false },
130
+ logged_in_adapter: logged_in_adapter,
131
+ logged_out_adapter: logged_out_adapter,
132
+ fallback_to_logged_out_adapter: true
65
133
  ).new(context)
66
- }
134
+ end
135
+
136
+ it "#[]=" do
137
+ expect_any_instance_of(logged_in_adapter).not_to receive(:[]=)
138
+ expect(logged_out_adapter_instance).to receive(:[]=).with("my_key", "my_value")
139
+ expect(logged_out_adapter_instance).to receive(:[]).with("my_key") { nil }
140
+ subject["my_key"] = "my_value"
141
+ end
142
+
143
+ it "#[]" do
144
+ expect_any_instance_of(logged_in_adapter).not_to receive(:[])
145
+ expect(logged_out_adapter_instance).to receive(:[]).with("my_key") { "my_value" }
146
+ expect(subject["my_key"]).to eq("my_value")
147
+ end
148
+
149
+ it "#delete" do
150
+ expect(logged_in_adapter_instance).to receive(:delete).with("my_key") { "my_value" }
151
+ expect(logged_out_adapter_instance).to receive(:delete).with("my_key") { "my_value" }
152
+ expect(subject.delete("my_key")).to eq("my_value")
153
+ end
67
154
 
68
- it_should_behave_like "forwarding calls"
155
+ it "#keys" do
156
+ expect(logged_in_adapter_instance).to receive(:keys) { ["my_value"] }
157
+ expect(logged_out_adapter_instance).to receive(:keys) { ["my_value", "my_value2"] }
158
+ expect(subject.keys).to eq(["my_value", "my_value2"])
159
+ end
160
+ end
69
161
  end
70
162
 
71
163
  describe "when errors in config" do
72
- before{
73
- described_class.config.clear
74
- }
75
- let(:some_proc){ ->{} }
164
+ before { described_class.config.clear }
165
+ let(:some_proc) { -> { } }
166
+
76
167
  it "when no logged in adapter" do
77
- expect{
168
+ expect {
78
169
  described_class.with_config(
79
170
  logged_in: some_proc,
80
- logged_out_adapter: just_adapter
81
- ).new(context)
171
+ logged_out_adapter: logged_out_adapter
172
+ ).new(context)
82
173
  }.to raise_error(StandardError, /:logged_in_adapter/)
83
174
  end
175
+
84
176
  it "when no logged out adapter" do
85
- expect{
177
+ expect {
86
178
  described_class.with_config(
87
179
  logged_in: some_proc,
88
- logged_in_adapter: just_adapter
89
- ).new(context)
180
+ logged_in_adapter: logged_in_adapter
181
+ ).new(context)
90
182
  }.to raise_error(StandardError, /:logged_out_adapter/)
91
183
  end
184
+
92
185
  it "when no logged in detector" do
93
- expect{
186
+ expect {
94
187
  described_class.with_config(
95
- logged_in_adapter: just_adapter,
96
- logged_out_adapter: just_adapter
97
- ).new(context)
188
+ logged_in_adapter: logged_in_adapter,
189
+ logged_out_adapter: logged_out_adapter
190
+ ).new(context)
98
191
  }.to raise_error(StandardError, /:logged_in$/)
99
192
  end
100
193
  end
101
-
102
194
  end
@@ -1,72 +1,81 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  require "spec_helper"
3
4
 
4
5
  describe Split::Persistence::RedisAdapter do
5
-
6
- let(:context) { double(:lookup => 'blah') }
6
+ let(:context) { double(lookup: "blah") }
7
7
 
8
8
  subject { Split::Persistence::RedisAdapter.new(context) }
9
9
 
10
- describe '#redis_key' do
10
+ describe "#redis_key" do
11
11
  before { Split::Persistence::RedisAdapter.reset_config! }
12
12
 
13
- context 'default' do
14
- it 'should raise error with prompt to set lookup_by' do
15
- expect{Split::Persistence::RedisAdapter.new(context)}.to raise_error(RuntimeError)
13
+ context "default" do
14
+ it "should raise error with prompt to set lookup_by" do
15
+ expect { Split::Persistence::RedisAdapter.new(context) }.to raise_error(RuntimeError)
16
16
  end
17
17
  end
18
18
 
19
- context 'config with key' do
19
+ context "config with key" do
20
20
  before { Split::Persistence::RedisAdapter.reset_config! }
21
- subject { Split::Persistence::RedisAdapter.new(context, 'manual') }
21
+ subject { Split::Persistence::RedisAdapter.new(context, "manual") }
22
22
 
23
23
  it 'should be "persistence:manual"' do
24
- expect(subject.redis_key).to eq('persistence:manual')
24
+ expect(subject.redis_key).to eq("persistence:manual")
25
25
  end
26
26
  end
27
27
 
28
28
  context 'config with lookup_by = proc { "block" }' do
29
- before { Split::Persistence::RedisAdapter.with_config(:lookup_by => proc{'block'}) }
29
+ before { Split::Persistence::RedisAdapter.with_config(lookup_by: proc { "block" }) }
30
30
 
31
31
  it 'should be "persistence:block"' do
32
- expect(subject.redis_key).to eq('persistence:block')
32
+ expect(subject.redis_key).to eq("persistence:block")
33
33
  end
34
34
  end
35
35
 
36
- context 'config with lookup_by = proc { |context| context.test }' do
37
- before { Split::Persistence::RedisAdapter.with_config(:lookup_by => proc{'block'}) }
38
- let(:context) { double(:test => 'block') }
36
+ context "config with lookup_by = proc { |context| context.test }" do
37
+ before { Split::Persistence::RedisAdapter.with_config(lookup_by: proc { "block" }) }
38
+ let(:context) { double(test: "block") }
39
39
 
40
40
  it 'should be "persistence:block"' do
41
- expect(subject.redis_key).to eq('persistence:block')
41
+ expect(subject.redis_key).to eq("persistence:block")
42
42
  end
43
43
  end
44
44
 
45
45
  context 'config with lookup_by = "method_name"' do
46
- before { Split::Persistence::RedisAdapter.with_config(:lookup_by => 'method_name') }
47
- let(:context) { double(:method_name => 'val') }
46
+ before { Split::Persistence::RedisAdapter.with_config(lookup_by: "method_name") }
47
+ let(:context) { double(method_name: "val") }
48
48
 
49
49
  it 'should be "persistence:bar"' do
50
- expect(subject.redis_key).to eq('persistence:val')
50
+ expect(subject.redis_key).to eq("persistence:val")
51
51
  end
52
52
  end
53
53
 
54
- context 'config with namespace and lookup_by' do
55
- before { Split::Persistence::RedisAdapter.with_config(:lookup_by => proc{'frag'}, :namespace => 'namer') }
54
+ context "config with namespace and lookup_by" do
55
+ before { Split::Persistence::RedisAdapter.with_config(lookup_by: proc { "frag" }, namespace: "namer") }
56
56
 
57
57
  it 'should be "namer"' do
58
- expect(subject.redis_key).to eq('namer:frag')
58
+ expect(subject.redis_key).to eq("namer:frag")
59
59
  end
60
60
  end
61
61
  end
62
62
 
63
- context 'functional tests' do
64
- before { Split::Persistence::RedisAdapter.with_config(:lookup_by => 'lookup') }
63
+ describe "#find" do
64
+ before { Split::Persistence::RedisAdapter.with_config(lookup_by: proc { "frag" }, namespace: "a_namespace") }
65
+
66
+ it "should create and user from a given key" do
67
+ adapter = Split::Persistence::RedisAdapter.find(2)
68
+ expect(adapter.redis_key).to eq("a_namespace:2")
69
+ end
70
+ end
71
+
72
+ context "functional tests" do
73
+ before { Split::Persistence::RedisAdapter.with_config(lookup_by: "lookup") }
65
74
 
66
75
  describe "#[] and #[]=" do
67
- it "should set and return the value for given key" do
68
- subject["my_key"] = "my_value"
69
- 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")
70
79
  end
71
80
  end
72
81
 
@@ -85,6 +94,5 @@ describe Split::Persistence::RedisAdapter do
85
94
  expect(subject.keys).to match(["my_key", "my_second_key"])
86
95
  end
87
96
  end
88
-
89
97
  end
90
98
  end
@@ -1,9 +1,9 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  require "spec_helper"
3
4
 
4
5
  describe Split::Persistence::SessionAdapter do
5
-
6
- let(:context) { double(:session => {}) }
6
+ let(:context) { double(session: {}) }
7
7
  subject { Split::Persistence::SessionAdapter.new(context) }
8
8
 
9
9
  describe "#[] and #[]=" do
@@ -28,5 +28,4 @@ describe Split::Persistence::SessionAdapter do
28
28
  expect(subject.keys).to match(["my_key", "my_second_key"])
29
29
  end
30
30
  end
31
-
32
31
  end
@@ -1,8 +1,8 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  require "spec_helper"
3
4
 
4
5
  describe Split::Persistence do
5
-
6
6
  subject { Split::Persistence }
7
7
 
8
8
  describe ".adapter" do
@@ -30,5 +30,4 @@ describe Split::Persistence do
30
30
  end
31
31
  end
32
32
  end
33
-
34
33
  end