verdict 0.6.3 → 0.7.0
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 +7 -0
- data/lib/verdict/experiment.rb +14 -6
- data/lib/verdict/version.rb +1 -1
- data/test/experiment_test.rb +81 -14
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a1929eb3266514c557ec595e7fa7f80065a1b600
|
4
|
+
data.tar.gz: 1f34b0ad26c876f348649ad04d96a9f0c077ea48
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 63801e6ec63ae74dcb33c418090fec977a4598e23da4ff6bc642e2041025915f5ea8eda536ff7c5415dfd18106d1dc1c1fe339b6901b26663b70bfcad4d8803f
|
7
|
+
data.tar.gz: 982e62386331ba13174d3e758a9624ba76b80e45e30ba59f788c65a239585a74abd6386f79622e0dd7314328c0e7843852a01bb6a4b4f7597f6b1d3618f99644
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,10 @@
|
|
1
|
+
## v0.7.0
|
2
|
+
**This version has breaking changes**
|
3
|
+
|
4
|
+
* Experiment can now specify multiple qualify blocks
|
5
|
+
* `Verdict::Experiment#qualifier` has been removed in favor for `Verdict::Experiment#qualifiers`, which returns an array of procs
|
6
|
+
* Allow pass of an argument to qualify with a method name as a symbol, instead of a block
|
7
|
+
|
1
8
|
## v0.6.3
|
2
9
|
|
3
10
|
* Fix bug were Verdict.directory is overwritten
|
data/lib/verdict/experiment.rb
CHANGED
@@ -2,7 +2,7 @@ class Verdict::Experiment
|
|
2
2
|
|
3
3
|
include Verdict::Metadata
|
4
4
|
|
5
|
-
attr_reader :handle, :
|
5
|
+
attr_reader :handle, :qualifiers, :storage, :event_logger
|
6
6
|
|
7
7
|
def self.define(handle, *args, &block)
|
8
8
|
experiment = self.new(handle, *args, &block)
|
@@ -14,7 +14,7 @@ class Verdict::Experiment
|
|
14
14
|
@handle = handle.to_s
|
15
15
|
|
16
16
|
options = default_options.merge(options)
|
17
|
-
@
|
17
|
+
@qualifiers = Array(options[:qualifier] || options[:qualifiers])
|
18
18
|
@event_logger = options[:event_logger] || Verdict::EventLogger.new(Verdict.default_logger)
|
19
19
|
@storage = storage(options[:storage] || :memory)
|
20
20
|
@store_unqualified = options[:store_unqualified]
|
@@ -58,8 +58,16 @@ class Verdict::Experiment
|
|
58
58
|
end
|
59
59
|
end
|
60
60
|
|
61
|
-
def qualify(&block)
|
62
|
-
|
61
|
+
def qualify(method_name = nil, &block)
|
62
|
+
if block_given?
|
63
|
+
@qualifiers << block
|
64
|
+
elsif method_name.nil?
|
65
|
+
raise ArgumentError, "no method nor blocked passed!"
|
66
|
+
elsif respond_to?(method_name, true)
|
67
|
+
@qualifiers << method(method_name).to_proc
|
68
|
+
else
|
69
|
+
raise ArgumentError, "No helper for #{method_name.inspect}"
|
70
|
+
end
|
63
71
|
end
|
64
72
|
|
65
73
|
def storage(storage = nil, options = {})
|
@@ -169,7 +177,7 @@ class Verdict::Experiment
|
|
169
177
|
end
|
170
178
|
|
171
179
|
def has_qualifier?
|
172
|
-
|
180
|
+
@qualifiers.any?
|
173
181
|
end
|
174
182
|
|
175
183
|
def everybody_qualifies?
|
@@ -204,7 +212,7 @@ class Verdict::Experiment
|
|
204
212
|
|
205
213
|
def subject_qualifies?(subject, context = nil)
|
206
214
|
ensure_experiment_has_started
|
207
|
-
everybody_qualifies? || @qualifier.call(subject, context)
|
215
|
+
everybody_qualifies? || @qualifiers.all? { |qualifier| qualifier.call(subject, context) }
|
208
216
|
end
|
209
217
|
|
210
218
|
protected
|
data/lib/verdict/version.rb
CHANGED
data/test/experiment_test.rb
CHANGED
@@ -5,7 +5,7 @@ class ExperimentTest < Minitest::Test
|
|
5
5
|
|
6
6
|
def test_no_qualifier
|
7
7
|
e = Verdict::Experiment.new('test')
|
8
|
-
|
8
|
+
refute e.has_qualifier?
|
9
9
|
assert e.everybody_qualifies?
|
10
10
|
end
|
11
11
|
|
@@ -18,14 +18,14 @@ class ExperimentTest < Minitest::Test
|
|
18
18
|
end
|
19
19
|
|
20
20
|
assert e.has_qualifier?
|
21
|
-
|
21
|
+
refute e.everybody_qualifies?
|
22
22
|
|
23
23
|
subject_stub = Struct.new(:id, :country)
|
24
24
|
ca_subject = subject_stub.new(1, 'CA')
|
25
25
|
us_subject = subject_stub.new(1, 'US')
|
26
26
|
|
27
|
-
assert e.
|
28
|
-
|
27
|
+
assert e.qualifiers.all? { |q| q.call(ca_subject) }
|
28
|
+
refute e.qualifiers.all? { |q| q.call(us_subject) }
|
29
29
|
|
30
30
|
qualified = e.assign(ca_subject)
|
31
31
|
assert_kind_of Verdict::Assignment, qualified
|
@@ -33,7 +33,74 @@ class ExperimentTest < Minitest::Test
|
|
33
33
|
|
34
34
|
non_qualified = e.assign(us_subject)
|
35
35
|
assert_kind_of Verdict::Assignment, non_qualified
|
36
|
-
|
36
|
+
refute non_qualified.qualified?
|
37
|
+
assert_equal nil, non_qualified.group
|
38
|
+
end
|
39
|
+
|
40
|
+
def test_multiple_qualifier
|
41
|
+
e = Verdict::Experiment.new('test') do |experiment|
|
42
|
+
qualify { |subject| subject.language == 'fr' }
|
43
|
+
qualify { |subject| subject.country == 'CA' }
|
44
|
+
|
45
|
+
groups do
|
46
|
+
group :all, 100
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
assert e.has_qualifier?
|
51
|
+
refute e.everybody_qualifies?
|
52
|
+
|
53
|
+
subject_stub = Struct.new(:id, :country, :language)
|
54
|
+
fr_subject = subject_stub.new(1, 'CA', 'fr')
|
55
|
+
en_subject = subject_stub.new(2, 'CA', 'en')
|
56
|
+
|
57
|
+
assert e.qualifiers.all? { |q| q.call(fr_subject) }
|
58
|
+
refute e.qualifiers.all? { |q| q.call(en_subject) }
|
59
|
+
|
60
|
+
qualified = e.assign(fr_subject)
|
61
|
+
assert_kind_of Verdict::Assignment, qualified
|
62
|
+
assert_equal e.group(:all), qualified.group
|
63
|
+
|
64
|
+
non_qualified = e.assign(en_subject)
|
65
|
+
assert_kind_of Verdict::Assignment, non_qualified
|
66
|
+
refute non_qualified.qualified?
|
67
|
+
assert_equal nil, non_qualified.group
|
68
|
+
end
|
69
|
+
|
70
|
+
module CountryIsCanadaHelper
|
71
|
+
def country_is_canada(subject, _context)
|
72
|
+
subject.country == 'CA'
|
73
|
+
end
|
74
|
+
end
|
75
|
+
def test_method_qualifier
|
76
|
+
|
77
|
+
e = Verdict::Experiment.new('test') do |experiment|
|
78
|
+
extend CountryIsCanadaHelper
|
79
|
+
|
80
|
+
qualify :country_is_canada
|
81
|
+
|
82
|
+
groups do
|
83
|
+
group :all, 100
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
assert e.has_qualifier?
|
88
|
+
refute e.everybody_qualifies?
|
89
|
+
|
90
|
+
subject_stub = Struct.new(:id, :country)
|
91
|
+
ca_subject = subject_stub.new(1, 'CA')
|
92
|
+
us_subject = subject_stub.new(1, 'US')
|
93
|
+
|
94
|
+
assert e.qualifiers.all? { |q| q.call(ca_subject, nil) }
|
95
|
+
refute e.qualifiers.all? { |q| q.call(us_subject, nil) }
|
96
|
+
|
97
|
+
qualified = e.assign(ca_subject)
|
98
|
+
assert_kind_of Verdict::Assignment, qualified
|
99
|
+
assert_equal e.group(:all), qualified.group
|
100
|
+
|
101
|
+
non_qualified = e.assign(us_subject)
|
102
|
+
assert_kind_of Verdict::Assignment, non_qualified
|
103
|
+
refute non_qualified.qualified?
|
37
104
|
assert_equal nil, non_qualified.group
|
38
105
|
end
|
39
106
|
|
@@ -45,7 +112,7 @@ class ExperimentTest < Minitest::Test
|
|
45
112
|
end
|
46
113
|
end
|
47
114
|
|
48
|
-
|
115
|
+
refute e.assign(nil).qualified?
|
49
116
|
assert_equal nil, e.convert('', :mygoal)
|
50
117
|
end
|
51
118
|
|
@@ -63,12 +130,12 @@ class ExperimentTest < Minitest::Test
|
|
63
130
|
assignment = e.assign(1)
|
64
131
|
assert_kind_of Verdict::Assignment, assignment
|
65
132
|
assert assignment.qualified?
|
66
|
-
|
133
|
+
refute assignment.returning?
|
67
134
|
assert_equal assignment.group, e.group(:a)
|
68
135
|
|
69
136
|
assignment = e.assign(3)
|
70
137
|
assert_kind_of Verdict::Assignment, assignment
|
71
|
-
|
138
|
+
refute assignment.qualified?
|
72
139
|
|
73
140
|
assert_equal :a, e.switch(1)
|
74
141
|
assert_equal :b, e.switch(2)
|
@@ -175,7 +242,7 @@ class ExperimentTest < Minitest::Test
|
|
175
242
|
original_assignment = e.assign(subject)
|
176
243
|
assert original_assignment.qualified?
|
177
244
|
new_assignment = e.disqualify_manually(subject)
|
178
|
-
|
245
|
+
refute new_assignment.qualified?
|
179
246
|
end
|
180
247
|
|
181
248
|
def test_disqualify_manually_fails_with_store_unqualified_disabled
|
@@ -212,7 +279,7 @@ class ExperimentTest < Minitest::Test
|
|
212
279
|
mock_store.expects(:store_assignment).never
|
213
280
|
|
214
281
|
assignment = e.assign(mock('subject'))
|
215
|
-
|
282
|
+
refute assignment.qualified?
|
216
283
|
end
|
217
284
|
|
218
285
|
def test_assignment_event_logging
|
@@ -273,7 +340,7 @@ class ExperimentTest < Minitest::Test
|
|
273
340
|
|
274
341
|
storage_mock.stubs(:retrieve_assignment).raises(Verdict::StorageError, 'storage read issues')
|
275
342
|
rescued_assignment = e.assign(stub(id: 123))
|
276
|
-
|
343
|
+
refute rescued_assignment.qualified?
|
277
344
|
end
|
278
345
|
|
279
346
|
def test_storage_write_failure
|
@@ -286,7 +353,7 @@ class ExperimentTest < Minitest::Test
|
|
286
353
|
storage_mock.expects(:retrieve_assignment).returns(e.subject_assignment(mock('subject_identifier'), e.group(:all), nil))
|
287
354
|
storage_mock.expects(:store_assignment).raises(Verdict::StorageError, 'storage write issues')
|
288
355
|
rescued_assignment = e.assign(stub(id: 456))
|
289
|
-
|
356
|
+
refute rescued_assignment.qualified?
|
290
357
|
end
|
291
358
|
|
292
359
|
def test_initial_started_at
|
@@ -328,7 +395,7 @@ class ExperimentTest < Minitest::Test
|
|
328
395
|
end
|
329
396
|
|
330
397
|
subject = stub(id: 'old', created_at: Time.new(2011))
|
331
|
-
|
398
|
+
refute e.assign(subject).qualified?
|
332
399
|
|
333
400
|
subject = stub(id: 'new', created_at: Time.new(2013))
|
334
401
|
assert e.assign(subject).qualified?
|
@@ -340,7 +407,7 @@ class ExperimentTest < Minitest::Test
|
|
340
407
|
groups { group :all, 100 }
|
341
408
|
end
|
342
409
|
|
343
|
-
|
410
|
+
refute e.started?, "The experiment should not have started yet"
|
344
411
|
|
345
412
|
e.assign(stub(id: '123'))
|
346
413
|
assert e.started?, "The experiment should have started after the first assignment"
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: verdict
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.7.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Shopify
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-
|
11
|
+
date: 2017-06-28 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: minitest
|