fec_results 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +17 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +63 -0
- data/Rakefile +1 -0
- data/api_routes.csv +1 -0
- data/fec_results.gemspec +25 -0
- data/lib/fec_results.rb +40 -0
- data/lib/fec_results/congress.rb +323 -0
- data/lib/fec_results/president.rb +340 -0
- data/lib/fec_results/result.rb +48 -0
- data/lib/fec_results/summary.rb +558 -0
- data/lib/fec_results/version.rb +3 -0
- metadata +129 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 Derek Willis
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,63 @@
|
|
1
|
+
# FecResults
|
2
|
+
|
3
|
+
FecResults is a Ruby library that provides access to federal election results as published by the Federal Election Commission. Although it is primarily a campaign finance disclosure agency, the FEC also compiles election results on its site. This library provides ways to access summary and contest-specific information about elections for the U.S. House of Representatives, the U.S. Senate and President from 2000-2012. This data represents regularly-scheduled primary and general elections, plus special elections held on the date of general elections. It does not include special elections held outside the regularly scheduled election calendar. The results are race-wide only; they do not contain any geographic breakdowns such as county.
|
4
|
+
|
5
|
+
Please be aware that there can be typos in some of the FEC results files, mainly in the FEC candidate IDs.
|
6
|
+
|
7
|
+
## Installation
|
8
|
+
|
9
|
+
Add this line to your application's Gemfile:
|
10
|
+
|
11
|
+
gem 'fec_results'
|
12
|
+
|
13
|
+
And then execute:
|
14
|
+
|
15
|
+
$ bundle
|
16
|
+
|
17
|
+
Or install it yourself as:
|
18
|
+
|
19
|
+
$ gem install fec_results
|
20
|
+
|
21
|
+
## Usage
|
22
|
+
|
23
|
+
FecResults can be used to retrieve both summary and contest-specific election results. Every instance of FecResults must include a year passed into the `new` method. For summary totals:
|
24
|
+
|
25
|
+
```ruby
|
26
|
+
require 'fec_results'
|
27
|
+
s = FecResults::Summary.new(:year => 2012)
|
28
|
+
general_votes = s.general_election_votes
|
29
|
+
=> [<OpenStruct state="AL", presidential_votes=2074338, senate_votes=nil, house_votes=1933630>, <OpenStruct state="AK", presidential_votes=300495, senate_votes=nil, house_votes=289804>,...]
|
30
|
+
general_votes.
|
31
|
+
alabama = general_votes.first
|
32
|
+
=> <OpenStruct state="AL", presidential_votes=2074338, senate_votes=nil, house_votes=1933630>
|
33
|
+
alabama.house_votes
|
34
|
+
=> 1933630
|
35
|
+
```
|
36
|
+
For specific congressional results, the file can take awhile to load, so try not to call `results` more than once, but rather save the output locally:
|
37
|
+
|
38
|
+
```ruby
|
39
|
+
c = FecResults::Congress.new(:year => 2012)
|
40
|
+
results = c.results
|
41
|
+
results.first
|
42
|
+
=> <FecResults::Result:0x007fb46e297870 @year=2012, @chamber="H", @state="AL", @district="01", @fec_id="H2AL01077", @incumbent=true, @candidate_last="Bonner", @candidate_first="Jo", @candidate_name="Bonner, Jo", @party="R", @primary_votes=48702, @primary_pct=55.54959907839358, @primary_unopposed=false, @runoff_votes=nil, @runoff_pct=nil, @general_votes=196374, @general_pct=97.85624588889553, @general_unopposed=false, @general_runoff_votes=nil, @general_runoff_pct=nil, @general_combined_party_votes=nil, @general_combined_party_pct=nil, @general_winner=true, @notes=nil>
|
43
|
+
```
|
44
|
+
|
45
|
+
To filter either summary or results items by state, pass in the state in a hash:
|
46
|
+
|
47
|
+
```ruby
|
48
|
+
c = FecResults::Congress.new(:year => 2012)
|
49
|
+
results = c.results({:state => 'AL'})
|
50
|
+
results.first
|
51
|
+
=> <FecResults::Result:0x007fb46e297870 @year=2012, @chamber="H", @state="AL", @district="01", @fec_id="H2AL01077", @incumbent=true, @candidate_last="Bonner", @candidate_first="Jo", @candidate_name="Bonner, Jo", @party="R", @primary_votes=48702, @primary_pct=55.54959907839358, @primary_unopposed=false, @runoff_votes=nil, @runoff_pct=nil, @general_votes=196374, @general_pct=97.85624588889553, @general_unopposed=false, @general_runoff_votes=nil, @general_runoff_pct=nil, @general_combined_party_votes=nil, @general_combined_party_pct=nil, @general_winner=true, @notes=nil>
|
52
|
+
```
|
53
|
+
|
54
|
+
|
55
|
+
|
56
|
+
|
57
|
+
## Contributing
|
58
|
+
|
59
|
+
1. Fork it
|
60
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
61
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
62
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
63
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
data/api_routes.csv
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
class,method,path,container,object,arg example
|
data/fec_results.gemspec
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'fec_results/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "fec_results"
|
8
|
+
spec.version = FecResults::VERSION
|
9
|
+
spec.authors = ["Derek Willis"]
|
10
|
+
spec.email = ["dwillis@gmail.com"]
|
11
|
+
spec.description = %q{Parses FEC federal election results into Ruby objects}
|
12
|
+
spec.summary = %q{House, Senate, Presidential results}
|
13
|
+
spec.homepage = ""
|
14
|
+
spec.license = "Apache"
|
15
|
+
|
16
|
+
spec.files = `git ls-files`.split($/)
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.add_development_dependency "bundler", "~> 1.3"
|
22
|
+
spec.add_development_dependency "rake"
|
23
|
+
spec.add_dependency "remote_table"
|
24
|
+
spec.add_dependency "american_date"
|
25
|
+
end
|
data/lib/fec_results.rb
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'remote_table'
|
3
|
+
require 'american_date'
|
4
|
+
require 'ostruct'
|
5
|
+
|
6
|
+
require "fec_results/version"
|
7
|
+
require "fec_results/congress"
|
8
|
+
require "fec_results/result"
|
9
|
+
require "fec_results/summary"
|
10
|
+
require "fec_results/president"
|
11
|
+
|
12
|
+
module FecResults
|
13
|
+
|
14
|
+
SUMMARY_URLS = {
|
15
|
+
'2012' => 'http://www.fec.gov/pubrec/fe2012/tables2012.xls',
|
16
|
+
'2010' => 'http://www.fec.gov/pubrec/fe2010/tables10.xls',
|
17
|
+
'2008' => 'http://www.fec.gov/pubrec/fe2008/tables2008.xls',
|
18
|
+
'2006' => 'http://www.fec.gov/pubrec/fe2006/tables06.xls',
|
19
|
+
'2004' => 'http://www.fec.gov/pubrec/fe2004/tables.xls',
|
20
|
+
'2002' => 'http://www.fec.gov/pubrec/fe2002/2002fedresults.xls',
|
21
|
+
'2000' => 'http://www.fec.gov/pubrec/fe2000/tables.xls'
|
22
|
+
}
|
23
|
+
|
24
|
+
CONGRESS_URLS = {
|
25
|
+
'2012' => 'http://www.fec.gov/pubrec/fe2012/2012congresults.xls',
|
26
|
+
'2010' => 'http://www.fec.gov/pubrec/fe2010/results10.xls',
|
27
|
+
'2008' => 'http://www.fec.gov/pubrec/fe2008/2008congresults.xls',
|
28
|
+
'2006' => 'http://www.fec.gov/pubrec/fe2006/results06.xls',
|
29
|
+
'2004' => 'http://www.fec.gov/pubrec/fe2004/2004congresults.xls',
|
30
|
+
'2002' => 'http://www.fec.gov/pubrec/fe2002/2002fedresults.xls',
|
31
|
+
'2000' => [{'http://www.fec.gov/pubrec/fe2000/senate.xls' => 'Senate (with Totals & Percent) '}, {'http://www.fec.gov/pubrec/fe2000/house.xls' => 'House (with Totals & Percents)'}]
|
32
|
+
}
|
33
|
+
|
34
|
+
PRESIDENT_URLS = {
|
35
|
+
'2012' => 'http://www.fec.gov/pubrec/fe2012/2012pres.xls',
|
36
|
+
'2008' => 'http://www.fec.gov/pubrec/fe2008/2008pres.xls',
|
37
|
+
'2004' => 'http://www.fec.gov/pubrec/fe2004/2004pres.xls',
|
38
|
+
'2000' => ['http://www.fec.gov/pubrec/fe2000/presge.xls', 'http://www.fec.gov/pubrec/fe2000/presprim.xls']
|
39
|
+
}
|
40
|
+
end
|
@@ -0,0 +1,323 @@
|
|
1
|
+
module FecResults
|
2
|
+
class Congress
|
3
|
+
|
4
|
+
attr_reader :year, :url
|
5
|
+
|
6
|
+
# given a year and an optional chamber ('house' or 'senate') and state ('ar', 'az', etc.)
|
7
|
+
# retrieves election results that fit the criteria
|
8
|
+
def initialize(params={})
|
9
|
+
params.each_pair do |k,v|
|
10
|
+
instance_variable_set("@#{k}", v)
|
11
|
+
end
|
12
|
+
@url = FecResults::CONGRESS_URLS[year.to_s]
|
13
|
+
end
|
14
|
+
|
15
|
+
def results(options={})
|
16
|
+
send("process_#{year}", options)
|
17
|
+
end
|
18
|
+
|
19
|
+
def process_2012(options)
|
20
|
+
results = []
|
21
|
+
t = RemoteTable.new(url, :sheet => "2012 US House & Senate Resuts")
|
22
|
+
rows = t.entries
|
23
|
+
rows = rows.select{|r| r['D'] == options[:chamber]} if options[:chamber]
|
24
|
+
rows = rows.select{|r| r['STATE ABBREVIATION'] == options[:state]} if options[:state]
|
25
|
+
rows.each do |candidate|
|
26
|
+
c = {:year => year}
|
27
|
+
next if candidate['CANDIDATE NAME (Last)'].blank?
|
28
|
+
next if candidate['D'].blank?
|
29
|
+
# find the office_type
|
30
|
+
if candidate['FEC ID#'].first != 'n'
|
31
|
+
c[:chamber] = candidate['FEC ID#'].first
|
32
|
+
elsif candidate['D'].first == 'S'
|
33
|
+
c[:chamber] = "S"
|
34
|
+
else
|
35
|
+
c[:chamber] = 'H'
|
36
|
+
end
|
37
|
+
c[:state] = candidate['STATE ABBREVIATION']
|
38
|
+
c[:district] = candidate['D']
|
39
|
+
c[:party] = candidate['PARTY']
|
40
|
+
c[:incumbent] = candidate['(I)'] == '(I)' ? true : false
|
41
|
+
c[:fec_id] = candidate['FEC ID#']
|
42
|
+
c[:candidate_first] = candidate['CANDIDATE NAME (First)']
|
43
|
+
c[:candidate_last] = candidate['CANDIDATE NAME (Last)']
|
44
|
+
c[:candidate_name] = candidate['CANDIDATE NAME']
|
45
|
+
|
46
|
+
c = update_vote_tallies(c, candidate, 'PRIMARY VOTES', 'PRIMARY %', 'RUNOFF VOTES', 'RUNOFF %', 'GENERAL VOTES ', 'GENERAL %')
|
47
|
+
c = update_general_runoff(c, candidate, 'GE RUNOFF ELECTION VOTES (LA)', 'GE RUNOFF ELECTION % (LA)') if c[:state] == 'LA'
|
48
|
+
c = update_combined_totals(c, candidate, 'COMBINED GE PARTY TOTALS (CT, NY, SC)', 'COMBINED % (CT, NY, SC)') if ['CT', 'NY', 'SC'].include?(c[:state])
|
49
|
+
|
50
|
+
c[:general_winner] = candidate['GE WINNER INDICATOR'] == "W" ? true : false unless c[:general_pct].nil?
|
51
|
+
|
52
|
+
results << c
|
53
|
+
end
|
54
|
+
Result.create_from_results(results)
|
55
|
+
end
|
56
|
+
|
57
|
+
def process_2010(options)
|
58
|
+
results = []
|
59
|
+
t = RemoteTable.new(url, :sheet => "2010 US House & Senate Results")
|
60
|
+
rows = t.entries
|
61
|
+
rows = rows.select{|r| r['DISTRICT'] == options[:chamber]} if options[:chamber]
|
62
|
+
rows = rows.select{|r| r['STATE ABBREVIATION'] == options[:state]} if options[:state]
|
63
|
+
rows.each do |candidate|
|
64
|
+
c = {:year => year}
|
65
|
+
next if candidate['CANDIDATE NAME (Last)'].blank?
|
66
|
+
next if candidate['DISTRICT'].blank?
|
67
|
+
# find the office_type
|
68
|
+
if candidate['FEC ID#'].first != 'n'
|
69
|
+
c[:chamber] = candidate['FEC ID#'].first
|
70
|
+
elsif candidate['DISTRICT'].first == 'S'
|
71
|
+
c[:chamber] = "S"
|
72
|
+
else
|
73
|
+
c[:chamber] = 'H'
|
74
|
+
end
|
75
|
+
c[:state] = candidate['STATE ABBREVIATION']
|
76
|
+
c[:district] = candidate['DISTRICT']
|
77
|
+
c[:party] = candidate['PARTY']
|
78
|
+
c[:incumbent] = candidate['INCUMBENT INDICATOR (I)'] == '(I)' ? true : false
|
79
|
+
c[:fec_id] = candidate['FEC ID#']
|
80
|
+
c[:candidate_first] = candidate['CANDIDATE NAME (First)']
|
81
|
+
c[:candidate_last] = candidate['CANDIDATE NAME (Last)']
|
82
|
+
c[:candidate_name] = candidate['CANDIDATE NAME (Last, First)']
|
83
|
+
|
84
|
+
c = update_vote_tallies(c, candidate, 'PRIMARY', 'PRIMARY %', 'RUNOFF', 'RUNOFF %', 'GENERAL ', 'GENERAL %')
|
85
|
+
c = update_combined_totals(c, candidate) if ['CT', 'NY', 'SC'].include?(c[:state])
|
86
|
+
|
87
|
+
results << c
|
88
|
+
end
|
89
|
+
Result.create_from_results(results)
|
90
|
+
end
|
91
|
+
|
92
|
+
def process_2008(options)
|
93
|
+
results = []
|
94
|
+
t = RemoteTable.new(url, :sheet => "2008 House and Senate Results")
|
95
|
+
rows = t.entries
|
96
|
+
rows = rows.select{|r| r['DISTRICT'] == options[:chamber]} if options[:chamber]
|
97
|
+
rows = rows.select{|r| r['STATE ABBREVIATION'] == options[:state]} if options[:state]
|
98
|
+
rows.each do |candidate|
|
99
|
+
c = {:year => year}
|
100
|
+
next if candidate['Candidate Name (Last)'].blank?
|
101
|
+
next if candidate['DISTRICT'].blank?
|
102
|
+
# find the office_type
|
103
|
+
if candidate['FEC ID#'].first != 'n'
|
104
|
+
c[:chamber] = candidate['FEC ID#'].first
|
105
|
+
elsif candidate['DISTRICT'].first == 'S'
|
106
|
+
c[:chamber] = "S"
|
107
|
+
else
|
108
|
+
c[:chamber] = 'H'
|
109
|
+
end
|
110
|
+
c[:state] = candidate['STATE ABBREVIATION']
|
111
|
+
c[:district] = candidate['DISTRICT']
|
112
|
+
c[:party] = candidate['PARTY']
|
113
|
+
c[:incumbent] = candidate['INCUMBENT INDICATOR (I)'] == '(I)' ? true : false
|
114
|
+
c[:fec_id] = candidate['FEC ID#']
|
115
|
+
c[:candidate_first] = candidate['CANDIDATE NAME (First)']
|
116
|
+
c[:candidate_last] = candidate['CANDIDATE NAME (Last)']
|
117
|
+
c[:candidate_name] = candidate['CANDIDATE NAME']
|
118
|
+
|
119
|
+
c = update_vote_tallies(c, candidate, 'PRIMARY', 'PRIMARY %', 'RUNOFF', 'RUNOFF %', 'GENERAL ', 'GENERAL %')
|
120
|
+
c = update_general_runoff(c, candidate, 'GE RUNOFF', 'GE RUNOFF %') if c[:state] == 'LA'
|
121
|
+
c = update_combined_totals(c, candidate, 'COMBINED GE PARTY TOTALS (CT, NY)', 'COMBINED % (CT, NY)') if ['CT', 'NY'].include?(c[:state])
|
122
|
+
|
123
|
+
results << c
|
124
|
+
end
|
125
|
+
Result.create_from_results(results)
|
126
|
+
end
|
127
|
+
|
128
|
+
def process_2006(options)
|
129
|
+
results = []
|
130
|
+
t = RemoteTable.new(url, :sheet => "2006 US House & Senate Results")
|
131
|
+
rows = t.entries
|
132
|
+
rows = rows.select{|r| r['DISTRICT'] == options[:chamber]} if options[:chamber]
|
133
|
+
rows = rows.select{|r| r['STATE ABBREVIATION'] == options[:state]} if options[:state]
|
134
|
+
rows.each do |candidate|
|
135
|
+
c = {:year => year}
|
136
|
+
next if candidate['LAST NAME'].blank?
|
137
|
+
next if candidate['DISTRICT'].blank?
|
138
|
+
# find the office_type
|
139
|
+
if candidate['FEC ID'].first != 'n'
|
140
|
+
c[:chamber] = candidate['FEC ID'].first
|
141
|
+
elsif candidate['DISTRICT'].first == 'S'
|
142
|
+
c[:chamber] = "S"
|
143
|
+
else
|
144
|
+
c[:chamber] = 'H'
|
145
|
+
end
|
146
|
+
c[:state] = candidate['STATE ABBREVIATION']
|
147
|
+
c[:district] = candidate['DISTRICT']
|
148
|
+
c[:party] = candidate['PARTY']
|
149
|
+
c[:incumbent] = candidate['INCUMBENT INDICATOR'] == '(I)' ? true : false
|
150
|
+
c[:fec_id] = candidate['FEC ID#']
|
151
|
+
c[:candidate_first] = candidate['FIRST NAME']
|
152
|
+
c[:candidate_last] = candidate['LAST NAME']
|
153
|
+
c[:candidate_name] = candidate['LAST NAME, FIRST']
|
154
|
+
|
155
|
+
c = update_vote_tallies(c, candidate, 'PRIMARY', 'PRIMARY %', 'RUNOFF', 'RUNOFF %', 'GENERAL', 'GENERAL %')
|
156
|
+
c = update_general_runoff(c, candidate, 'GE RUNOFF', 'GE RUNOFF %') if c[:state] == 'LA'
|
157
|
+
c = update_combined_totals(c, candidate, 'COMBINED GE PARTY TOTALS (NY, SC)', 'COMBINED % (NY, SC)') if ['SC', 'NY'].include?(c[:state])
|
158
|
+
|
159
|
+
results << c
|
160
|
+
end
|
161
|
+
Result.create_from_results(results)
|
162
|
+
end
|
163
|
+
|
164
|
+
def process_2004(options)
|
165
|
+
results = []
|
166
|
+
t = RemoteTable.new(url, :sheet => "2004 US HOUSE & SENATE RESULTS")
|
167
|
+
rows = t.entries
|
168
|
+
rows = rows.select{|r| r['DISTRICT'] == options[:chamber]} if options[:chamber]
|
169
|
+
rows = rows.select{|r| r['STATE ABBREVIATION'] == options[:state]} if options[:state]
|
170
|
+
rows.each do |candidate|
|
171
|
+
c = {:year => year}
|
172
|
+
next if candidate['LAST NAME'].blank?
|
173
|
+
next if candidate['DISTRICT'].blank?
|
174
|
+
# find the office_type
|
175
|
+
if candidate['FEC ID'].first != 'n'
|
176
|
+
c[:chamber] = candidate['FEC ID'].first
|
177
|
+
elsif candidate['DISTRICT'].first == 'S'
|
178
|
+
c[:chamber] = "S"
|
179
|
+
else
|
180
|
+
c[:chamber] = 'H'
|
181
|
+
end
|
182
|
+
c[:state] = candidate['STATE ABBREVIATION']
|
183
|
+
c[:district] = candidate['DISTRICT']
|
184
|
+
c[:party] = candidate['PARTY']
|
185
|
+
c[:incumbent] = candidate['INCUMBENT INDICATOR'] == '(I)' ? true : false
|
186
|
+
c[:fec_id] = candidate['FEC ID#']
|
187
|
+
c[:candidate_first] = candidate['FIRST NAME']
|
188
|
+
c[:candidate_last] = candidate['LAST NAME']
|
189
|
+
c[:candidate_name] = candidate['LAST NAME, FIRST']
|
190
|
+
|
191
|
+
c = update_vote_tallies(c, candidate, 'PRIMARY', 'PRIMARY %', 'RUNOFF', 'RUNOFF %', 'GENERAL', 'GENERAL %')
|
192
|
+
c = update_general_runoff(c, candidate, 'GE RUNOFF', 'GE RUNOFF %') if c[:state] == 'LA'
|
193
|
+
|
194
|
+
results << c
|
195
|
+
end
|
196
|
+
Result.create_from_results(results)
|
197
|
+
end
|
198
|
+
|
199
|
+
def process_2002(options={})
|
200
|
+
results = []
|
201
|
+
t = RemoteTable.new(url, :sheet => "2002 House & Senate Results")
|
202
|
+
rows = t.entries
|
203
|
+
rows = rows.select{|r| r['DISTRICT'] == options[:chamber]} if options[:chamber]
|
204
|
+
rows = rows.select{|r| r['STATE'] == options[:state]} if options[:state]
|
205
|
+
rows.each do |candidate|
|
206
|
+
c = {:year => year}
|
207
|
+
next if candidate['LAST NAME'].blank?
|
208
|
+
next if candidate['DISTRICT'].blank?
|
209
|
+
# find the office_type
|
210
|
+
if candidate['FEC ID'].first != 'n'
|
211
|
+
c[:chamber] = candidate['FEC ID'].first
|
212
|
+
elsif candidate['DISTRICT'].first == 'S'
|
213
|
+
c[:chamber] = "S"
|
214
|
+
else
|
215
|
+
c[:chamber] = 'H'
|
216
|
+
end
|
217
|
+
c[:state] = candidate['STATE']
|
218
|
+
c[:district] = candidate['DISTRICT']
|
219
|
+
c[:party] = candidate['PARTY']
|
220
|
+
c[:incumbent] = candidate['INCUMBENT INDICATOR'] == '(I)' ? true : false
|
221
|
+
c[:fec_id] = candidate['FEC ID#']
|
222
|
+
c[:candidate_first] = candidate['FIRST NAME']
|
223
|
+
c[:candidate_last] = candidate['LAST NAME']
|
224
|
+
c[:candidate_name] = candidate['LAST NAME, FIRST']
|
225
|
+
|
226
|
+
c = update_vote_tallies(c, candidate, 'PRIMARY RESULTS', 'PRIMARY %', 'RUNOFF RESULTS', 'RUNOFF %', 'GENERAL RESULTS', 'GENERAL %')
|
227
|
+
c = update_combined_totals(c, candidate, 'COMBINED GE PARTY TOTALS (NY, SC)', 'COMBINED % (NY, SC)') if ['SC', 'NY'].include?(c[:state])
|
228
|
+
|
229
|
+
results << c
|
230
|
+
end
|
231
|
+
Result.create_from_results(results)
|
232
|
+
end
|
233
|
+
|
234
|
+
def process_2000(options={})
|
235
|
+
results = []
|
236
|
+
url.each do |u|
|
237
|
+
t = RemoteTable.new(u.keys.first, :sheet => u.values.first)
|
238
|
+
rows = t.entries
|
239
|
+
rows = rows.select{|r| r['STATE'] == options[:state]} if options[:state]
|
240
|
+
rows.each do |candidate|
|
241
|
+
c = {:year => year}
|
242
|
+
next if candidate['NAME'][0..4] == 'Total'
|
243
|
+
next if candidate['DISTRICT'].blank?
|
244
|
+
if candidate['DISTRICT'].first == 'S'
|
245
|
+
c[:chamber] = "S"
|
246
|
+
else
|
247
|
+
c[:chamber] = 'H'
|
248
|
+
end
|
249
|
+
c[:state] = candidate['STATE']
|
250
|
+
c[:district] = candidate['DISTRICT']
|
251
|
+
c[:party] = candidate['PARTY']
|
252
|
+
c[:incumbent] = candidate['INCUMBENT INDICATOR'] == '(I)' ? true : false
|
253
|
+
c[:candidate_first], c[:candidate_last] = candidate['NAME'].split(', ')
|
254
|
+
c[:candidate_name] = candidate['NAME']
|
255
|
+
|
256
|
+
c = update_vote_tallies(c, candidate, 'PRIMARY RESULTS', 'PRIMARY %', 'RUNOFF RESULTS', 'RUNOFF %', 'GENERAL RESULTS', 'GENERAL %')
|
257
|
+
c = update_general_runoff(c, candidate, 'GENERAL RUNOFF RESULTS', 'GENERAL RUNOFF %') if c[:state] == 'LA'
|
258
|
+
|
259
|
+
results << c
|
260
|
+
end
|
261
|
+
end
|
262
|
+
if options[:chamber] == 'H'
|
263
|
+
results = results.select{|r| r[:chamber] != 'S'}
|
264
|
+
elsif options[:chamber] == 'S'
|
265
|
+
results = results.select{|r| r[:chamber] == 'S'}
|
266
|
+
end
|
267
|
+
Result.create_from_results(results)
|
268
|
+
end
|
269
|
+
|
270
|
+
|
271
|
+
def update_vote_tallies(c, candidate, primary_votes, primary_pct, runoff_votes, runoff_pct, general_votes, general_pct)
|
272
|
+
if candidate[primary_votes] == 'Unopposed'
|
273
|
+
c[:primary_unopposed] = true
|
274
|
+
c[:primary_votes] = nil
|
275
|
+
c[:primary_pct] = 100.0
|
276
|
+
else
|
277
|
+
c[:primary_unopposed] = false
|
278
|
+
c[:primary_votes] = candidate[primary_votes].to_i
|
279
|
+
c[:primary_pct] = candidate[primary_pct].to_f*100.0
|
280
|
+
end
|
281
|
+
|
282
|
+
if candidate[runoff_votes].blank?
|
283
|
+
c[:runoff_votes] = nil
|
284
|
+
c[:runoff_pct] = nil
|
285
|
+
else
|
286
|
+
c[:runoff_votes] = candidate[runoff_votes].to_i
|
287
|
+
c[:runoff_pct] = candidate[runoff_pct].to_f*100.0
|
288
|
+
end
|
289
|
+
|
290
|
+
if candidate[general_votes] == 'Unopposed'
|
291
|
+
c[:general_unopposed] = true
|
292
|
+
c[:general_votes] = nil
|
293
|
+
c[:general_pct] = 100.0
|
294
|
+
elsif candidate[general_votes].blank?
|
295
|
+
c[:general_unopposed] = false
|
296
|
+
c[:general_votes] = nil
|
297
|
+
c[:general_pct] = nil
|
298
|
+
else
|
299
|
+
c[:general_unopposed] = false
|
300
|
+
c[:general_votes] = candidate[general_votes].to_i
|
301
|
+
c[:general_pct] = candidate[general_pct].to_f*100.0
|
302
|
+
end
|
303
|
+
c
|
304
|
+
end
|
305
|
+
|
306
|
+
def update_general_runoff(c, candidate, general_runoff_votes, general_runoff_pct)
|
307
|
+
unless candidate[general_runoff_votes].blank?
|
308
|
+
c[:general_runoff_votes] = candidate[general_runoff_votes].to_i
|
309
|
+
c[:general_runoff_pct] = candidate[general_runoff_pct].to_f*100.0
|
310
|
+
end
|
311
|
+
c
|
312
|
+
end
|
313
|
+
|
314
|
+
def update_combined_totals(c, candidate, general_combined_party_votes, general_combined_party_pct)
|
315
|
+
unless candidate[general_combined_party_votes].blank?
|
316
|
+
c[:general_combined_party_votes] = candidate[general_combined_party_votes].to_i
|
317
|
+
c[:general_combined_party_pct] = candidate[general_combined_party_pct].to_f*100.0
|
318
|
+
end
|
319
|
+
c
|
320
|
+
end
|
321
|
+
|
322
|
+
end
|
323
|
+
end
|