divisio 0.1.0 → 0.2.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/.rubocop.yml +8 -0
- data/Gemfile +0 -9
- data/README.md +1 -1
- data/divisio.gemspec +6 -2
- data/lib/divisio.rb +0 -1
- data/lib/divisio/base_adapter.rb +2 -2
- data/lib/divisio/modulo_algorithm.rb +0 -1
- data/lib/divisio/mongoid_adapter.rb +1 -1
- data/lib/divisio/mongoid_adapter/experiment.rb +1 -3
- data/lib/divisio/version.rb +1 -1
- data/mongoid.yml +1 -3
- data/spec/divisio/base_adapter_spec.rb +0 -1
- data/spec/divisio/modulo_algorithm_spec.rb +4 -4
- data/spec/divisio/mongoid_adapter/experiment_spec.rb +8 -10
- data/spec/divisio/mongoid_adapter_spec.rb +3 -5
- data/spec/divisio/no_persistence_adapter_spec.rb +0 -1
- data/spec/spec_helper.rb +2 -2
- data/spec/support/shared_examples_for_base_adapter.rb +2 -3
- metadata +47 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: cd36702ea18fb40ba9952362c384f24cb0a41da1
|
4
|
+
data.tar.gz: 6a12c149173875cf9d9cade5705c447f114dd792
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 70781a34c9383b36b4e68b7cf2bc12af388cfb8db71a92ba3b97c6d4686a258bfafe823f449bff2e12fcd595b6242538cc253130ac550715e41e239b637bae7a
|
7
|
+
data.tar.gz: f038c089575bbb2ed3b61f0024f35c25a928a7f8a543f9ec69d3de647d3e1a0bc93ffbeda957f52b57a70084fc07535408251ffd7d17f82574629ad247b21769
|
data/.rubocop.yml
ADDED
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -43,7 +43,7 @@ Divisio.new.split(experiment_name, variants, identity) # ==>> 1
|
|
43
43
|
|
44
44
|
### Mongoid adaper
|
45
45
|
|
46
|
-
_Requires mongoid
|
46
|
+
_Requires mongoid v5.0.0 or greater_
|
47
47
|
|
48
48
|
This adapter will persist the experiment name, identifier, and variant information in a MongoDb collection called `experiments`. Note: The variant returned will be cast to a string.
|
49
49
|
|
data/divisio.gemspec
CHANGED
@@ -8,8 +8,8 @@ Gem::Specification.new do |spec|
|
|
8
8
|
spec.version = Divisio::VERSION
|
9
9
|
spec.authors = ['Dragos Miron']
|
10
10
|
spec.email = ['tech@simplybusiness.co.uk']
|
11
|
-
spec.summary =
|
12
|
-
spec.description =
|
11
|
+
spec.summary = 'Provides a splitting framework similar to AB testing'
|
12
|
+
spec.description = 'Provides a splitting framework similar to AB testing'
|
13
13
|
spec.homepage = 'http://www.simplybusiness.co.uk'
|
14
14
|
spec.license = 'MIT'
|
15
15
|
|
@@ -17,4 +17,8 @@ Gem::Specification.new do |spec|
|
|
17
17
|
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
18
|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
19
|
spec.require_paths = ['lib']
|
20
|
+
|
21
|
+
spec.add_development_dependency 'mongoid', '~> 6.0'
|
22
|
+
spec.add_development_dependency 'rspec', '~> 3.5'
|
23
|
+
spec.add_development_dependency 'rubocop', '~> 0.46'
|
20
24
|
end
|
data/lib/divisio.rb
CHANGED
data/lib/divisio/base_adapter.rb
CHANGED
@@ -3,10 +3,10 @@ class Divisio
|
|
3
3
|
extend self
|
4
4
|
|
5
5
|
def split(experiment_name, variants, identity)
|
6
|
-
ModuloAlgorithm.new(experiment_name.to_s+identity.to_s, variants).calc
|
6
|
+
ModuloAlgorithm.new(experiment_name.to_s + identity.to_s, variants).calc
|
7
7
|
end
|
8
8
|
|
9
|
-
def delete_experiment_for_identity(
|
9
|
+
def delete_experiment_for_identity(_identity, _experiment_name)
|
10
10
|
raise NotImplementedError
|
11
11
|
end
|
12
12
|
end
|
@@ -1,7 +1,6 @@
|
|
1
1
|
class Divisio
|
2
2
|
module MongoidAdapter
|
3
3
|
class Experiment
|
4
|
-
|
5
4
|
include Mongoid::Document
|
6
5
|
include Mongoid::Timestamps
|
7
6
|
|
@@ -12,8 +11,7 @@ class Divisio
|
|
12
11
|
field :identifier, type: String
|
13
12
|
field :variant, type: String
|
14
13
|
|
15
|
-
index({ name: 1, identifier: 1},
|
16
|
-
|
14
|
+
index({ name: 1, identifier: 1 }, unique: true)
|
17
15
|
end
|
18
16
|
end
|
19
17
|
end
|
data/lib/divisio/version.rb
CHANGED
data/mongoid.yml
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
describe Divisio::ModuloAlgorithm do
|
2
2
|
describe '#calc' do
|
3
|
-
let(:variants) {
|
3
|
+
let(:variants) {}
|
4
4
|
|
5
5
|
context 'when there is one variant provided' do
|
6
6
|
let(:variants) { 1 }
|
@@ -11,9 +11,9 @@ describe Divisio::ModuloAlgorithm do
|
|
11
11
|
end
|
12
12
|
|
13
13
|
context 'when there are multiple variants provided' do
|
14
|
-
let(:variants) {
|
14
|
+
let(:variants) { %w(1 2 3) }
|
15
15
|
|
16
|
-
{ blah8: '1', blah4: '2', blah0: '3'}.each_pair do |key, expected_variant|
|
16
|
+
{ blah8: '1', blah4: '2', blah0: '3' }.each_pair do |key, expected_variant|
|
17
17
|
it "returns the variant based on the key provided: #{key}" do
|
18
18
|
expect(Divisio::ModuloAlgorithm.new(key, variants).calc).to eq(expected_variant)
|
19
19
|
end
|
@@ -23,7 +23,7 @@ describe Divisio::ModuloAlgorithm do
|
|
23
23
|
context 'when there are multiple weighted variants provided' do
|
24
24
|
let(:variants) { { a: 1, b: 2, c: 3 } }
|
25
25
|
|
26
|
-
{ blah8: :a, blah4: :b, blah0: :c}.each_pair do |key, expected_variant|
|
26
|
+
{ blah8: :a, blah4: :b, blah0: :c }.each_pair do |key, expected_variant|
|
27
27
|
it "returns the variant based on the key provided and weight: #{key}" do
|
28
28
|
expect(Divisio::ModuloAlgorithm.new(key, variants).calc).to eq(expected_variant)
|
29
29
|
end
|
@@ -1,36 +1,34 @@
|
|
1
1
|
describe Divisio::MongoidAdapter::Experiment do
|
2
2
|
describe '#save' do
|
3
|
-
|
4
|
-
let(:required_fields) { {:name => 'experiment', :identifier => 'hash', :variant => '2'} }
|
3
|
+
let(:required_fields) { { name: 'experiment', identifier: 'hash', variant: '2' } }
|
5
4
|
subject { Divisio::MongoidAdapter::Experiment.new }
|
6
5
|
|
7
6
|
context 'all fields are present' do
|
8
7
|
it 'gets saved to the database' do
|
9
8
|
subject.attributes = required_fields
|
10
9
|
|
11
|
-
expect{ subject.save }.to change{ described_class.count }.from(0).to(1)
|
10
|
+
expect { subject.save }.to change { described_class.count }.from(0).to(1)
|
12
11
|
end
|
13
12
|
end
|
14
13
|
|
15
14
|
context 'missing fields' do
|
16
15
|
it 'does not get saved if identifier is missing' do
|
17
|
-
subject.attributes = required_fields.tap{ |h| h.delete(:identifier) }
|
16
|
+
subject.attributes = required_fields.tap { |h| h.delete(:identifier) }
|
18
17
|
expect(subject.save).to be_falsey
|
19
18
|
end
|
20
19
|
|
21
20
|
it 'does not get saved if name is missing' do
|
22
|
-
subject.attributes = required_fields.tap{ |h| h.delete(:name) }
|
21
|
+
subject.attributes = required_fields.tap { |h| h.delete(:name) }
|
23
22
|
expect(subject.save).to be_falsey
|
24
23
|
end
|
25
24
|
|
26
25
|
it 'does not get saved if variant is missing' do
|
27
|
-
subject.attributes = required_fields.tap{ |h| h.delete(:variant) }
|
26
|
+
subject.attributes = required_fields.tap { |h| h.delete(:variant) }
|
28
27
|
expect(subject.save).to be_falsey
|
29
28
|
end
|
30
29
|
end
|
31
30
|
|
32
31
|
context 'uniqueness' do
|
33
|
-
|
34
32
|
it 'does not save second object with the same name and identifier' do
|
35
33
|
subject.attributes = required_fields
|
36
34
|
subject.save
|
@@ -39,16 +37,16 @@ describe Divisio::MongoidAdapter::Experiment do
|
|
39
37
|
required_fields[:variant] = '3'
|
40
38
|
new_object = described_class.new(required_fields)
|
41
39
|
|
42
|
-
expect{ new_object.save }.to_not change(described_class, :count)
|
40
|
+
expect { new_object.save }.to_not change(described_class, :count)
|
43
41
|
end
|
44
42
|
|
45
43
|
it 'does not save second object in case of race condition because of mongo index' do
|
46
44
|
described_class.create_indexes
|
47
|
-
Mongoid.
|
45
|
+
Mongoid::Clients.default[:divisio_mongoid_adapter_experiments].insert_one(required_fields)
|
48
46
|
expect(described_class.count).to eq(1)
|
49
47
|
|
50
48
|
collection = described_class.collection
|
51
|
-
expect{collection.
|
49
|
+
expect { collection.insert_one(required_fields) }.to raise_exception(Mongo::Error::OperationFailure)
|
52
50
|
end
|
53
51
|
end
|
54
52
|
end
|
@@ -4,12 +4,11 @@ describe Divisio::MongoidAdapter do
|
|
4
4
|
let(:identity) { 'identity' }
|
5
5
|
|
6
6
|
describe '::split' do
|
7
|
-
subject{ described_class.split(experiment, variants, identity) }
|
7
|
+
subject { described_class.split(experiment, variants, identity) }
|
8
8
|
|
9
9
|
it_behaves_like 'a base adapter'
|
10
10
|
|
11
11
|
context 'new record' do
|
12
|
-
|
13
12
|
it 'saves the experiment to the database' do
|
14
13
|
expect_any_instance_of(Divisio::MongoidAdapter::Experiment).to receive(:save)
|
15
14
|
subject
|
@@ -21,7 +20,6 @@ describe Divisio::MongoidAdapter do
|
|
21
20
|
end
|
22
21
|
|
23
22
|
context 'old record' do
|
24
|
-
|
25
23
|
before do
|
26
24
|
Divisio::MongoidAdapter::Experiment.create(name: experiment, identifier: identity, variant: 'random')
|
27
25
|
end
|
@@ -38,7 +36,7 @@ describe Divisio::MongoidAdapter do
|
|
38
36
|
end
|
39
37
|
|
40
38
|
describe '::delete_experiment_for_identity' do
|
41
|
-
subject{ described_class.delete_experiment_for_identity(identity, experiment) }
|
39
|
+
subject { described_class.delete_experiment_for_identity(identity, experiment) }
|
42
40
|
|
43
41
|
context 'record exists in the database' do
|
44
42
|
before do
|
@@ -46,7 +44,7 @@ describe Divisio::MongoidAdapter do
|
|
46
44
|
end
|
47
45
|
|
48
46
|
it 'deletes the record' do
|
49
|
-
expect{subject}.to change { Divisio::MongoidAdapter::Experiment.count }.from(1).to(0)
|
47
|
+
expect { subject }.to change { Divisio::MongoidAdapter::Experiment.count }.from(1).to(0)
|
50
48
|
end
|
51
49
|
|
52
50
|
it 'returns true' do
|
data/spec/spec_helper.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
ENV['RACK_ENV'] = 'test'
|
2
2
|
|
3
|
-
Dir['./spec/support/**/*.rb'].sort.each { |f| require f}
|
3
|
+
Dir['./spec/support/**/*.rb'].sort.each { |f| require f }
|
4
4
|
|
5
5
|
require 'mongoid'
|
6
6
|
require 'divisio'
|
@@ -9,6 +9,6 @@ Mongoid.load!('mongoid.yml')
|
|
9
9
|
|
10
10
|
RSpec.configure do |config|
|
11
11
|
config.before(:each) do
|
12
|
-
Mongoid
|
12
|
+
Mongoid.purge!
|
13
13
|
end
|
14
14
|
end
|
@@ -1,10 +1,9 @@
|
|
1
1
|
shared_examples_for 'a base adapter' do
|
2
|
-
|
3
2
|
describe '::split' do
|
4
3
|
let(:experiment) { 'experiment' }
|
5
|
-
let(:variants) {
|
4
|
+
let(:variants) { %w(1 2 3) }
|
6
5
|
let(:identity) { 'identity' }
|
7
|
-
subject{ described_class.split(experiment, variants, identity) }
|
6
|
+
subject { described_class.split(experiment, variants, identity) }
|
8
7
|
|
9
8
|
it 'returns a variant for the given experiment and identity' do
|
10
9
|
expect(subject).to eq('3')
|
metadata
CHANGED
@@ -1,15 +1,57 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: divisio
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Dragos Miron
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
12
|
-
dependencies:
|
11
|
+
date: 2017-01-04 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: mongoid
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '6.0'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '6.0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rspec
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '3.5'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '3.5'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rubocop
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '0.46'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0.46'
|
13
55
|
description: Provides a splitting framework similar to AB testing
|
14
56
|
email:
|
15
57
|
- tech@simplybusiness.co.uk
|
@@ -19,6 +61,7 @@ extra_rdoc_files: []
|
|
19
61
|
files:
|
20
62
|
- ".gitignore"
|
21
63
|
- ".rspec"
|
64
|
+
- ".rubocop.yml"
|
22
65
|
- Gemfile
|
23
66
|
- LICENSE.txt
|
24
67
|
- README.md
|
@@ -59,7 +102,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
59
102
|
version: '0'
|
60
103
|
requirements: []
|
61
104
|
rubyforge_project:
|
62
|
-
rubygems_version: 2.
|
105
|
+
rubygems_version: 2.4.5.1
|
63
106
|
signing_key:
|
64
107
|
specification_version: 4
|
65
108
|
summary: Provides a splitting framework similar to AB testing
|
@@ -72,4 +115,3 @@ test_files:
|
|
72
115
|
- spec/divisio_spec.rb
|
73
116
|
- spec/spec_helper.rb
|
74
117
|
- spec/support/shared_examples_for_base_adapter.rb
|
75
|
-
has_rdoc:
|