verdict 0.6.3 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: a92b885958acdb2076598cf696dcd91c8a2247a9
4
- data.tar.gz: 942c8fca6745450639522b541f703d01ef3dab3f
3
+ metadata.gz: a1929eb3266514c557ec595e7fa7f80065a1b600
4
+ data.tar.gz: 1f34b0ad26c876f348649ad04d96a9f0c077ea48
5
5
  SHA512:
6
- metadata.gz: 6d7a2547e02b9e07864a0c26d74d244033d21e5ad8eaabf4aed09b92e1d356cc34aea7a70a4fd16271d740ff5393a3d1c13ebe940ceb7e56ea544ef3316b90bb
7
- data.tar.gz: f3d02419590bd341634b7946282aab584daf19db6d6fa7718425b8565d239b227906c3ef0354c17a253cb2f956f2a25c63b6bb4150a93323865f8b8ebcbbcf91
6
+ metadata.gz: 63801e6ec63ae74dcb33c418090fec977a4598e23da4ff6bc642e2041025915f5ea8eda536ff7c5415dfd18106d1dc1c1fe339b6901b26663b70bfcad4d8803f
7
+ data.tar.gz: 982e62386331ba13174d3e758a9624ba76b80e45e30ba59f788c65a239585a74abd6386f79622e0dd7314328c0e7843852a01bb6a4b4f7597f6b1d3618f99644
@@ -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
@@ -2,7 +2,7 @@ class Verdict::Experiment
2
2
 
3
3
  include Verdict::Metadata
4
4
 
5
- attr_reader :handle, :qualifier, :storage, :event_logger
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
- @qualifier = options[:qualifier]
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
- @qualifier = block
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
- !@qualifier.nil?
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
@@ -1,3 +1,3 @@
1
1
  module Verdict
2
- VERSION = "0.6.3"
2
+ VERSION = "0.7.0"
3
3
  end
@@ -5,7 +5,7 @@ class ExperimentTest < Minitest::Test
5
5
 
6
6
  def test_no_qualifier
7
7
  e = Verdict::Experiment.new('test')
8
- assert !e.has_qualifier?
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
- assert !e.everybody_qualifies?
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.qualifier.call(ca_subject)
28
- assert !e.qualifier.call(us_subject)
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
- assert !non_qualified.qualified?
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
- assert !e.assign(nil).qualified?
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
- assert !assignment.returning?
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
- assert !assignment.qualified?
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
- assert !new_assignment.qualified?
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
- assert !assignment.qualified?
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
- assert !rescued_assignment.qualified?
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
- assert !rescued_assignment.qualified?
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
- assert !e.assign(subject).qualified?
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
- assert !e.started?, "The experiment should not have started yet"
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.6.3
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-04-19 00:00:00.000000000 Z
11
+ date: 2017-06-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: minitest