ablab 0.3.0 → 0.4.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/lib/ablab.rb +47 -11
- data/lib/ablab/version.rb +1 -1
- data/spec/ablab_spec.rb +74 -10
- 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: aa8125e2a869a953786f4b1bcacab2ac1752d00c
|
4
|
+
data.tar.gz: c661d695bcad5f817801b42aa1e4ffc99920d346
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7f459d5d133435d8c828d0626c0846575c3eb49d941fb21bb430cb1c91853162f5ff82fe89c2c49df0e2ace5eafcc1eba65adcd05865e6e84fcb875de792848d
|
7
|
+
data.tar.gz: 2a9e3c91a04cec5ee3691604b806dce7b53c4cf3871ee1dea791033326f16f0be0f13475ac507f4ece116e858adedf0537fbbb645baaaf671e33a8204587ca88
|
data/lib/ablab.rb
CHANGED
@@ -76,7 +76,7 @@ module Ablab
|
|
76
76
|
|
77
77
|
def initialize(name, &block)
|
78
78
|
@name = name.to_sym
|
79
|
-
@control = Group.
|
79
|
+
@control = Group.control
|
80
80
|
@groups = [@control]
|
81
81
|
@callbacks = []
|
82
82
|
instance_exec(&block)
|
@@ -98,7 +98,7 @@ module Ablab
|
|
98
98
|
end
|
99
99
|
|
100
100
|
def group(name, options = {})
|
101
|
-
group = Group.new(name, options[:description])
|
101
|
+
group = Group.new(name, options[:description], options[:weight])
|
102
102
|
@groups << group
|
103
103
|
end
|
104
104
|
|
@@ -137,17 +137,23 @@ module Ablab
|
|
137
137
|
|
138
138
|
def group
|
139
139
|
return @group unless @group.nil?
|
140
|
-
forced = forced_group
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
140
|
+
if forced = forced_group
|
141
|
+
return forced
|
142
|
+
end
|
143
|
+
d = draw / experiment.percentage_of_visitors
|
144
|
+
return nil if d >= 1
|
145
|
+
tot_weight = experiment.groups.map(&:weight).reduce(:+).to_f
|
146
|
+
@group = experiment.groups.reduce(0) do |t, group|
|
147
|
+
t += group.weight / tot_weight
|
148
|
+
break group if d < t
|
149
|
+
t
|
150
|
+
end
|
145
151
|
end
|
146
152
|
|
147
153
|
def draw
|
148
154
|
sid_hash = Digest::SHA1.hexdigest(session_id)[-8..-1].to_i(16)
|
149
155
|
exp_hash = Digest::SHA1.hexdigest(experiment.name.to_s)[-8..-1].to_i(16)
|
150
|
-
(sid_hash ^ exp_hash) % 1000
|
156
|
+
((sid_hash ^ exp_hash) % 1000) / 10.0
|
151
157
|
end
|
152
158
|
|
153
159
|
def perform_callbacks!(event)
|
@@ -165,7 +171,7 @@ module Ablab
|
|
165
171
|
return nil unless request && request.respond_to?(:params)
|
166
172
|
groups = parse_groups(request.params[:ablab_group])
|
167
173
|
group = groups[experiment.name.to_s]
|
168
|
-
|
174
|
+
experiment.groups.find { |g| g == group }
|
169
175
|
end
|
170
176
|
|
171
177
|
private def parse_groups(str)
|
@@ -195,9 +201,39 @@ module Ablab
|
|
195
201
|
end
|
196
202
|
|
197
203
|
class Group
|
198
|
-
attr_reader :name, :description
|
199
|
-
|
204
|
+
attr_reader :name, :description, :weight
|
205
|
+
alias_method :eql?, :==
|
206
|
+
def initialize(name, description = nil, weight = nil)
|
200
207
|
@name, @description = name.to_sym, description
|
208
|
+
@weight = weight || 1
|
209
|
+
end
|
210
|
+
|
211
|
+
def control?
|
212
|
+
name == :control
|
213
|
+
end
|
214
|
+
|
215
|
+
def experimental?
|
216
|
+
!control?
|
217
|
+
end
|
218
|
+
|
219
|
+
def ==(o)
|
220
|
+
if o.is_a?(Symbol)
|
221
|
+
name == o
|
222
|
+
elsif o.is_a?(String)
|
223
|
+
name.to_s == o
|
224
|
+
elsif o.is_a?(self.class)
|
225
|
+
name == o.name && description == o.description
|
226
|
+
else
|
227
|
+
false
|
228
|
+
end
|
229
|
+
end
|
230
|
+
|
231
|
+
def hash
|
232
|
+
name.hash
|
233
|
+
end
|
234
|
+
|
235
|
+
def self.control
|
236
|
+
new(:control, 'control group')
|
201
237
|
end
|
202
238
|
end
|
203
239
|
|
data/lib/ablab/version.rb
CHANGED
data/spec/ablab_spec.rb
CHANGED
@@ -186,10 +186,26 @@ describe Ablab do
|
|
186
186
|
allow(run).to receive(:draw).and_return 0
|
187
187
|
expect(run).to be_in_group(:control)
|
188
188
|
run = Ablab::Run.new(experiment, 'abc', request)
|
189
|
-
allow(run).to receive(:draw).and_return
|
189
|
+
allow(run).to receive(:draw).and_return 33.4
|
190
190
|
expect(run).to be_in_group(:a)
|
191
191
|
run = Ablab::Run.new(experiment, 'abc', request)
|
192
|
-
allow(run).to receive(:draw).and_return
|
192
|
+
allow(run).to receive(:draw).and_return 99.9
|
193
|
+
expect(run).to be_in_group(:b)
|
194
|
+
end
|
195
|
+
|
196
|
+
it 'respects group weights' do
|
197
|
+
experiment = Ablab::Experiment.new(:foo) do
|
198
|
+
group :a
|
199
|
+
group :b, weight: 2
|
200
|
+
end
|
201
|
+
run = Ablab::Run.new(experiment, 'abc', request)
|
202
|
+
allow(run).to receive(:draw).and_return 24.0
|
203
|
+
expect(run).to be_in_group(:control)
|
204
|
+
run = Ablab::Run.new(experiment, 'abc', request)
|
205
|
+
allow(run).to receive(:draw).and_return 25.0
|
206
|
+
expect(run).to be_in_group(:a)
|
207
|
+
run = Ablab::Run.new(experiment, 'abc', request)
|
208
|
+
allow(run).to receive(:draw).and_return 50.0
|
193
209
|
expect(run).to be_in_group(:b)
|
194
210
|
end
|
195
211
|
|
@@ -202,16 +218,16 @@ describe Ablab do
|
|
202
218
|
it 'selects only the given percentage of users' do
|
203
219
|
experiment.percentage_of_visitors 30
|
204
220
|
run = Ablab::Run.new(experiment, 'abc', request)
|
205
|
-
allow(run).to receive(:draw).and_return 0
|
221
|
+
allow(run).to receive(:draw).and_return 0.0
|
206
222
|
expect(run).to be_in_group(:control)
|
207
223
|
run = Ablab::Run.new(experiment, 'abc', request)
|
208
|
-
allow(run).to receive(:draw).and_return
|
224
|
+
allow(run).to receive(:draw).and_return 10.0
|
209
225
|
expect(run).to be_in_group(:a)
|
210
226
|
run = Ablab::Run.new(experiment, 'abc', request)
|
211
|
-
allow(run).to receive(:draw).and_return
|
227
|
+
allow(run).to receive(:draw).and_return 20.0
|
212
228
|
expect(run).to be_in_group(:b)
|
213
229
|
run = Ablab::Run.new(experiment, 'abc', request)
|
214
|
-
allow(run).to receive(:draw).and_return
|
230
|
+
allow(run).to receive(:draw).and_return 30.0
|
215
231
|
expect(run.group).to be_nil
|
216
232
|
end
|
217
233
|
|
@@ -220,25 +236,26 @@ describe Ablab do
|
|
220
236
|
d1 = Ablab::Run.new(experiment, '8asd7f8asf7', request).draw
|
221
237
|
dir = File.expand_path(File.dirname(__FILE__), '../lib')
|
222
238
|
d2 = `bundle exec ruby -I#{dir} -e "require 'ablab'; require 'ostruct'; puts Ablab::Run.new(OpenStruct.new(name: :foo), '8asd7f8asf7', nil).draw"`
|
223
|
-
expect(d1).to eq(d2.
|
239
|
+
expect(d1).to eq(d2.to_f)
|
224
240
|
end
|
225
241
|
|
226
|
-
it "returns an
|
242
|
+
it "returns an float number < 100" do
|
227
243
|
expect(
|
228
|
-
(0..100).map { |i| Ablab::Run.new(experiment, "#{i}", request).draw }.all? { |x| x.is_a?(
|
244
|
+
(0..100).map { |i| Ablab::Run.new(experiment, "#{i}", request).draw }.all? { |x| x.is_a?(Float) && x < 100 }
|
229
245
|
).to be(true)
|
230
246
|
end
|
231
247
|
end
|
232
248
|
|
233
249
|
describe "#group" do
|
234
250
|
it "returns one of the groups" do
|
235
|
-
expect(Ablab::Run.new(experiment, rand(12345).to_s, request).group)
|
251
|
+
expect([:a, :b, :control]).to include(Ablab::Run.new(experiment, rand(12345).to_s, request).group)
|
236
252
|
end
|
237
253
|
|
238
254
|
it "returns the forced group, if set with the 'ablab_group' param" do
|
239
255
|
params = { ablab_group: 'bar:baz,foo:a' }
|
240
256
|
allow(request).to receive(:params).and_return(params)
|
241
257
|
run = Ablab::Run.new(experiment, '6q5wed', request)
|
258
|
+
expect(run.group).to be_a(Ablab::Group)
|
242
259
|
expect(run.group).to eq(:a)
|
243
260
|
end
|
244
261
|
end
|
@@ -341,4 +358,51 @@ describe Ablab do
|
|
341
358
|
end
|
342
359
|
end
|
343
360
|
end
|
361
|
+
|
362
|
+
describe Ablab::Group do
|
363
|
+
let(:control_group) { Ablab::Group.new(:control, "control group") }
|
364
|
+
let(:experimental_group) { Ablab::Group.new(:foo, "foo group") }
|
365
|
+
|
366
|
+
describe "#control?" do
|
367
|
+
it 'is true for the control group' do
|
368
|
+
expect(control_group.control?).to be true
|
369
|
+
end
|
370
|
+
|
371
|
+
it 'is false for other groups' do
|
372
|
+
expect(experimental_group.control?).to be false
|
373
|
+
end
|
374
|
+
end
|
375
|
+
|
376
|
+
describe "#experimental?" do
|
377
|
+
it 'is false for the control group' do
|
378
|
+
expect(control_group.experimental?).to be false
|
379
|
+
end
|
380
|
+
|
381
|
+
it 'is true for other groups' do
|
382
|
+
expect(experimental_group.experimental?).to be true
|
383
|
+
end
|
384
|
+
end
|
385
|
+
|
386
|
+
describe "#==" do
|
387
|
+
it 'accepts comparison to Symbol instances' do
|
388
|
+
expect(control_group).to eq(:control)
|
389
|
+
expect(control_group).not_to eq(:foo)
|
390
|
+
end
|
391
|
+
|
392
|
+
it 'accepts comparison to String instances' do
|
393
|
+
expect(control_group).to eq('control')
|
394
|
+
expect(control_group).not_to eq('foo')
|
395
|
+
end
|
396
|
+
|
397
|
+
it 'accepts comparison to Ablab::Group instances' do
|
398
|
+
expect(control_group).to eq(control_group)
|
399
|
+
expect(control_group).to eq(Ablab::Group.new(:control, "control group"))
|
400
|
+
expect(control_group).not_to eq(experimental_group)
|
401
|
+
end
|
402
|
+
|
403
|
+
it 'is false for everyhing else' do
|
404
|
+
expect(control_group).not_to eq(Object.new)
|
405
|
+
end
|
406
|
+
end
|
407
|
+
end
|
344
408
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ablab
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Luca Ongaro
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-
|
11
|
+
date: 2016-05-18 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|