ablab 0.3.0 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|