eenie_meenie 0.1.0 → 0.1.1
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +24 -6
- data/lib/eenie_meenie/assignment.rb +31 -12
- data/lib/eenie_meenie/version.rb +1 -1
- data/test/eenie_meenie/assignment_test.rb +38 -1
- metadata +1 -1
data/README.md
CHANGED
@@ -8,7 +8,7 @@ Installation
|
|
8
8
|
|
9
9
|
EenieMeenie is a Ruby gem, and can be installed using `gem install eenie_meenie` or by adding the following to your application's Gemfile:
|
10
10
|
|
11
|
-
gem 'eenie_meenie', '0.1.
|
11
|
+
gem 'eenie_meenie', '0.1.1'
|
12
12
|
|
13
13
|
Usage
|
14
14
|
-----
|
@@ -19,10 +19,28 @@ Attention! The usage of `EeenieMeenie::Assignment` changed with the release of v
|
|
19
19
|
2. Assign a threshold of "DO NOT CARE" to any group by passing `false` instead of a `Float`
|
20
20
|
3. Tell EeenieMeenie which groups can be assigned by the algorithm. Any group with a threshold should be included here.
|
21
21
|
4. Tell it how to scope the member class (tell it which study, if you're using one member class for all studies)
|
22
|
+
5. Specify the population to be used when calculating whether a group's population threshold has been reached.
|
22
23
|
|
23
24
|
Example Configurations
|
24
25
|
----------------------
|
25
26
|
|
27
|
+
eenie_meenie users can specify the population
|
28
|
+
using the :members option, e.g.
|
29
|
+
|
30
|
+
```ruby
|
31
|
+
EenieMeenie::Assignment.new({
|
32
|
+
member: @some_member,
|
33
|
+
members: MemberClass.where(something).joins(another),
|
34
|
+
groups: ["Experimental", "Control"],
|
35
|
+
group_rules: {
|
36
|
+
"Experimental" => { threshold: 0.51 },
|
37
|
+
"Control" => { threshold: 0.51 }
|
38
|
+
}
|
39
|
+
})
|
40
|
+
```
|
41
|
+
|
42
|
+
Other examples ...
|
43
|
+
|
26
44
|
```ruby
|
27
45
|
# Control: Do not care (chosen manually, if ever)
|
28
46
|
# Experimental A: %50 (randomly assign)
|
@@ -46,12 +64,12 @@ EenieMeenie::Assignment.new({
|
|
46
64
|
# Experimental B: %33.3 (randomly assign)
|
47
65
|
|
48
66
|
EenieMeenie::Assignment.new({
|
49
|
-
groups: ["Control", "Experimental A", "Experimental B"],
|
50
|
-
member: @obj,
|
67
|
+
groups: ["Control", "Experimental A", "Experimental B"], # EenieMeenie's assignment options
|
68
|
+
member: @obj, # Member of population
|
51
69
|
group_rules: {
|
52
|
-
"Control" => { threshold: (1.0 / 3.0) },
|
53
|
-
"Experimental A" => { threshold: (1.0 / 3.0) },
|
54
|
-
"Experimental B" => { threshold: (1.0 / 3.0) }
|
70
|
+
"Control" => { threshold: (1.0 / 3.0) }, # No more than one-third
|
71
|
+
"Experimental A" => { threshold: (1.0 / 3.0) }, # No more than one-third
|
72
|
+
"Experimental B" => { threshold: (1.0 / 3.0) } # No more than one-third
|
55
73
|
},
|
56
74
|
class_rules: { organization_id: 1} # Only consider members belonging to Organization 1
|
57
75
|
}).execute!
|
@@ -9,35 +9,54 @@ module EenieMeenie
|
|
9
9
|
end
|
10
10
|
|
11
11
|
def execute!
|
12
|
-
set_group_counts
|
13
|
-
return random_group
|
12
|
+
set_group_counts and return random_group
|
14
13
|
end
|
15
14
|
|
16
15
|
private
|
17
|
-
|
18
|
-
#
|
16
|
+
# eenie_meenie users can specify the population
|
17
|
+
# using the :members option, e.g.
|
18
|
+
# EenieMeenie::Assignment.new({
|
19
|
+
# member: @some_member,
|
20
|
+
# members: MemberClass.where(something).joins(another),
|
21
|
+
# groups: ["Experimental", "Control"],
|
22
|
+
# group_rules: {
|
23
|
+
# "Experimental" => { threshold: 0.51 },
|
24
|
+
# "Control" => { threshold: 0.51 }
|
25
|
+
# }
|
26
|
+
# }).execute!
|
27
|
+
#
|
28
|
+
# By default, eenie_meenie will consider all records
|
29
|
+
# in the provided `:member`s class to be the population.
|
30
|
+
#
|
31
|
+
# If the :class_rules option is given, eenie_meenie will pass
|
32
|
+
# its value on to #where
|
19
33
|
def population
|
20
34
|
@members ||= @member.class.where(@class_rules)
|
21
35
|
end
|
22
36
|
|
23
|
-
#
|
37
|
+
# Add some data to the hash before processing
|
24
38
|
def set_group_counts
|
25
39
|
@group_rules.each do |k,v|
|
26
40
|
v[:count] = population.where(experimental_group: k.to_s).count
|
27
41
|
end
|
28
42
|
end
|
29
43
|
|
30
|
-
#
|
31
|
-
def
|
32
|
-
@
|
33
|
-
|
34
|
-
}.keys
|
44
|
+
# Pick from options whose thresholds have not been reached
|
45
|
+
def candidates
|
46
|
+
@group_rules.select { |k,v|
|
47
|
+
@groups.include?(k) && !busts_threshold?(k)
|
48
|
+
}.keys
|
49
|
+
end
|
35
50
|
|
36
|
-
|
51
|
+
# Does the group's representation exceed the provided threshold?
|
52
|
+
def busts_threshold?(group_key)
|
53
|
+
group = @group_rules[group_key]
|
54
|
+
group[:count] / @members.count.to_f >= (group[:threshold] || 1)
|
37
55
|
end
|
38
56
|
|
57
|
+
# Fallback on provided group options
|
39
58
|
def random_group
|
40
|
-
|
59
|
+
candidates.sample || @groups.sample
|
41
60
|
end
|
42
61
|
end
|
43
62
|
end
|
data/lib/eenie_meenie/version.rb
CHANGED
@@ -22,6 +22,9 @@ describe EenieMeenie::Assignment do
|
|
22
22
|
@member.expect :class, @member_class
|
23
23
|
@member_class.expect :where, @relation, [{}]
|
24
24
|
@relation.expect :where, @relation, [{:experimental_group=>"Control"}]
|
25
|
+
@relation.expect :where, @relation, [{:experimental_group=>"Experimental"}]
|
26
|
+
@relation.expect :count, 42
|
27
|
+
@relation.expect :count, 42
|
25
28
|
@relation.expect :count, 42
|
26
29
|
@relation.expect :count, 42
|
27
30
|
@subject = EenieMeenie::Assignment
|
@@ -47,11 +50,45 @@ describe EenieMeenie::Assignment do
|
|
47
50
|
result = @subject.new(@minimum_dependencies.merge({
|
48
51
|
groups: ["Control"],
|
49
52
|
group_rules: {
|
50
|
-
"Control" => { threshold: 1
|
53
|
+
"Control" => { threshold: 1 },
|
54
|
+
}
|
55
|
+
})).execute!
|
56
|
+
|
57
|
+
result.must_equal "Control"
|
58
|
+
end
|
59
|
+
|
60
|
+
it "it defaults to a threshold of 100% if no threshold is provided" do
|
61
|
+
result = @subject.new(@minimum_dependencies.merge({
|
62
|
+
groups: ["Control"],
|
63
|
+
group_rules: {
|
64
|
+
"Control" => { }
|
51
65
|
}
|
52
66
|
})).execute!
|
53
67
|
|
54
68
|
assert_equal result, "Control"
|
55
69
|
end
|
70
|
+
|
71
|
+
it "it defaults to a threshold of 100% if provided threshold is false(y)" do
|
72
|
+
result = @subject.new(@minimum_dependencies.merge({
|
73
|
+
groups: ["Control"],
|
74
|
+
group_rules: {
|
75
|
+
"Control" => { threshold: false }
|
76
|
+
}
|
77
|
+
})).execute!
|
78
|
+
|
79
|
+
assert_equal result, "Control"
|
80
|
+
end
|
81
|
+
|
82
|
+
it "returns a result from the groups provided" do
|
83
|
+
result = @subject.new(@minimum_dependencies.merge({
|
84
|
+
groups: @groups,
|
85
|
+
group_rules: {
|
86
|
+
"Control" => { threshold: 0.51 },
|
87
|
+
"Experimental" => { threshold: 0.51 }
|
88
|
+
}
|
89
|
+
})).execute!
|
90
|
+
|
91
|
+
@groups.must_include result
|
92
|
+
end
|
56
93
|
end
|
57
94
|
end
|