eenie_meenie 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1 @@
1
+ *.sw?
data/CHANGELOG.md ADDED
@@ -0,0 +1,13 @@
1
+ 0.0.1 - Initial release, allows you to initialize an instance of Rubeuler::Problem with required options `:number` (int) and `:answer` (string of ruby code). Answer is evaluated and compared to answer predefined in Rubeuler::Problem#solutions method. Result is returned indicating success/failure and the time elapsed when running the code in `:answer`
2
+
3
+ 0.0.2 - Fixed Rakefile (gave myself the ability to use `rake release`); Updated description in gemspec
4
+
5
+ 0.0.3 - Moved Rubeuler::Problem#solutions to Rubeuler::Solution#for_problem to make the intended use more intuitive
6
+
7
+ 0.0.4 - Add tests using minitest
8
+
9
+ 0.0.5 - Feature: Track other variables... the options `tracked: {foo: @foo}` would track a variable set as `@foo` in Rubeuler::Problem's `:answer` argument
10
+ Improve on tests, improve timer by moving Benchmark closer to code being evaluated
11
+
12
+ 0.0.6 - Reverting the change to the Benchmark implementation from 0.0.5
13
+
data/Gemfile ADDED
@@ -0,0 +1,3 @@
1
+ source "http://rubygems.org"
2
+
3
+ gemspec
data/Gemfile.lock ADDED
@@ -0,0 +1,33 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ eenie_meenie (0.0.1)
5
+
6
+ GEM
7
+ remote: http://rubygems.org/
8
+ specs:
9
+ coderay (1.0.7)
10
+ method_source (0.8)
11
+ minitest (3.5.0)
12
+ pry (0.9.10)
13
+ coderay (~> 1.0.5)
14
+ method_source (~> 0.8)
15
+ slop (~> 3.3.1)
16
+ pry (0.9.10-java)
17
+ coderay (~> 1.0.5)
18
+ method_source (~> 0.8)
19
+ slop (~> 3.3.1)
20
+ spoon (~> 0.0)
21
+ rake (0.9.2.2)
22
+ slop (3.3.3)
23
+ spoon (0.0.1)
24
+
25
+ PLATFORMS
26
+ java
27
+ ruby
28
+
29
+ DEPENDENCIES
30
+ eenie_meenie!
31
+ minitest
32
+ pry
33
+ rake
data/README.md ADDED
@@ -0,0 +1,13 @@
1
+ EenieMeenie
2
+ ========
3
+
4
+ This tool was written in order to play with some simple methods for assigning members of a population to one of two groups. The goal is to provide an algorithm that will limit the user's ability to predict which group a member will be assigned.
5
+
6
+ Installation
7
+ ------------
8
+
9
+ EenieMeenie is a Ruby gem, and can be installed using `gem install eenie_meenie`
10
+
11
+ ### Pull requests/issues
12
+
13
+ Please submit any useful pull requests through GitHub. Please report any bugs using Github's issue tracker
data/Rakefile ADDED
@@ -0,0 +1,9 @@
1
+ require "bundler/gem_tasks"
2
+ require "rake/testtask"
3
+
4
+ Rake::TestTask.new do |t|
5
+ t.pattern = 'test/**/*_test.rb'
6
+ t.libs.push 'test'
7
+ end
8
+
9
+ task :default => :test
@@ -0,0 +1,26 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "eenie_meenie/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "eenie_meenie"
7
+ s.version = EenieMeenie::VERSION
8
+ s.authors = ["Tad Hosford"]
9
+ s.email = ["tad.hosford@gmail.com"]
10
+ s.homepage = "http://github.com/rthbound/eenie_meenie"
11
+ s.description = %q{ Attempts to provide a random but (mostly)
12
+ even distribution of samples amongst
13
+ specified groups
14
+ }
15
+ s.summary = %q{ }
16
+
17
+ s.files = `git ls-files`.split("\n")
18
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
19
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
20
+ s.require_paths = ["lib"]
21
+
22
+ s.add_development_dependency "minitest"
23
+
24
+ s.add_development_dependency "rake"
25
+ s.add_development_dependency "pry"
26
+ end
@@ -0,0 +1,62 @@
1
+ module EenieMeenie
2
+ class Assignment < ::EenieMeenie::Base
3
+ def initialize(options)
4
+ load_options(:groups, :member_class, options)
5
+ raise ArgumentError unless @member_class.respond_to?(:group)
6
+ end
7
+
8
+ def execute!
9
+ group = assign
10
+ end
11
+
12
+ private
13
+
14
+ def assign
15
+ group = coercion_threshold_reached? ? assign_with_coercion : assign_without_coercion
16
+
17
+ group
18
+ end
19
+
20
+ def count_for_group(group)
21
+ @member_class.where(group: group).count
22
+ end
23
+
24
+ def assign_without_coercion
25
+ selected_group = @groups.sample
26
+ if rand(expected_population) >= (expected_population / 2)
27
+ group = selected_group
28
+ else
29
+ group = the_other_group(selected_group)
30
+ end
31
+ end
32
+
33
+ def assign_with_coercion
34
+ group = @groups.sample
35
+ group_tally = count_for_group(group)
36
+ other_group = (@groups - [group]).first
37
+ group = other_group if group_tally > count_for_group(other_group) + rand(leeway)
38
+
39
+ group
40
+ end
41
+
42
+ def expected_population
43
+ 60000.to_f
44
+ end
45
+
46
+ def current_population
47
+ @member_class.count.to_f
48
+ end
49
+
50
+ def leeway
51
+ ((current_population / 2 ) * 0.01).round
52
+ end
53
+
54
+ def the_other_group group
55
+ (@groups - [group]).first
56
+ end
57
+
58
+ def coercion_threshold_reached?
59
+ (current_population / expected_population) >= 0.9
60
+ end
61
+ end
62
+ end
@@ -0,0 +1,13 @@
1
+ module EenieMeenie
2
+ class Base
3
+ def load_option(option, options)
4
+ instance_variable_set("@#{option}", options.fetch(option.to_sym) { raise "Missing required option: #{option}" } )
5
+ end
6
+
7
+ def load_options(*option_names, options)
8
+ option_names.each{|o| load_option(o, options) }
9
+
10
+ option_names << instance_variable_set("@tracked", options[:tracked]) if options[:tracked]
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,14 @@
1
+ module EenieMeenie
2
+ class MinyMoe < ::EenieMeenie::Base
3
+ def initialize(options)
4
+ load_options(:groups, :population, :sorter, options)
5
+ end
6
+
7
+ def execute!
8
+ groups = @sorter.new(groups: @groups, population: @population).sort
9
+ return EenieMeenie::Result.new(groups: groups, population: @population)
10
+ end
11
+
12
+ private
13
+ end
14
+ end
@@ -0,0 +1,22 @@
1
+ module EenieMeenie
2
+ class Result
3
+ def initialize(options)
4
+ @groups = options[:groups]
5
+ @population = options[:population]
6
+ @imbalance = @groups.values.inject(:-).abs
7
+ @relative_imbalance = (@imbalance / @population).to_f
8
+ end
9
+
10
+ def groups
11
+ @groups
12
+ end
13
+
14
+ def imbalance
15
+ @imbalance
16
+ end
17
+
18
+ def relative_imbalance
19
+ @relative_imbalance
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,20 @@
1
+ module EenieMeenie
2
+ module Sorters
3
+ class PureRandom < EenieMeenie::Base
4
+ def initialize(*args, options)
5
+ load_options(:groups, :population, options)
6
+ end
7
+
8
+ def sort
9
+ results = {}
10
+ @groups.each { |group| results.merge!(group => 0) }
11
+
12
+ @population.times do |i|
13
+ results[(rand(@population) >= (@population / 2) ? @groups.first : @groups.last)] += 1
14
+ end
15
+ groups = results
16
+ end
17
+ end
18
+ end
19
+ end
20
+
@@ -0,0 +1,61 @@
1
+ module EenieMeenie
2
+ module Sorters
3
+ class LateCoercion < EenieMeenie::Base
4
+ def initialize(*args, options)
5
+ load_options(:groups, :population, options)
6
+ end
7
+
8
+ def sort
9
+ @results = {}
10
+ @groups.each { |group| @results.merge!(group => 0) }
11
+
12
+ @population.times do |i|
13
+ @results[assign] += 1
14
+ end
15
+ groups = @results
16
+ end
17
+
18
+ def assign
19
+ coercion_threshold_reached? ? assign_with_coercion : assign_without_coercion
20
+ end
21
+
22
+ def assign_without_coercion
23
+ selected_group = @groups.sample
24
+ if rand(@population) >= (@population / 2)
25
+ group = selected_group
26
+ else
27
+ group = the_other_group(selected_group)
28
+ end
29
+ end
30
+
31
+ def the_other_group group
32
+ (@groups - [group]).first
33
+ end
34
+
35
+ def assign_with_coercion
36
+ group = @groups.sample
37
+ group_tally = count_for_group(group)
38
+ other_group = (@groups - [group]).first
39
+ group = other_group if group_tally > count_for_group(other_group) + rand(leeway)
40
+
41
+ group
42
+ end
43
+
44
+ def count_for_group(group)
45
+ @results[group].to_f
46
+ end
47
+
48
+ def leeway
49
+ ((current_population / 2 ) * 0.01).round
50
+ end
51
+
52
+ def current_population
53
+ @results.values.inject(&:+).to_f
54
+ end
55
+
56
+ def coercion_threshold_reached?
57
+ (current_population / @population) >= 0.9
58
+ end
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,23 @@
1
+ module EenieMeenie
2
+ module Sorters
3
+ class PickAGroup < EenieMeenie::Base
4
+ def initialize(*args, options)
5
+ load_options(:groups, :population, options)
6
+ end
7
+
8
+ def sort
9
+ results = {}
10
+ @groups.each { |group| results.merge!(group => 0) }
11
+
12
+ @population.times do |i|
13
+ group = @groups.sample
14
+ other_group = (@groups - [group]).first
15
+ group = other_group if results.values.any? {|v| results[group] > v + rand(10) }
16
+ results[group] += 1
17
+ end
18
+ groups = results
19
+ end
20
+ end
21
+ end
22
+ end
23
+
@@ -0,0 +1,20 @@
1
+ module EenieMeenie
2
+ module Sorters
3
+ class PureRandom < EenieMeenie::Base
4
+ def initialize(*args, options)
5
+ load_options(:groups, :population, options)
6
+ end
7
+
8
+ def sort
9
+ results = {}
10
+ @groups.each { |group| results.merge!(group => 0) }
11
+
12
+ @population.times do |i|
13
+ results[(rand(@population) > (@population / 2) ? @groups.first : @groups.last)] += 1
14
+ end
15
+ groups = results
16
+ end
17
+ end
18
+ end
19
+ end
20
+
@@ -0,0 +1,20 @@
1
+ module EenieMeenie
2
+ module Sorters
3
+ class RoundRobin < EenieMeenie::Base
4
+ def initialize(*args, options)
5
+ load_options(:groups, :population, options)
6
+ end
7
+
8
+ def sort
9
+ results = {}
10
+ @groups.each { |group| results.merge!(group => 0) }
11
+ @population.times do |i|
12
+ results[@groups[i % @groups.length]] += 1
13
+ end
14
+
15
+ groups = results
16
+ end
17
+ end
18
+ end
19
+ end
20
+
@@ -0,0 +1,3 @@
1
+ module EenieMeenie
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,11 @@
1
+ require "eenie_meenie/base"
2
+ #require "eenie_meenie/miny_moe"
3
+ #require "eenie_meenie/sorters/round_robin"
4
+ #require "eenie_meenie/sorters/pure_random"
5
+ #require "eenie_meenie/sorters/pick_a_group"
6
+ #require "eenie_meenie/version"
7
+ #require "eenie_meenie/result"
8
+
9
+ Dir.glob(File.join(File.dirname(__FILE__), '/**/*.rb')) do |c|
10
+ require(c)
11
+ end
@@ -0,0 +1,13 @@
1
+ require "minitest_helper"
2
+
3
+ describe EenieMeenie::MinyMoe do
4
+ describe ".execute!" do
5
+ before do
6
+ @options = { population: 100, groups: ["Experimental", "Control"] }
7
+ @subject = EenieMeenie::MinyMoe
8
+ end
9
+ it "returns a result" do
10
+ @subject.new(@options.merge(sorter: EenieMeenie::Sorters::RoundRobin)).execute!.must_be_kind_of(EenieMeenie::Result)
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,12 @@
1
+ # Testing frameworks
2
+ require "minitest/spec"
3
+ require "minitest/autorun"
4
+
5
+ # Debugger
6
+ require "pry"
7
+
8
+ # The gem
9
+ $: << File.dirname(__FILE__) + "/../lib"
10
+ $: << File.dirname(__FILE__)
11
+
12
+ require "eenie_meenie"
metadata ADDED
@@ -0,0 +1,106 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: eenie_meenie
3
+ version: !ruby/object:Gem::Version
4
+ prerelease:
5
+ version: 0.0.1
6
+ platform: ruby
7
+ authors:
8
+ - Tad Hosford
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+
13
+ date: 2012-12-27 00:00:00 Z
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: minitest
17
+ prerelease: false
18
+ requirement: &id001 !ruby/object:Gem::Requirement
19
+ none: false
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: "0"
24
+ type: :development
25
+ version_requirements: *id001
26
+ - !ruby/object:Gem::Dependency
27
+ name: rake
28
+ prerelease: false
29
+ requirement: &id002 !ruby/object:Gem::Requirement
30
+ none: false
31
+ requirements:
32
+ - - ">="
33
+ - !ruby/object:Gem::Version
34
+ version: "0"
35
+ type: :development
36
+ version_requirements: *id002
37
+ - !ruby/object:Gem::Dependency
38
+ name: pry
39
+ prerelease: false
40
+ requirement: &id003 !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ">="
44
+ - !ruby/object:Gem::Version
45
+ version: "0"
46
+ type: :development
47
+ version_requirements: *id003
48
+ description: " Attempts to provide a random but (mostly)\n even distribution of samples amongst\n specified groups\n "
49
+ email:
50
+ - tad.hosford@gmail.com
51
+ executables: []
52
+
53
+ extensions: []
54
+
55
+ extra_rdoc_files: []
56
+
57
+ files:
58
+ - .gitignore
59
+ - CHANGELOG.md
60
+ - Gemfile
61
+ - Gemfile.lock
62
+ - README.md
63
+ - Rakefile
64
+ - eenie_meenie.gemspec
65
+ - lib/eenie_meenie.rb
66
+ - lib/eenie_meenie/assignment.rb
67
+ - lib/eenie_meenie/base.rb
68
+ - lib/eenie_meenie/miny_moe.rb
69
+ - lib/eenie_meenie/result.rb
70
+ - lib/eenie_meenie/sorters/bucket_shuffle.rb
71
+ - lib/eenie_meenie/sorters/late_coercion.rb
72
+ - lib/eenie_meenie/sorters/pick_a_group.rb
73
+ - lib/eenie_meenie/sorters/pure_random.rb
74
+ - lib/eenie_meenie/sorters/round_robin.rb
75
+ - lib/eenie_meenie/version.rb
76
+ - test/eenie_meenie/miny_moe_test.rb
77
+ - test/minitest_helper.rb
78
+ homepage: http://github.com/rthbound/eenie_meenie
79
+ licenses: []
80
+
81
+ post_install_message:
82
+ rdoc_options: []
83
+
84
+ require_paths:
85
+ - lib
86
+ required_ruby_version: !ruby/object:Gem::Requirement
87
+ none: false
88
+ requirements:
89
+ - - ">="
90
+ - !ruby/object:Gem::Version
91
+ version: "0"
92
+ required_rubygems_version: !ruby/object:Gem::Requirement
93
+ none: false
94
+ requirements:
95
+ - - ">="
96
+ - !ruby/object:Gem::Version
97
+ version: "0"
98
+ requirements: []
99
+
100
+ rubyforge_project:
101
+ rubygems_version: 1.8.24
102
+ signing_key:
103
+ specification_version: 3
104
+ summary: ""
105
+ test_files: []
106
+