votesmart 0.3.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.
- data/.gitignore +1 -0
- data/History.txt +20 -0
- data/README.rdoc +48 -0
- data/Rakefile +45 -0
- data/VERSION.yml +4 -0
- data/lib/mcll4r/MIT-LICENSE +20 -0
- data/lib/mcll4r/README +19 -0
- data/lib/mcll4r/mcll4r.rb +24 -0
- data/lib/mcll4r/mcll4r_test.rb +35 -0
- data/lib/vote_smart.rb +22 -0
- data/lib/vote_smart/address.rb +42 -0
- data/lib/vote_smart/candidate.rb +32 -0
- data/lib/vote_smart/candidate_bio.rb +16 -0
- data/lib/vote_smart/candidate_office.rb +15 -0
- data/lib/vote_smart/committee.rb +23 -0
- data/lib/vote_smart/common.rb +97 -0
- data/lib/vote_smart/district.rb +38 -0
- data/lib/vote_smart/election.rb +21 -0
- data/lib/vote_smart/leadership.rb +16 -0
- data/lib/vote_smart/local.rb +21 -0
- data/lib/vote_smart/measure.rb +16 -0
- data/lib/vote_smart/notes.rb +11 -0
- data/lib/vote_smart/npat.rb +11 -0
- data/lib/vote_smart/office.rb +119 -0
- data/lib/vote_smart/official.rb +131 -0
- data/lib/vote_smart/phone.rb +12 -0
- data/lib/vote_smart/rating.rb +43 -0
- data/lib/vote_smart/state.rb +29 -0
- data/lib/vote_smart/vote.rb +70 -0
- data/lib/votesmart.rb +1 -0
- data/script/autospec +6 -0
- data/script/console +10 -0
- data/script/destroy +14 -0
- data/script/generate +14 -0
- data/script/is_gem_built +40 -0
- data/spec/responses/Address.get_office.106446.js +1 -0
- data/spec/responses/Address.get_office.1721.js +1 -0
- data/spec/responses/District.get_by_office_state.7.GA.js +1 -0
- data/spec/responses/District.get_by_office_state.8.GA.js +1 -0
- data/spec/responses/District.get_by_office_state.9.GA.js +1 -0
- data/spec/responses/Office.get_offices_by_type.C.js +1 -0
- data/spec/responses/Office.get_offices_by_type.L.js +1 -0
- data/spec/responses/Office.get_offices_by_type.P.js +1 -0
- data/spec/responses/Office.get_offices_by_type.S.js +1 -0
- data/spec/responses/Office.get_types.js +1 -0
- data/spec/responses/Official.get_by_district.20451.js +1 -0
- data/spec/responses/Official.get_by_district.20689.js +1 -0
- data/spec/responses/Official.get_by_district.21397.js +1 -0
- data/spec/responses/Official.get_by_district.21946.js +1 -0
- data/spec/responses/Official.get_by_office_state.12.CO.js +1 -0
- data/spec/responses/Official.get_by_office_state.12.GA.js +1 -0
- data/spec/responses/Official.get_by_office_state.13.GA.js +1 -0
- data/spec/responses/Official.get_by_office_state.33.GA.js +1 -0
- data/spec/responses/Official.get_by_office_state.42.GA.js +1 -0
- data/spec/responses/Official.get_by_office_state.44.GA.js +1 -0
- data/spec/responses/Official.get_by_office_state.45.GA.js +1 -0
- data/spec/responses/Official.get_by_office_state.53.GA.js +1 -0
- data/spec/responses/Rating.get_sig.1863.js +1 -0
- data/spec/responses/State.get_state.GA.js +1 -0
- data/spec/responses/State.get_state_ids.js +1 -0
- data/spec/responses/authorization_failed.js +1 -0
- data/spec/spec_helper.rb +98 -0
- data/spec/vote_smart/district_spec.rb +36 -0
- data/spec/vote_smart/office_spec.rb +96 -0
- data/spec/vote_smart/official_spec.rb +56 -0
- data/spec/vote_smart/rating_spec.rb +15 -0
- data/spec/vote_smart/state_spec.rb +28 -0
- data/tasks/spec_json.rake +64 -0
- data/votesmart.gemspec +116 -0
- metadata +149 -0
@@ -0,0 +1,38 @@
|
|
1
|
+
module VoteSmart
|
2
|
+
|
3
|
+
class District < Common
|
4
|
+
|
5
|
+
attr_accessor :id, :name, :office_id, :state_id
|
6
|
+
|
7
|
+
attr_accessor :office
|
8
|
+
|
9
|
+
set_attribute_map "districtId" => :id, "name" => :name, "officeId" => :office_id, "stateId" => :state_id
|
10
|
+
|
11
|
+
def number
|
12
|
+
return unless name
|
13
|
+
|
14
|
+
scan = name.scan(/District (\d[0-9]*)/) || []
|
15
|
+
scan = scan.first || []
|
16
|
+
num = scan.first
|
17
|
+
num ? num.to_i : nil
|
18
|
+
end
|
19
|
+
|
20
|
+
def official
|
21
|
+
@official ||= Official.find_by_district(self)
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.find_all_by_office_and_state office, state
|
25
|
+
find_all_by_office_id_and_state_id(office.id, state.id)
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.find_all_by_office_id_and_state_id office_id, state_id
|
29
|
+
response_child(get_by_office_state(office_id, state_id), "districtList", "district").collect {|attributes| District.new(attributes)}
|
30
|
+
end
|
31
|
+
|
32
|
+
# Returns districts service the office and state provided
|
33
|
+
def self.get_by_office_state office_id, state_id = 'NA', district_name = ''
|
34
|
+
request("District.getByOfficeState", "officeId" => office_id, "stateId" => state_id, "districtName" => district_name)
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module VoteSmart
|
2
|
+
|
3
|
+
class Election < Common
|
4
|
+
|
5
|
+
# Returns detailed election information
|
6
|
+
def self.get_election election_id
|
7
|
+
request("Election.getElection", "electionId" => election_id)
|
8
|
+
end
|
9
|
+
|
10
|
+
# returns a list of elections based on the criteria
|
11
|
+
def self.get_election_by_year_state year, state_id
|
12
|
+
request("Election.getElectionByYearState", "year" => year, "stateId" => state_id)
|
13
|
+
end
|
14
|
+
|
15
|
+
# Returns a list of candidates in the election and election stage provided
|
16
|
+
def self.get_stage_candidates election_id, stage_id, party = ""
|
17
|
+
request("Election.getStageCandidates", "electionId" => election_id, "stageId" => stage_id, "party" => party)
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module VoteSmart
|
2
|
+
|
3
|
+
class Leadership < Common
|
4
|
+
|
5
|
+
# Returns a list of leadership positions
|
6
|
+
def self.get_positions state_id = "NA", office_id = nil
|
7
|
+
request("Leadership.getPositions", "stateId" => state_id, "officeId" => office_id)
|
8
|
+
end
|
9
|
+
|
10
|
+
# Returns a list of candidates in specific leadership positions
|
11
|
+
def self.get_officials leadership_id, state_id = "NA"
|
12
|
+
request("Leadership.getOfficials", "leadershipId" => leadership_id, "stateId" => state_id)
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module VoteSmart
|
2
|
+
|
3
|
+
class Local < Common
|
4
|
+
|
5
|
+
# Returns a list of cities in a given state
|
6
|
+
def get_cities state_id
|
7
|
+
request("Local.getCities", "stateId" => state_id)
|
8
|
+
end
|
9
|
+
|
10
|
+
# Returns a list of counties in a given state.
|
11
|
+
def get_counties state_id
|
12
|
+
request("Local.getCounties", "stateId" => state_id)
|
13
|
+
end
|
14
|
+
|
15
|
+
#
|
16
|
+
def get_officials local_id
|
17
|
+
request("Local.getOfficials", "localId" => local_id)
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module VoteSmart
|
2
|
+
|
3
|
+
class Measure < Common
|
4
|
+
|
5
|
+
# Returns a ballot measure's details
|
6
|
+
def self.get_measure measure_id
|
7
|
+
request("Measure.getMeasure", "measureId" => measure_id)
|
8
|
+
end
|
9
|
+
|
10
|
+
# Returns a list of ballot measures that fit the criteria
|
11
|
+
def self.get_measures_by_year_state year, state_id
|
12
|
+
request("Measure.getMeasuresByYearState", "year" => year, "stateId" => state_id)
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,119 @@
|
|
1
|
+
module VoteSmart
|
2
|
+
|
3
|
+
class Office < Common
|
4
|
+
|
5
|
+
attr_accessor :id, :type_id, :level_id, :branch_id, :name, :title, :short_title
|
6
|
+
|
7
|
+
attr_accessor :office
|
8
|
+
|
9
|
+
set_attribute_map "officeId" => :id, "officeTypeId" => :type_id, "officeLevelId" => :level_id,
|
10
|
+
"officeBranchId" => :branch_id, "name" => :name, "title" => :title, "shortTitle" => :short_title
|
11
|
+
|
12
|
+
def districts_by_state_id state_id
|
13
|
+
@districts_by_state ||= {}
|
14
|
+
districts = District.find_all_by_office_id_and_state_id(self.id, state_id)
|
15
|
+
districts.each { |district| district.office = self }
|
16
|
+
@districts_by_state[state_id] ||= districts
|
17
|
+
end
|
18
|
+
|
19
|
+
def district_by_state_id_and_number state_id, number
|
20
|
+
number = number.to_i
|
21
|
+
districts = districts_by_state_id(state_id)
|
22
|
+
districts.find {|district| district.number == number}
|
23
|
+
end
|
24
|
+
|
25
|
+
def official_by_state_id state_id
|
26
|
+
@official_by_state ||= {}
|
27
|
+
official = Official.find_by_office_id_and_state_id(self.id, state_id)
|
28
|
+
official.office = self if official
|
29
|
+
@official_by_state[state_id] ||= official
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.all
|
33
|
+
Type.all.collect { |type| find_all_by_type(type) }.uniq.flatten
|
34
|
+
end
|
35
|
+
|
36
|
+
def self.find_all_by_type type
|
37
|
+
find_all_by_type_id(type.id)
|
38
|
+
end
|
39
|
+
|
40
|
+
def self.find_all_by_type_id type_id
|
41
|
+
response_child(get_offices_by_type(type_id), "offices", "office").collect {|attributes| Office.new(attributes)}
|
42
|
+
end
|
43
|
+
|
44
|
+
def self.find_by_name name
|
45
|
+
Office.all.collect {|office| office if office.name == name }.compact.first
|
46
|
+
end
|
47
|
+
|
48
|
+
def self.find_all_by_name names
|
49
|
+
offices = Office.all
|
50
|
+
names.collect {|name| offices.find {|office| office.name == name }}
|
51
|
+
end
|
52
|
+
|
53
|
+
# Gets a list of office types
|
54
|
+
def self.get_types
|
55
|
+
request("Office.getTypes")
|
56
|
+
end
|
57
|
+
|
58
|
+
# Returns branches of government and their respective IDs
|
59
|
+
def self.get_branches
|
60
|
+
request("Office.getBranches")
|
61
|
+
end
|
62
|
+
|
63
|
+
# Returns levels of government and their respective IDs
|
64
|
+
def self.get_levels
|
65
|
+
request("Office.getLevels")
|
66
|
+
end
|
67
|
+
|
68
|
+
# Returns a list of offices by office type
|
69
|
+
def self.get_offices_by_type type_id
|
70
|
+
request("Office.getOfficesByType", "typeId" => type_id)
|
71
|
+
end
|
72
|
+
|
73
|
+
# Returns a list of offices by level of government
|
74
|
+
def self.get_offices_by_level level_id
|
75
|
+
request("Office.getOfficesByLevel", "levelId" => level_id)
|
76
|
+
end
|
77
|
+
|
78
|
+
# Returns a list of offices by office type and level of government
|
79
|
+
def self.get_offices_by_type_level type_id, level_id
|
80
|
+
request("Office.getOfficesByType", "levelId" => level_id, "typeId" => type_id)
|
81
|
+
end
|
82
|
+
|
83
|
+
# Returns a list of offices by branch and level of government
|
84
|
+
def self.get_offices_by_branch_level branch_id, level_id
|
85
|
+
request("Office.getOfficesByBranchLevel", "branchId" => branch_id, "levelId" => level_id)
|
86
|
+
end
|
87
|
+
|
88
|
+
class Type < Common
|
89
|
+
|
90
|
+
|
91
|
+
attr_accessor :id, :level_id, :branch_id, :name
|
92
|
+
|
93
|
+
set_attribute_map "officeTypeId" => :id, "officeLevelId" => :level_id,
|
94
|
+
"officeBranchId" => :branch_id, "name" => :name
|
95
|
+
|
96
|
+
def self.all
|
97
|
+
@types ||= response_child(Office.get_types, "officeTypes", "type").collect {|attributes| Type.new(attributes)}
|
98
|
+
end
|
99
|
+
|
100
|
+
def self.find_by_name name
|
101
|
+
Type.all.collect {|type| type if type.name == name }.compact.first
|
102
|
+
end
|
103
|
+
|
104
|
+
def offices
|
105
|
+
@offices ||= Office.find_all_by_type(self)
|
106
|
+
end
|
107
|
+
|
108
|
+
def offices_by_name names
|
109
|
+
names.collect {|name| offices.find {|office| office.name == name }}
|
110
|
+
end
|
111
|
+
|
112
|
+
def office_by_name name
|
113
|
+
offices_by_name([name]).first
|
114
|
+
end
|
115
|
+
|
116
|
+
end
|
117
|
+
|
118
|
+
end
|
119
|
+
end
|
@@ -0,0 +1,131 @@
|
|
1
|
+
module VoteSmart
|
2
|
+
|
3
|
+
class Official < Common
|
4
|
+
|
5
|
+
attr_accessor :id, :first_name, :nick_name, :middle_name, :last_name, :suffix, :title,
|
6
|
+
:election_parties, :office_parties, :district_id, :district_name, :state_id
|
7
|
+
|
8
|
+
attr_accessor :district, :office, :office_id, :party
|
9
|
+
|
10
|
+
set_attribute_map "candidateId" => :id, "firstName" => :first_name, "nickName" => :nick_name,
|
11
|
+
"middleName" => :middle_name, "lastName" => :last_name, "suffix" => :suffix,
|
12
|
+
"title" => :title, "electionParties" => :election_parties, "officeDistrictId" => :district_id,
|
13
|
+
"officeDistrictName" => :district_name, "officeParties" => :party, "officeStateId" => :state_id
|
14
|
+
|
15
|
+
def offices
|
16
|
+
offices = Official.response_child(Address.get_office(self.id), "address", "office")
|
17
|
+
(offices.is_a?(Array) ? offices : [offices]).collect {|office|
|
18
|
+
CandidateOffice.new(office)
|
19
|
+
}
|
20
|
+
end
|
21
|
+
|
22
|
+
def inspect
|
23
|
+
"Official: " + [title, first_name, last_name].compact.join(' ')
|
24
|
+
end
|
25
|
+
|
26
|
+
def office_id
|
27
|
+
@office_id || (office.id if office)
|
28
|
+
end
|
29
|
+
|
30
|
+
def self.find_by_district district
|
31
|
+
official = find_by_district_id district.id
|
32
|
+
official.district = district if official
|
33
|
+
official.office = district.office if official
|
34
|
+
official
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.find_by_district_id district_id
|
38
|
+
response = response_child(get_by_district(district_id), "candidateList", "candidate")
|
39
|
+
Official.new(response) unless response.empty?
|
40
|
+
end
|
41
|
+
|
42
|
+
def self.find_by_office_id_and_state_id office_id, state_id
|
43
|
+
response = response_child(get_by_office_state(office_id, state_id), "candidateList", "candidate")
|
44
|
+
official = Official.new(response) unless response.empty?
|
45
|
+
official.office_id = office_id if official
|
46
|
+
official.state_id ||= state_id if official
|
47
|
+
official
|
48
|
+
end
|
49
|
+
|
50
|
+
|
51
|
+
|
52
|
+
def self.find_all_by_address address, city, state, zip
|
53
|
+
placemark = Geocoding.get("#{address} #{city}, #{state} #{zip}").first
|
54
|
+
|
55
|
+
return [] unless placemark
|
56
|
+
|
57
|
+
state ||= placemark.administrative_area
|
58
|
+
|
59
|
+
placemark ? find_all_by_state_and_latitude_and_longitude(state, placemark.latitude, placemark.longitude) : []
|
60
|
+
end
|
61
|
+
|
62
|
+
def self.find_all_by_state_and_latitude_and_longitude state, latitude, longitude
|
63
|
+
response = Mcll4r.new.district_lookup(latitude, longitude)
|
64
|
+
response = response["response"] if response
|
65
|
+
|
66
|
+
state_upper = (response["state_upper"] || {})["district"]
|
67
|
+
state_lower = (response["state_lower"] || {})["district"]
|
68
|
+
|
69
|
+
find_all_state_wide_officials(state) + find_state_legislators(state, state_upper, state_lower, state_lower)
|
70
|
+
end
|
71
|
+
|
72
|
+
def self.find_all_state_wide_officials state_id
|
73
|
+
state_wide_office_names = ["Secretary of State", "Secretary of the Commonwealth", "Attorney General", "Secretary of Education",
|
74
|
+
"Education Secretary", "Treasurer", "Auditor"]
|
75
|
+
|
76
|
+
state_wide_type = Office::Type.find_by_name("State Wide")
|
77
|
+
|
78
|
+
state_wide_offices = state_wide_type ? state_wide_type.offices_by_name(state_wide_office_names) : []
|
79
|
+
|
80
|
+
state_wide_offices.collect { |office| office.official_by_state_id(state_id) }.compact
|
81
|
+
end
|
82
|
+
|
83
|
+
def self.find_state_legislators state_id, senate_district, house_district, assembly_district
|
84
|
+
officials = []
|
85
|
+
|
86
|
+
state_leg_type = Office::Type.find_by_name("State Legislature")
|
87
|
+
|
88
|
+
{"State Senate" => senate_district,
|
89
|
+
"State House" => house_district,
|
90
|
+
"State Assembly" => assembly_district}.each do |office_name, district_number|
|
91
|
+
|
92
|
+
office = state_leg_type.office_by_name(office_name) if state_leg_type
|
93
|
+
|
94
|
+
district = office.district_by_state_id_and_number(state_id, district_number) if office
|
95
|
+
|
96
|
+
official = district.official if district
|
97
|
+
|
98
|
+
officials.push official if official
|
99
|
+
end
|
100
|
+
|
101
|
+
officials
|
102
|
+
end
|
103
|
+
|
104
|
+
|
105
|
+
# Returns a list of incumbents that fit the criteria
|
106
|
+
def self.get_by_office_state office_id, state_id = 'NA'
|
107
|
+
request("Officials.getByOfficeState", "officeId" => office_id, "stateId" => state_id)
|
108
|
+
end
|
109
|
+
|
110
|
+
# Searches for incumbents with exact lastname matches
|
111
|
+
def self.get_by_lastname lastname
|
112
|
+
request("Officials.getByLastname", "lastName" => lastname)
|
113
|
+
end
|
114
|
+
|
115
|
+
# Searches for incumbents with fuzzy lastname match
|
116
|
+
def self.get_by_levenstein lastname
|
117
|
+
request("Officials.getByLevenstein", "lastName" => lastname)
|
118
|
+
end
|
119
|
+
|
120
|
+
# Returns incumbents in the provided election_id
|
121
|
+
def self.get_by_election election_id
|
122
|
+
request("Officials.getByElection", "electionId" => election_id)
|
123
|
+
end
|
124
|
+
|
125
|
+
# Returns incumbents in the provided district_id
|
126
|
+
def self.get_by_district district_id
|
127
|
+
request("Officials.getByDistrict", "districtId" => district_id)
|
128
|
+
end
|
129
|
+
|
130
|
+
end
|
131
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
module VoteSmart
|
2
|
+
|
3
|
+
class Phone < Common
|
4
|
+
|
5
|
+
attr_accessor :phone1, :phone2, :fax1, :fax2, :toll_free, :ttyd
|
6
|
+
|
7
|
+
set_attribute_map "phone1" => :phone1, "phone2" => :phone2, "fax1" => :fax1, "fax2" => :fax2,
|
8
|
+
"tollFree" => :toll_free, "ttyd" => :ttyd
|
9
|
+
|
10
|
+
end
|
11
|
+
|
12
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module VoteSmart
|
2
|
+
|
3
|
+
class Rating < Common
|
4
|
+
|
5
|
+
# Returns categories with ratings according to state_id(NA = fed)
|
6
|
+
def self.get_categories state_id = nil
|
7
|
+
request("Rating.getCategories", "stateId" => state_id)
|
8
|
+
end
|
9
|
+
|
10
|
+
# Returns a list of SIGs with ratings in category and state
|
11
|
+
def self.get_sig_list category_id, state_id = 'NA'
|
12
|
+
request("Rating.getSigList", "categoryId" => category_id, "stateId" => state_id)
|
13
|
+
end
|
14
|
+
|
15
|
+
# Returns detailed SIG information
|
16
|
+
def self.get_sig sig_id
|
17
|
+
result = request("Rating.getSig", "sigId" => sig_id)
|
18
|
+
# PVS return utf control codes for punction in descriptions
|
19
|
+
if result['sig']['description'].first == '"'
|
20
|
+
result['sig']['description'] = result['sig']['description'][1..-2]
|
21
|
+
end
|
22
|
+
result['sig']['description'] = result['sig']['description'].unpack("U*").map do |char|
|
23
|
+
case char
|
24
|
+
when 146 # 0092
|
25
|
+
39
|
26
|
+
when 148, 147 # 0093,4
|
27
|
+
34
|
28
|
+
when 150, 151 # 0096,7
|
29
|
+
45
|
30
|
+
else
|
31
|
+
char
|
32
|
+
end
|
33
|
+
end.pack("U*")
|
34
|
+
result
|
35
|
+
end
|
36
|
+
|
37
|
+
# Returns an SIG's rating on a specific candidate
|
38
|
+
def self.get_candidate_rating candidate_id, sig_id
|
39
|
+
request("Rating.getCandidateRating", "candidateId" => candidate_id, "sigId" => sig_id)
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
43
|
+
end
|