meekster 0.0.1
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 +15 -0
- data/.gitignore +17 -0
- data/Gemfile +3 -0
- data/README.md +31 -0
- data/Rakefile +5 -0
- data/lib/meekster.rb +9 -0
- data/lib/meekster/ballot.rb +9 -0
- data/lib/meekster/ballot_file.rb +60 -0
- data/lib/meekster/candidate.rb +13 -0
- data/lib/meekster/election.rb +85 -0
- data/lib/meekster/round.rb +211 -0
- data/lib/meekster/version.rb +3 -0
- data/meekster.gemspec +19 -0
- data/spec/ballot_file_spec.rb +40 -0
- data/spec/ballot_files/42.blt +8 -0
- data/spec/ballot_files/Anderston-City-2007.blt +2043 -0
- data/spec/meekster_spec.rb +151 -0
- data/spec/round_spec.rb +22 -0
- metadata +93 -0
@@ -0,0 +1,151 @@
|
|
1
|
+
require File.expand_path("../lib/meekster", File.dirname(__FILE__))
|
2
|
+
|
3
|
+
describe "meekster" do
|
4
|
+
|
5
|
+
describe "simplest election" do
|
6
|
+
it "elects the candidate" do
|
7
|
+
c1 = Meekster::Candidate.new
|
8
|
+
c1.name = "Adam"
|
9
|
+
candidates = [c1]
|
10
|
+
|
11
|
+
b1 = Meekster::Ballot.new
|
12
|
+
b1.ranking = [c1]
|
13
|
+
ballots = [b1]
|
14
|
+
|
15
|
+
election = Meekster::Election.new
|
16
|
+
election.candidates = candidates
|
17
|
+
election.ballots = ballots
|
18
|
+
election.seats = 1
|
19
|
+
|
20
|
+
election.run!
|
21
|
+
|
22
|
+
c1.state.should == :elected
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
describe "wikipedia example STV election" do
|
27
|
+
before(:each) do
|
28
|
+
candidates = [
|
29
|
+
@oranges = Meekster::Candidate.new('Oranges'),
|
30
|
+
@pears = Meekster::Candidate.new('Pears'),
|
31
|
+
@chocolate = Meekster::Candidate.new('Chocolate'),
|
32
|
+
@strawberries = Meekster::Candidate.new('Stawberries'),
|
33
|
+
@sweets = Meekster::Candidate.new('Sweets')
|
34
|
+
]
|
35
|
+
|
36
|
+
ballots = [
|
37
|
+
Meekster::Ballot.new([@oranges]),
|
38
|
+
Meekster::Ballot.new([@oranges]),
|
39
|
+
Meekster::Ballot.new([@oranges]),
|
40
|
+
Meekster::Ballot.new([@oranges]),
|
41
|
+
Meekster::Ballot.new([@pears, @oranges]),
|
42
|
+
Meekster::Ballot.new([@pears, @oranges]),
|
43
|
+
Meekster::Ballot.new([@chocolate, @strawberries]),
|
44
|
+
Meekster::Ballot.new([@chocolate, @strawberries]),
|
45
|
+
Meekster::Ballot.new([@chocolate, @strawberries]),
|
46
|
+
Meekster::Ballot.new([@chocolate, @strawberries]),
|
47
|
+
Meekster::Ballot.new([@chocolate, @strawberries]),
|
48
|
+
Meekster::Ballot.new([@chocolate, @strawberries]),
|
49
|
+
Meekster::Ballot.new([@chocolate, @strawberries]),
|
50
|
+
Meekster::Ballot.new([@chocolate, @strawberries]),
|
51
|
+
Meekster::Ballot.new([@chocolate, @sweets]),
|
52
|
+
Meekster::Ballot.new([@chocolate, @sweets]),
|
53
|
+
Meekster::Ballot.new([@chocolate, @sweets]),
|
54
|
+
Meekster::Ballot.new([@chocolate, @sweets]),
|
55
|
+
Meekster::Ballot.new([@strawberries]),
|
56
|
+
Meekster::Ballot.new([@sweets])
|
57
|
+
]
|
58
|
+
|
59
|
+
election = Meekster::Election.new
|
60
|
+
election.candidates = candidates
|
61
|
+
election.ballots = ballots
|
62
|
+
election.seats = 3
|
63
|
+
|
64
|
+
election.run!
|
65
|
+
end
|
66
|
+
|
67
|
+
it "elects the correct candidates" do
|
68
|
+
@chocolate.state.should == :elected
|
69
|
+
@oranges.state.should == :elected
|
70
|
+
@strawberries.state.should == :elected
|
71
|
+
end
|
72
|
+
|
73
|
+
it "rejects the correct candidates" do
|
74
|
+
@pears.state.should == :defeated
|
75
|
+
@sweets.state.should == :defeated
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
# http://code.google.com/p/droop/wiki/Droop
|
80
|
+
describe "sample elections from Droop" do
|
81
|
+
describe "42" do
|
82
|
+
before(:all) do
|
83
|
+
@election = Meekster::Election.new(
|
84
|
+
:ballot_file => Meekster::BallotFile.new(
|
85
|
+
:filename => File.expand_path("ballot_files/42.blt", File.dirname(__FILE__))
|
86
|
+
)
|
87
|
+
)
|
88
|
+
@election.run!
|
89
|
+
end
|
90
|
+
|
91
|
+
it "elects the correct candidates" do
|
92
|
+
@election.candidates.find{|c| c.name == 'Castor'}.state.should == :elected
|
93
|
+
@election.candidates.find{|c| c.name == 'Castor'}.votes.should be_within(0.000000001).of(2.000000004)
|
94
|
+
|
95
|
+
@election.candidates.find{|c| c.name == 'Helen'}.state.should == :elected
|
96
|
+
@election.candidates.find{|c| c.name == 'Helen'}.votes.should be_within(0.000000001).of(2.000000000)
|
97
|
+
end
|
98
|
+
|
99
|
+
it "rejects the correct candidates" do
|
100
|
+
@election.candidates.find{|c| c.name == 'Pollux'}.state.should == :defeated
|
101
|
+
end
|
102
|
+
|
103
|
+
it "calculates votes for the rejected candidates correctly" do
|
104
|
+
pending('Need to fix final round') do
|
105
|
+
@election.candidates.find{|c| c.name == 'Pollux'}.votes.should be_within(0.000000001).of(0.000000000)
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
describe "Anderston-City-2007" do
|
111
|
+
before(:all) do
|
112
|
+
@election = Meekster::Election.new(
|
113
|
+
:ballot_file => Meekster::BallotFile.new(
|
114
|
+
:filename => File.expand_path("ballot_files/Anderston-City-2007.blt", File.dirname(__FILE__))
|
115
|
+
)
|
116
|
+
)
|
117
|
+
@election.run!
|
118
|
+
end
|
119
|
+
|
120
|
+
it "elects the correct candidates" do
|
121
|
+
@election.candidates.find{|c| c.name == 'Nina Baker'}.state.should == :elected
|
122
|
+
@election.candidates.find{|c| c.name == 'Nina Baker'}.votes.should be_within(0.00001).of(1298.307340419)
|
123
|
+
|
124
|
+
@election.candidates.find{|c| c.name == 'Philip Braat'}.state.should == :elected
|
125
|
+
@election.candidates.find{|c| c.name == 'Philip Braat'}.votes.should be_within(0.00001).of(1297.105615751)
|
126
|
+
|
127
|
+
@election.candidates.find{|c| c.name == 'Craig MacKay'}.state.should == :elected
|
128
|
+
@election.candidates.find{|c| c.name == 'Craig MacKay'}.votes.should be_within(0.00001).of(1280.501790024)
|
129
|
+
|
130
|
+
@election.candidates.find{|c| c.name == 'Gordon Matheson'}.state.should == :elected
|
131
|
+
@election.candidates.find{|c| c.name == 'Gordon Matheson'}.votes.should be_within(0.00001).of(1325.225745098)
|
132
|
+
end
|
133
|
+
|
134
|
+
it "rejects the correct candidates" do
|
135
|
+
['Erin Boyle', 'Dave Holladay', 'Akhtar Khan', 'Ann Laird', 'Peter Murray'].each do |name|
|
136
|
+
@election.candidates.find{|c| c.name == name}.state.should == :defeated
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
it "calculates votes for the rejected candidates correctly" do
|
141
|
+
pending('Need to fix final round')
|
142
|
+
end
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
it "calculates the final quota"
|
147
|
+
it "calculates the final number of votes"
|
148
|
+
it "calculates the final residual"
|
149
|
+
it "calculates the final surplus"
|
150
|
+
|
151
|
+
end
|
data/spec/round_spec.rb
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
require './lib/meekster/round'
|
2
|
+
require 'bigdecimal'
|
3
|
+
|
4
|
+
describe Meekster::Round do
|
5
|
+
|
6
|
+
describe ".round_up_to_nine_decimal_places" do
|
7
|
+
it "rounds to the same value when tenth and later decimal places are zero" do
|
8
|
+
Meekster::Round.round_up_to_nine_decimal_places(BigDecimal('1.1234567890')).should == BigDecimal('1.123456789')
|
9
|
+
end
|
10
|
+
|
11
|
+
it "rounds up when tenth decimal place is present" do
|
12
|
+
Meekster::Round.round_up_to_nine_decimal_places(BigDecimal('1.2222222221')).should == BigDecimal('1.2222222230')
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
describe ".truncate_to_nine_decimal_places" do
|
17
|
+
it "removes tenth decimal and more" do
|
18
|
+
Meekster::Round.truncate_to_nine_decimal_places(BigDecimal('1.3333333337777')).should == BigDecimal('1.333333333')
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
metadata
ADDED
@@ -0,0 +1,93 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: meekster
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Chris Mear
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2013-07-01 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: rspec
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ~>
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 2.9.0
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ~>
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 2.9.0
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ~>
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 0.9.2
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ~>
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: 0.9.2
|
41
|
+
description: Meekster implements a Meek Single Transferable Vote (STV) voting system,
|
42
|
+
as described in the Proportional Representation Foundation's Reference Meek Rule.
|
43
|
+
email: chris@feedmechocolate.com
|
44
|
+
executables: []
|
45
|
+
extensions: []
|
46
|
+
extra_rdoc_files: []
|
47
|
+
files:
|
48
|
+
- .gitignore
|
49
|
+
- Gemfile
|
50
|
+
- README.md
|
51
|
+
- Rakefile
|
52
|
+
- lib/meekster.rb
|
53
|
+
- lib/meekster/ballot.rb
|
54
|
+
- lib/meekster/ballot_file.rb
|
55
|
+
- lib/meekster/candidate.rb
|
56
|
+
- lib/meekster/election.rb
|
57
|
+
- lib/meekster/round.rb
|
58
|
+
- lib/meekster/version.rb
|
59
|
+
- meekster.gemspec
|
60
|
+
- spec/ballot_file_spec.rb
|
61
|
+
- spec/ballot_files/42.blt
|
62
|
+
- spec/ballot_files/Anderston-City-2007.blt
|
63
|
+
- spec/meekster_spec.rb
|
64
|
+
- spec/round_spec.rb
|
65
|
+
homepage: https://github.com/chrismear/meekster
|
66
|
+
licenses: []
|
67
|
+
metadata: {}
|
68
|
+
post_install_message:
|
69
|
+
rdoc_options: []
|
70
|
+
require_paths:
|
71
|
+
- lib
|
72
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
73
|
+
requirements:
|
74
|
+
- - ! '>='
|
75
|
+
- !ruby/object:Gem::Version
|
76
|
+
version: '0'
|
77
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
78
|
+
requirements:
|
79
|
+
- - ! '>='
|
80
|
+
- !ruby/object:Gem::Version
|
81
|
+
version: '0'
|
82
|
+
requirements: []
|
83
|
+
rubyforge_project:
|
84
|
+
rubygems_version: 2.0.3
|
85
|
+
signing_key:
|
86
|
+
specification_version: 4
|
87
|
+
summary: An implementation of the Meek STV election voting system.
|
88
|
+
test_files:
|
89
|
+
- spec/ballot_file_spec.rb
|
90
|
+
- spec/ballot_files/42.blt
|
91
|
+
- spec/ballot_files/Anderston-City-2007.blt
|
92
|
+
- spec/meekster_spec.rb
|
93
|
+
- spec/round_spec.rb
|