split 1.4.0 → 1.4.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +11 -0
- data/README.md +9 -5
- data/lib/split.rb +1 -0
- data/lib/split/configuration.rb +4 -0
- data/lib/split/experiment.rb +19 -32
- data/lib/split/goals_collection.rb +44 -0
- data/lib/split/trial.rb +1 -1
- data/lib/split/version.rb +1 -1
- data/spec/experiment_catalog_spec.rb +15 -0
- data/spec/experiment_spec.rb +43 -32
- data/spec/goals_collection_spec.rb +80 -0
- data/split.gemspec +1 -0
- metadata +19 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 07f7886845453ce92ac81c33d32927c4c0528d39
|
4
|
+
data.tar.gz: 26a46a18c8a8e743ea532be9f9e2e3c63f516f4e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1beb35f67693fa2073877c112cda7ba7abec3dfeff05699fdf13275d79ba0b424c982cc7c2811fdde826fcbced38f4e6b34d1e8db56786bf43aa7edff6d0bb92
|
7
|
+
data.tar.gz: d5956789a67b6d92d46e86e55b340900f806951a3dfea7419e1889df6844e21ef20a6777420fbb1362a8001f15c30e9114eb6020ec0de8b3bb508c8c58dfc6af
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,14 @@
|
|
1
|
+
## 1.4.1 (April 21st, 2016)
|
2
|
+
|
3
|
+
Bugfixes:
|
4
|
+
|
5
|
+
- respect manual start configuration after an experiment has been deleted (@mtyeh411, #372)
|
6
|
+
|
7
|
+
Misc:
|
8
|
+
|
9
|
+
- Introduce goals collection to reduce complexity of Experiment#save (@pakallis, #365)
|
10
|
+
- Revise specs according to http://betterspecs.org/ (@hkliya, #369)
|
11
|
+
|
1
12
|
## 1.4.0 (April 2nd, 2016)
|
2
13
|
|
3
14
|
Features:
|
data/README.md
CHANGED
@@ -151,7 +151,7 @@ It is not required to send `SPLIT_DISABLE=false` to activate Split.
|
|
151
151
|
By default new AB tests will be active right after deployment. In case you would like to start new test a while after
|
152
152
|
the deploy, you can do it by setting the `start_manually` configuration option to `true`.
|
153
153
|
|
154
|
-
After choosing this option tests won't be started right after deploy, but after pressing the `Start` button in Split admin dashboard.
|
154
|
+
After choosing this option tests won't be started right after deploy, but after pressing the `Start` button in Split admin dashboard. If a test is deleted from the Split dashboard, then it can only be started after pressing the `Start` button whenever being re-initialized.
|
155
155
|
|
156
156
|
### Reset after completion
|
157
157
|
|
@@ -284,8 +284,12 @@ For example:
|
|
284
284
|
|
285
285
|
``` ruby
|
286
286
|
Split.configure do |config|
|
287
|
+
# after experiment reset or deleted
|
287
288
|
config.on_experiment_reset = -> (example) { # Do something on reset }
|
288
289
|
config.on_experiment_delete = -> (experiment) { # Do something else on delete }
|
290
|
+
# before experiment reset or deleted
|
291
|
+
config.on_before_experiment_reset = -> (example) { # Do something on reset }
|
292
|
+
config.on_before_experiment_delete = -> (experiment) { # Do something else on delete }
|
289
293
|
end
|
290
294
|
```
|
291
295
|
|
@@ -445,9 +449,9 @@ Split.configure do |config|
|
|
445
449
|
alternatives: ["a", "b"],
|
446
450
|
metadata: {
|
447
451
|
"a" => {"text" => "Have a fantastic day"},
|
448
|
-
"b" => {"text" => "Don't get hit by a bus"}
|
452
|
+
"b" => {"text" => "Don't get hit by a bus"}
|
449
453
|
}
|
450
|
-
}
|
454
|
+
}
|
451
455
|
}
|
452
456
|
end
|
453
457
|
```
|
@@ -493,7 +497,7 @@ Split.configure do |config|
|
|
493
497
|
config.experiments = {
|
494
498
|
my_first_experiment: {
|
495
499
|
alternatives: ["a", "b"],
|
496
|
-
metric: :my_metric
|
500
|
+
metric: :my_metric
|
497
501
|
}
|
498
502
|
}
|
499
503
|
end
|
@@ -628,7 +632,7 @@ trial.choose!
|
|
628
632
|
trial.alternative.name
|
629
633
|
|
630
634
|
# if the goal has been achieved, increment the successful completions for this alternative.
|
631
|
-
if
|
635
|
+
if goal_achieved?
|
632
636
|
trial.complete!
|
633
637
|
end
|
634
638
|
|
data/lib/split.rb
CHANGED
data/lib/split/configuration.rb
CHANGED
@@ -19,6 +19,8 @@ module Split
|
|
19
19
|
attr_accessor :on_trial_complete
|
20
20
|
attr_accessor :on_experiment_reset
|
21
21
|
attr_accessor :on_experiment_delete
|
22
|
+
attr_accessor :on_before_experiment_reset
|
23
|
+
attr_accessor :on_before_experiment_delete
|
22
24
|
attr_accessor :include_rails_helper
|
23
25
|
attr_accessor :beta_probability_simulations
|
24
26
|
attr_accessor :redis_url
|
@@ -199,6 +201,8 @@ module Split
|
|
199
201
|
@db_failover_on_db_error = proc{|error|} # e.g. use Rails logger here
|
200
202
|
@on_experiment_reset = proc{|experiment|}
|
201
203
|
@on_experiment_delete = proc{|experiment|}
|
204
|
+
@on_before_experiment_reset = proc{|experiment|}
|
205
|
+
@on_before_experiment_delete = proc{|experiment|}
|
202
206
|
@db_failover_allow_parameter_override = false
|
203
207
|
@allow_multiple_experiments = false
|
204
208
|
@enabled = true
|
data/lib/split/experiment.rb
CHANGED
@@ -23,7 +23,7 @@ module Split
|
|
23
23
|
if alternatives.empty? && (exp_config = Split.configuration.experiment_for(name))
|
24
24
|
set_alternatives_and_options(
|
25
25
|
alternatives: load_alternatives_from_configuration,
|
26
|
-
goals:
|
26
|
+
goals: Split::GoalsCollection.new(@name).load_from_configuration,
|
27
27
|
metadata: load_metadata_from_configuration,
|
28
28
|
resettable: exp_config[:resettable],
|
29
29
|
algorithm: exp_config[:algorithm]
|
@@ -60,7 +60,7 @@ module Split
|
|
60
60
|
exp_config = Split.configuration.experiment_for(name)
|
61
61
|
if exp_config
|
62
62
|
alts = load_alternatives_from_configuration
|
63
|
-
options[:goals] =
|
63
|
+
options[:goals] = Split::GoalsCollection.new(@name).load_from_configuration
|
64
64
|
options[:metadata] = load_metadata_from_configuration
|
65
65
|
options[:resettable] = exp_config[:resettable]
|
66
66
|
options[:algorithm] = exp_config[:algorithm]
|
@@ -84,21 +84,21 @@ module Split
|
|
84
84
|
Split.redis.sadd(:experiments, name)
|
85
85
|
start unless Split.configuration.start_manually
|
86
86
|
@alternatives.reverse.each {|a| Split.redis.lpush(name, a.name)}
|
87
|
-
|
87
|
+
goals_collection.save
|
88
88
|
save_metadata
|
89
89
|
Split.redis.set(metadata_key, @metadata.to_json) unless @metadata.nil?
|
90
90
|
else
|
91
91
|
existing_alternatives = load_alternatives_from_redis
|
92
|
-
existing_goals =
|
92
|
+
existing_goals = Split::GoalsCollection.new(@name).load_from_redis
|
93
93
|
existing_metadata = load_metadata_from_redis
|
94
94
|
unless existing_alternatives == @alternatives.map(&:name) && existing_goals == @goals && existing_metadata == @metadata
|
95
95
|
reset
|
96
96
|
@alternatives.each(&:delete)
|
97
|
-
|
97
|
+
goals_collection.delete
|
98
98
|
delete_metadata
|
99
99
|
Split.redis.del(@name)
|
100
100
|
@alternatives.reverse.each {|a| Split.redis.lpush(name, a.name)}
|
101
|
-
|
101
|
+
goals_collection.save
|
102
102
|
save_metadata
|
103
103
|
end
|
104
104
|
end
|
@@ -113,9 +113,7 @@ module Split
|
|
113
113
|
raise ExperimentNotFound.new("Experiment #{@name} not found")
|
114
114
|
end
|
115
115
|
@alternatives.each {|a| a.validate! }
|
116
|
-
|
117
|
-
raise ArgumentError, 'Goals must be an array'
|
118
|
-
end
|
116
|
+
goals_collection.validate!
|
119
117
|
end
|
120
118
|
|
121
119
|
def new_record?
|
@@ -241,6 +239,7 @@ module Split
|
|
241
239
|
end
|
242
240
|
|
243
241
|
def reset
|
242
|
+
Split.configuration.on_before_experiment_reset.call(self)
|
244
243
|
alternatives.each(&:reset)
|
245
244
|
reset_winner
|
246
245
|
Split.configuration.on_experiment_reset.call(self)
|
@@ -248,20 +247,20 @@ module Split
|
|
248
247
|
end
|
249
248
|
|
250
249
|
def delete
|
250
|
+
Split.configuration.on_before_experiment_delete.call(self)
|
251
|
+
if Split.configuration.start_manually
|
252
|
+
Split.redis.hdel(:experiment_start_times, @name)
|
253
|
+
end
|
251
254
|
alternatives.each(&:delete)
|
252
255
|
reset_winner
|
253
256
|
Split.redis.srem(:experiments, name)
|
254
257
|
Split.redis.del(name)
|
255
|
-
|
258
|
+
goals_collection.delete
|
256
259
|
delete_metadata
|
257
260
|
Split.configuration.on_experiment_delete.call(self)
|
258
261
|
increment_version
|
259
262
|
end
|
260
263
|
|
261
|
-
def delete_goals
|
262
|
-
Split.redis.del(goals_key)
|
263
|
-
end
|
264
|
-
|
265
264
|
def delete_metadata
|
266
265
|
Split.redis.del(metadata_key)
|
267
266
|
end
|
@@ -271,7 +270,7 @@ module Split
|
|
271
270
|
self.resettable = exp_config['resettable']
|
272
271
|
self.algorithm = exp_config['algorithm']
|
273
272
|
self.alternatives = load_alternatives_from_redis
|
274
|
-
self.goals =
|
273
|
+
self.goals = Split::GoalsCollection.new(@name).load_from_redis
|
275
274
|
self.metadata = load_metadata_from_redis
|
276
275
|
end
|
277
276
|
|
@@ -419,19 +418,6 @@ module Split
|
|
419
418
|
metadata = Split.configuration.experiment_for(@name)[:metadata]
|
420
419
|
end
|
421
420
|
|
422
|
-
def load_goals_from_configuration
|
423
|
-
goals = Split.configuration.experiment_for(@name)[:goals]
|
424
|
-
if goals.nil?
|
425
|
-
goals = []
|
426
|
-
else
|
427
|
-
goals.flatten
|
428
|
-
end
|
429
|
-
end
|
430
|
-
|
431
|
-
def load_goals_from_redis
|
432
|
-
Split.redis.lrange(goals_key, 0, -1)
|
433
|
-
end
|
434
|
-
|
435
421
|
def load_metadata_from_redis
|
436
422
|
meta = Split.redis.get(metadata_key)
|
437
423
|
JSON.parse(meta) unless meta.nil?
|
@@ -459,13 +445,14 @@ module Split
|
|
459
445
|
end
|
460
446
|
end
|
461
447
|
|
462
|
-
def save_goals
|
463
|
-
@goals.reverse.each {|a| Split.redis.lpush(goals_key, a)} unless @goals.nil?
|
464
|
-
end
|
465
|
-
|
466
448
|
def save_metadata
|
467
449
|
Split.redis.set(metadata_key, @metadata.to_json) unless @metadata.nil?
|
468
450
|
end
|
469
451
|
|
452
|
+
private
|
453
|
+
|
454
|
+
def goals_collection
|
455
|
+
Split::GoalsCollection.new(@name, @goals)
|
456
|
+
end
|
470
457
|
end
|
471
458
|
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
module Split
|
2
|
+
class GoalsCollection
|
3
|
+
|
4
|
+
def initialize(experiment_name, goals=nil)
|
5
|
+
@experiment_name = experiment_name
|
6
|
+
@goals = goals
|
7
|
+
end
|
8
|
+
|
9
|
+
def load_from_redis
|
10
|
+
Split.redis.lrange(goals_key, 0, -1)
|
11
|
+
end
|
12
|
+
|
13
|
+
def load_from_configuration
|
14
|
+
goals = Split.configuration.experiment_for(@experiment_name)[:goals]
|
15
|
+
|
16
|
+
if goals.nil?
|
17
|
+
goals = []
|
18
|
+
else
|
19
|
+
goals.flatten
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def save
|
24
|
+
return false if @goals.nil?
|
25
|
+
@goals.reverse.each { |goal| Split.redis.lpush(goals_key, goal) }
|
26
|
+
end
|
27
|
+
|
28
|
+
def validate!
|
29
|
+
unless @goals.nil? || @goals.kind_of?(Array)
|
30
|
+
raise ArgumentError, 'Goals must be an array'
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def delete
|
35
|
+
Split.redis.del(goals_key)
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
def goals_key
|
41
|
+
"#{@experiment_name}:goals"
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
data/lib/split/trial.rb
CHANGED
@@ -55,7 +55,7 @@ module Split
|
|
55
55
|
|
56
56
|
if @options[:override]
|
57
57
|
self.alternative = @options[:override]
|
58
|
-
elsif @options[:disabled] ||
|
58
|
+
elsif @options[:disabled] || Split.configuration.disabled?
|
59
59
|
self.alternative = @experiment.control
|
60
60
|
elsif @experiment.has_winner?
|
61
61
|
self.alternative = @experiment.winner
|
data/lib/split/version.rb
CHANGED
@@ -35,4 +35,19 @@ describe Split::ExperimentCatalog do
|
|
35
35
|
expect(subject.find_or_create('my_exp', 'control me').control.to_s).to eq('control me')
|
36
36
|
end
|
37
37
|
end
|
38
|
+
|
39
|
+
describe '.find' do
|
40
|
+
it "should return an existing experiment" do
|
41
|
+
experiment = Split::Experiment.new('basket_text', alternatives: ['blue', 'red', 'green'])
|
42
|
+
experiment.save
|
43
|
+
|
44
|
+
experiment = subject.find('basket_text')
|
45
|
+
|
46
|
+
expect(experiment.name).to eq('basket_text')
|
47
|
+
end
|
48
|
+
|
49
|
+
it "should return nil if experiment not exist" do
|
50
|
+
expect(subject.find('non_existent_experiment')).to be_nil
|
51
|
+
end
|
52
|
+
end
|
38
53
|
end
|
data/spec/experiment_spec.rb
CHANGED
@@ -104,18 +104,6 @@ describe Split::Experiment do
|
|
104
104
|
end
|
105
105
|
end
|
106
106
|
|
107
|
-
describe 'find' do
|
108
|
-
it "should return an existing experiment" do
|
109
|
-
experiment.save
|
110
|
-
experiment = Split::ExperimentCatalog.find('basket_text')
|
111
|
-
expect(experiment.name).to eq('basket_text')
|
112
|
-
end
|
113
|
-
|
114
|
-
it "should return an existing experiment" do
|
115
|
-
expect(Split::ExperimentCatalog.find('non_existent_experiment')).to be_nil
|
116
|
-
end
|
117
|
-
end
|
118
|
-
|
119
107
|
describe 'control' do
|
120
108
|
it 'should be the first alternative' do
|
121
109
|
experiment.save
|
@@ -210,6 +198,18 @@ describe Split::Experiment do
|
|
210
198
|
expect(Split.configuration.on_experiment_delete).to receive(:call)
|
211
199
|
experiment.delete
|
212
200
|
end
|
201
|
+
|
202
|
+
it "should call the on_before_experiment_delete hook" do
|
203
|
+
expect(Split.configuration.on_before_experiment_delete).to receive(:call)
|
204
|
+
experiment.delete
|
205
|
+
end
|
206
|
+
|
207
|
+
it 'should reset the start time if the experiment should be manually started' do
|
208
|
+
Split.configuration.start_manually = true
|
209
|
+
experiment.start
|
210
|
+
experiment.delete
|
211
|
+
expect(experiment.start_time).to be_nil
|
212
|
+
end
|
213
213
|
end
|
214
214
|
|
215
215
|
|
@@ -276,6 +276,11 @@ describe Split::Experiment do
|
|
276
276
|
expect(Split.configuration.on_experiment_reset).to receive(:call)
|
277
277
|
experiment.reset
|
278
278
|
end
|
279
|
+
|
280
|
+
it "should call the on_before_experiment_reset hook" do
|
281
|
+
expect(Split.configuration.on_before_experiment_reset).to receive(:call)
|
282
|
+
experiment.reset
|
283
|
+
end
|
279
284
|
end
|
280
285
|
|
281
286
|
describe 'algorithm' do
|
@@ -291,31 +296,38 @@ describe Split::Experiment do
|
|
291
296
|
end
|
292
297
|
end
|
293
298
|
|
294
|
-
describe 'next_alternative' do
|
295
|
-
|
299
|
+
describe '#next_alternative' do
|
300
|
+
context 'with multiple alternatives' do
|
301
|
+
let(:experiment) { Split::ExperimentCatalog.find_or_create('link_color', 'blue', 'red', 'green') }
|
296
302
|
|
297
|
-
|
298
|
-
|
299
|
-
|
303
|
+
context 'with winner' do
|
304
|
+
it "should always return the winner" do
|
305
|
+
green = Split::Alternative.new('green', 'link_color')
|
306
|
+
experiment.winner = 'green'
|
300
307
|
|
301
|
-
|
302
|
-
|
308
|
+
expect(experiment.next_alternative.name).to eq('green')
|
309
|
+
green.increment_participation
|
303
310
|
|
304
|
-
|
305
|
-
|
311
|
+
expect(experiment.next_alternative.name).to eq('green')
|
312
|
+
end
|
313
|
+
end
|
306
314
|
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
315
|
+
context 'without winner' do
|
316
|
+
it "should use the specified algorithm" do
|
317
|
+
experiment.algorithm = Split::Algorithms::Whiplash
|
318
|
+
expect(experiment.algorithm).to receive(:choose_alternative).and_return(Split::Alternative.new('green', 'link_color'))
|
319
|
+
expect(experiment.next_alternative.name).to eq('green')
|
320
|
+
end
|
321
|
+
end
|
311
322
|
end
|
312
|
-
end
|
313
323
|
|
314
|
-
|
315
|
-
|
324
|
+
context 'with single alternative' do
|
325
|
+
let(:experiment) { Split::ExperimentCatalog.find_or_create('link_color', 'blue') }
|
316
326
|
|
317
|
-
|
318
|
-
|
327
|
+
it "should always return the only alternative" do
|
328
|
+
expect(experiment.next_alternative.name).to eq('blue')
|
329
|
+
expect(experiment.next_alternative.name).to eq('blue')
|
330
|
+
end
|
319
331
|
end
|
320
332
|
end
|
321
333
|
|
@@ -432,8 +444,7 @@ describe Split::Experiment do
|
|
432
444
|
|
433
445
|
it "should return nil and not re-calculate probabilities if they have already been calculated today" do
|
434
446
|
experiment = Split::ExperimentCatalog.find_or_create({'link_color3' => ["purchase", "refund"]}, 'blue', 'red', 'green')
|
435
|
-
|
436
|
-
experiment.calc_time = experiment_calc_time
|
447
|
+
expect(experiment.calc_winning_alternatives).not_to be nil
|
437
448
|
expect(experiment.calc_winning_alternatives).to be nil
|
438
449
|
end
|
439
450
|
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'split/goals_collection'
|
3
|
+
require 'time'
|
4
|
+
|
5
|
+
describe Split::GoalsCollection do
|
6
|
+
let(:experiment_name) { 'experiment_name' }
|
7
|
+
|
8
|
+
describe 'initialization' do
|
9
|
+
let(:goals_collection) {
|
10
|
+
Split::GoalsCollection.new('experiment_name', ['goal1', 'goal2'])
|
11
|
+
}
|
12
|
+
|
13
|
+
it "should have an experiment_name" do
|
14
|
+
expect(goals_collection.instance_variable_get(:@experiment_name)).
|
15
|
+
to eq('experiment_name')
|
16
|
+
end
|
17
|
+
|
18
|
+
it "should have a list of goals" do
|
19
|
+
expect(goals_collection.instance_variable_get(:@goals)).
|
20
|
+
to eq(['goal1', 'goal2'])
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
describe "#validate!" do
|
25
|
+
it "should't raise ArgumentError if @goals is nil?" do
|
26
|
+
goals_collection = Split::GoalsCollection.new('experiment_name')
|
27
|
+
expect { goals_collection.validate! }.not_to raise_error(ArgumentError)
|
28
|
+
end
|
29
|
+
|
30
|
+
it "should raise ArgumentError if @goals is not an Array" do
|
31
|
+
goals_collection = Split::GoalsCollection.
|
32
|
+
new('experiment_name', 'not an array')
|
33
|
+
expect { goals_collection.validate! }.to raise_error(ArgumentError)
|
34
|
+
end
|
35
|
+
|
36
|
+
it "should't raise ArgumentError if @goals is an array" do
|
37
|
+
goals_collection = Split::GoalsCollection.
|
38
|
+
new('experiment_name', ['an array'])
|
39
|
+
expect { goals_collection.validate! }.not_to raise_error(ArgumentError)
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
describe "#delete" do
|
44
|
+
let(:goals_key) { "#{experiment_name}:goals" }
|
45
|
+
|
46
|
+
it "should delete goals from redis" do
|
47
|
+
goals_collection = Split::GoalsCollection.new(experiment_name, ['goal1'])
|
48
|
+
goals_collection.save
|
49
|
+
|
50
|
+
goals_collection.delete
|
51
|
+
expect(Split.redis.exists(goals_key)).to be false
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
describe "#save" do
|
56
|
+
let(:goals_key) { "#{experiment_name}:goals" }
|
57
|
+
|
58
|
+
it "should return false if @goals is nil" do
|
59
|
+
goals_collection = Split::GoalsCollection.
|
60
|
+
new(experiment_name, nil)
|
61
|
+
|
62
|
+
expect(goals_collection.save).to be false
|
63
|
+
end
|
64
|
+
|
65
|
+
it "should save goals to redis if @goals is valid" do
|
66
|
+
goals = ['valid goal 1', 'valid goal 2']
|
67
|
+
collection = Split::GoalsCollection.new(experiment_name, goals)
|
68
|
+
collection.save
|
69
|
+
|
70
|
+
expect(Split.redis.lrange(goals_key, 0, -1)).to eq goals
|
71
|
+
end
|
72
|
+
|
73
|
+
it "should return @goals if @goals is valid" do
|
74
|
+
goals_collection = Split::GoalsCollection.
|
75
|
+
new(experiment_name, ['valid goal'])
|
76
|
+
|
77
|
+
expect(goals_collection.save).to eq(['valid goal'])
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
data/split.gemspec
CHANGED
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: 1.4.
|
4
|
+
version: 1.4.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Andrew Nesbitt
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-04-
|
11
|
+
date: 2016-04-21 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: redis
|
@@ -136,6 +136,20 @@ dependencies:
|
|
136
136
|
- - "~>"
|
137
137
|
- !ruby/object:Gem::Version
|
138
138
|
version: '3.4'
|
139
|
+
- !ruby/object:Gem::Dependency
|
140
|
+
name: pry
|
141
|
+
requirement: !ruby/object:Gem::Requirement
|
142
|
+
requirements:
|
143
|
+
- - "~>"
|
144
|
+
- !ruby/object:Gem::Version
|
145
|
+
version: '0.10'
|
146
|
+
type: :development
|
147
|
+
prerelease: false
|
148
|
+
version_requirements: !ruby/object:Gem::Requirement
|
149
|
+
requirements:
|
150
|
+
- - "~>"
|
151
|
+
- !ruby/object:Gem::Version
|
152
|
+
version: '0.10'
|
139
153
|
description:
|
140
154
|
email:
|
141
155
|
- andrewnez@gmail.com
|
@@ -181,6 +195,7 @@ files:
|
|
181
195
|
- lib/split/extensions.rb
|
182
196
|
- lib/split/extensions/array.rb
|
183
197
|
- lib/split/extensions/string.rb
|
198
|
+
- lib/split/goals_collection.rb
|
184
199
|
- lib/split/helper.rb
|
185
200
|
- lib/split/metric.rb
|
186
201
|
- lib/split/persistence.rb
|
@@ -199,6 +214,7 @@ files:
|
|
199
214
|
- spec/encapsulated_helper_spec.rb
|
200
215
|
- spec/experiment_catalog_spec.rb
|
201
216
|
- spec/experiment_spec.rb
|
217
|
+
- spec/goals_collection_spec.rb
|
202
218
|
- spec/helper_spec.rb
|
203
219
|
- spec/metric_spec.rb
|
204
220
|
- spec/persistence/cookie_adapter_spec.rb
|
@@ -243,6 +259,7 @@ test_files:
|
|
243
259
|
- spec/encapsulated_helper_spec.rb
|
244
260
|
- spec/experiment_catalog_spec.rb
|
245
261
|
- spec/experiment_spec.rb
|
262
|
+
- spec/goals_collection_spec.rb
|
246
263
|
- spec/helper_spec.rb
|
247
264
|
- spec/metric_spec.rb
|
248
265
|
- spec/persistence/cookie_adapter_spec.rb
|