luigi-sunlight 0.2.0 → 0.9.0
Sign up to get free protection for your applications and to get access to all the features.
- data/CHANGES.textile +13 -0
- data/README.textile +62 -34
- data/lib/sunlight.rb +0 -54
- data/lib/sunlight/base.rb +57 -0
- data/lib/sunlight/district.rb +6 -6
- data/lib/sunlight/filing.rb +119 -0
- data/lib/sunlight/issue.rb +15 -0
- data/lib/sunlight/legislator.rb +11 -12
- data/lib/sunlight/lobbyist.rb +63 -0
- data/sunlight.gemspec +6 -4
- metadata +6 -2
data/CHANGES.textile
CHANGED
@@ -1,3 +1,16 @@
|
|
1
|
+
h3. 0.9.0 / 2009-03-15
|
2
|
+
|
3
|
+
* Warning: This release is not backwards-compatible!
|
4
|
+
* Change loading behavior of base functionality, works better with Rails and Merb
|
5
|
+
* Sunlight::SunlightObject is now Sunlight::Base
|
6
|
+
* For set up, Sunlight.api_key= is now Sunlight::Base.api_key=
|
7
|
+
* For set up, using "include 'Sunlight'" is no longer recommended
|
8
|
+
* Correct usage is Sunlight::Legislator.all_for(...) instead of just Legislator.all_for(...)
|
9
|
+
* Credit to Rue the Ghetto (rughetto on GitHub) and Eric Mill for inspiring the improvements above
|
10
|
+
* Add support for senate_class ("I", "II", or "III") and in_office (0 or 1) on Legislator
|
11
|
+
* Add support for Lobbyists, Filings, and Issues
|
12
|
+
* Huge credit to mindleak on GitHub for Lobbyist-related functionality
|
13
|
+
|
1
14
|
h3. 0.2.0 / 2009-03-01
|
2
15
|
|
3
16
|
* Add support for twitter_id and youtube_url on Legislator
|
data/README.textile
CHANGED
@@ -36,16 +36,15 @@ h2. Set Up
|
|
36
36
|
|
37
37
|
First, register for an API key "here":http://services.sunlightlabs.com/api/register/.
|
38
38
|
|
39
|
-
Then, you'll want to stick the following lines somewhere in your Ruby environment.
|
39
|
+
Then, you'll want to stick the following lines somewhere in your Ruby environment. _Note, this set up changed slightly as of version 0.9.0:_
|
40
40
|
|
41
41
|
<pre><code>
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
Sunlight.api_key = 'yourapikeyfromtheurlabove'
|
42
|
+
require 'rubygems'
|
43
|
+
require 'sunlight'
|
44
|
+
Sunlight::Base.api_key = 'yourapikeyfromtheurlabove'
|
46
45
|
</code></pre>
|
47
46
|
|
48
|
-
If you're testing this out in IRB, you'll run them one at a time. If you're using Rails 2.1, stick them in a file called @sunlight.rb@ in @RAILS_ROOT/config/initializers@. They'll load on app startup.
|
47
|
+
If you're testing this out in IRB, you'll run them one at a time. If you're using Rails >=2.1, stick them in a file called @sunlight.rb@ in @RAILS_ROOT/config/initializers@. They'll load on app startup.
|
49
48
|
|
50
49
|
h2. Usage
|
51
50
|
|
@@ -56,15 +55,15 @@ h3. Legislator
|
|
56
55
|
Time to get to the good stuff. The most useful method is @Legislator#all_for@:
|
57
56
|
|
58
57
|
<pre><code>
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
58
|
+
congresspeople = Sunlight::Legislator.all_for(:address => "123 Fifth Ave New York, NY 10003")
|
59
|
+
senior_senator = congresspeople[:senior_senator]
|
60
|
+
junior_senator = congresspeople[:junior_senator]
|
61
|
+
representative = congresspeople[:representative]
|
62
|
+
|
63
|
+
junior_senator.firstname # returns "Kirsten"
|
64
|
+
junior_senator.lastname # returns "Gillibrand"
|
65
|
+
junior_senator.congress_office # returns "531 Dirksen Senate Office Building"
|
66
|
+
junior_senator.phone # returns "202-224-4451"
|
68
67
|
</code></pre>
|
69
68
|
|
70
69
|
Note that you should make the best attempt to get a full street address, as that is geocoded behind the scenes into a lat/long pair. If all you have is a five-digit zip code, you should not use @Legislator#all_for@, instead opting for @Legislator#all_in_zipcode@ (see below). If you pass in a zip+4, then go ahead and use @Legislator#all_for@.
|
@@ -72,7 +71,7 @@ Note that you should make the best attempt to get a full street address, as that
|
|
72
71
|
So @Legislator#all_for@ returns a hash of @Legislator@ objects, and the keys are @:senior_senator@, @:junior_senator@, and @:representative@. Make sure to review all the available fields from the "Sunlight Labs API":http://services.sunlightlabs.com/api/docs/legislators/. You can also pass in a lat/long pair:
|
73
72
|
|
74
73
|
<pre><code>
|
75
|
-
|
74
|
+
congresspeople = Sunlight::Legislator.all_for(:latitude => 33.876145, :longitude => -84.453789)
|
76
75
|
</code></pre>
|
77
76
|
|
78
77
|
This bypasses the geocoding necessary by the Google Maps API. For social networks and other applications with a User object, it makes sense to geocode the user's address up front and save the lat/long data in the local database. Then, use the lat/long pair instead of address, which cuts a substantial bit of time from the @Legislator#all_for@ request since the Google Maps API Geocoding function doesn't have to be called.
|
@@ -80,31 +79,30 @@ This bypasses the geocoding necessary by the Google Maps API. For social network
|
|
80
79
|
Have a five-digit zip code only? You can use the @Legislator#all_in_zipcode@ method, but keep in mind that a single zip may have multiple U.S. Representatives, as congressional district lines frequently divide populous zip codes. Unlike @Legislator#all_for@, this method returns an array of legislators, and it'll be up to you to parse through them (there will be a senior senator, a junior senator, and one or more representatives).
|
81
80
|
|
82
81
|
<pre><code>
|
83
|
-
members_of_congress = Legislator.all_in_zipcode(90210)
|
84
|
-
|
82
|
+
members_of_congress = Sunlight::Legislator.all_in_zipcode(90210)
|
83
|
+
|
85
84
|
members_of_congress.each do |member|
|
86
85
|
# do stuff
|
87
86
|
end
|
88
|
-
|
89
87
|
</code></pre>
|
90
88
|
|
91
89
|
You can also use the @Legislator#all_where@ method for searching based on available fields. Again, you'll get back an array of @Legislator@ objects:
|
92
90
|
|
93
91
|
<pre><code>
|
94
|
-
|
95
|
-
|
96
|
-
|
92
|
+
johns = Sunlight::Legislator.all_where(:firstname => "John")
|
93
|
+
floridians = Sunlight::Legislator.all_where(:state => "FL")
|
94
|
+
dudes = Sunlight::Legislator.all_where(:gender => "M")
|
97
95
|
|
98
|
-
|
99
|
-
|
100
|
-
|
96
|
+
johns.each do |john|
|
97
|
+
# do stuff
|
98
|
+
end
|
101
99
|
</code></pre>
|
102
100
|
|
103
101
|
Lastly, to provide your users with a name search functionality, use @Legislator#search_by_name@, which uses fuzzy matching to compensate for nicknames and misspellings. So "Teddy Kennedey" (real name Edward Kennedy) and "Jack Murtha" (real name John Murtha) will return the correct matches. You can specify a higher confidence threshold (default set to 0.80) if you feel that the matches being returned aren't accurate enough. This also returns an array of @Legislator@ objects:
|
104
102
|
|
105
103
|
<pre><code>
|
106
|
-
legislators = Legislator.search_by_name("Teddy Kennedey")
|
107
|
-
legislators = Legislator.search_by_name("Johnny Boy Kerry", 0.91)
|
104
|
+
legislators = Sunlight::Legislator.search_by_name("Teddy Kennedey")
|
105
|
+
legislators = Sunlight::Legislator.search_by_name("Johnny Boy Kerry", 0.91)
|
108
106
|
</code></pre>
|
109
107
|
|
110
108
|
|
@@ -114,18 +112,48 @@ h3. District
|
|
114
112
|
There's also the @District@ object. @District#get@ takes in either lat/long or an address and does it's best to return the correct Congressional District:
|
115
113
|
|
116
114
|
<pre><code>
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
115
|
+
district = Sunlight::District.get(:latitude => 33.876145, :longitude => -84.453789)
|
116
|
+
district.state # returns "GA"
|
117
|
+
district.number # returns "6"
|
118
|
+
|
119
|
+
district = Sunlight::District.get(:address => "123 Fifth Ave New York, NY")
|
122
120
|
</code></pre>
|
123
121
|
|
124
122
|
Finally, two more methods, @District.all_from_zipcode@ and @District.zipcodes_in@, help you out when you want to get all districts in a given zip code, or if you want to get back all zip codes in a given district.
|
125
123
|
|
126
124
|
<pre><code>
|
127
|
-
|
128
|
-
|
125
|
+
districts = Sunlight::District.all_from_zipcode(90210) # returns array of District objects
|
126
|
+
zipcodes = Sunlight::District.zipcodes_in("NY", "10") # returns array of zip codes as strings ["11201", "11202", "11203",...]
|
127
|
+
</code></pre>
|
128
|
+
|
129
|
+
h3. Lobbyists and Filings
|
130
|
+
|
131
|
+
Moving away from members of Congress, the Sunlight API also exposes data on @Lobbyists@, the organizations and companies they lobby on behalf of, and the @Issues@ they lobby on. Lobbyists must submit filings to the Senate Office of Public Records, and these are represented as @Filings@ in the API.
|
132
|
+
|
133
|
+
Like on the @Legislator@ object, the @Lobbyist@ object provides for fuzzy name search capability. However, because the universe of Lobbyists is much larger than Legislators, the confidence threshold defaults to 0.90 instead of 0.80, and also limits the search to Lobbyists who have filed in the current year. Both can be adjusted, and the method returns an array of @Lobbyist@ objects:
|
134
|
+
|
135
|
+
<pre><code>
|
136
|
+
lobbyists = Lobbyist.search("Nisha Thompsen")
|
137
|
+
lobbyists = Lobbyist.search("Michael Klein", 0.95, 2007)
|
138
|
+
</code></pre>
|
139
|
+
|
140
|
+
You can also use the @Filing@ object to get a specific filing record, where the unique identifier comes from the "Senate Office of Public Records":http://senate.gov/legislative/Public_Disclosure/LDA_reports.htm. The @Filing@ object will have an array of issues and lobbyists associated to it.
|
141
|
+
|
142
|
+
<pre><code>
|
143
|
+
filing = Sunlight::Filing.get("29D4D19E-CB7D-46D2-99F0-27FF15901A4C")
|
144
|
+
filing.issues.each { |issue| ... }
|
145
|
+
filing.lobbyists.each { |lobbyist| ... }
|
146
|
+
</code></pre>
|
147
|
+
|
148
|
+
If you have a client name (that is, the organization or company the lobbyist works for) or the registrant name (the lobbyist), then you can also find associated filings. To use the @all_where@ method, pass in a hash with @:client_name@, @:registrant_name@, and @:year@ as the keys. You must pass in @:client_name@ or @:registrant_name@.
|
149
|
+
|
150
|
+
<pre><code>
|
151
|
+
filings = Filing.all_where(:client_name => "SUNLIGHT FOUNDATION")
|
152
|
+
filings.each do |filing|
|
153
|
+
...
|
154
|
+
filing.issues.each { |issue| ... }
|
155
|
+
filing.lobbyists.each { |issue| ... }
|
156
|
+
end
|
129
157
|
</code></pre>
|
130
158
|
|
131
159
|
|
data/lib/sunlight.rb
CHANGED
@@ -5,58 +5,4 @@ require 'ym4r/google_maps/geocoding'
|
|
5
5
|
require 'net/http'
|
6
6
|
include Ym4r::GoogleMaps
|
7
7
|
|
8
|
-
module Sunlight
|
9
|
-
|
10
|
-
API_URL = "http://services.sunlightlabs.com/api/"
|
11
|
-
API_FORMAT = "json"
|
12
|
-
attr_accessor :api_key
|
13
|
-
|
14
|
-
# Houses general methods to work with the Sunlight and Google Maps APIs
|
15
|
-
class SunlightObject
|
16
|
-
|
17
|
-
|
18
|
-
# Constructs a Sunlight API-friendly URL
|
19
|
-
def self.construct_url(api_method, params)
|
20
|
-
if Sunlight.api_key == nil or Sunlight.api_key == ''
|
21
|
-
raise "Failed to provide Sunlight API Key"
|
22
|
-
else
|
23
|
-
"#{API_URL}#{api_method}.#{API_FORMAT}?apikey=#{Sunlight.api_key}#{hash2get(params)}"
|
24
|
-
end
|
25
|
-
end
|
26
|
-
|
27
|
-
|
28
|
-
# Converts a hash to a GET string
|
29
|
-
def self.hash2get(h)
|
30
|
-
|
31
|
-
get_string = ""
|
32
|
-
|
33
|
-
h.each_pair do |key, value|
|
34
|
-
get_string += "&#{key.to_s}=#{CGI::escape(value.to_s)}"
|
35
|
-
end
|
36
|
-
|
37
|
-
get_string
|
38
|
-
|
39
|
-
end # def hash2get
|
40
|
-
|
41
|
-
|
42
|
-
# Use the Net::HTTP and JSON libraries to make the API call
|
43
|
-
#
|
44
|
-
# Usage:
|
45
|
-
# District.get_json_data("http://someurl.com") # returns Hash of data or nil
|
46
|
-
def self.get_json_data(url)
|
47
|
-
|
48
|
-
response = Net::HTTP.get_response(URI.parse(url))
|
49
|
-
if response.class == Net::HTTPOK
|
50
|
-
result = JSON.parse(response.body)
|
51
|
-
else
|
52
|
-
nil
|
53
|
-
end
|
54
|
-
|
55
|
-
end # self.get_json_data
|
56
|
-
|
57
|
-
|
58
|
-
end # class SunlightObject
|
59
|
-
|
60
|
-
end # module Sunlight
|
61
|
-
|
62
8
|
Dir["#{File.dirname(__FILE__)}/sunlight/*.rb"].each { |source_file| require source_file }
|
@@ -0,0 +1,57 @@
|
|
1
|
+
module Sunlight
|
2
|
+
|
3
|
+
# Houses general methods to work with the Sunlight and Google Maps APIs
|
4
|
+
class Base
|
5
|
+
|
6
|
+
API_URL = "http://services.sunlightlabs.com/api/"
|
7
|
+
API_FORMAT = "json"
|
8
|
+
@@api_key = ''
|
9
|
+
|
10
|
+
def self.api_key
|
11
|
+
@@api_key
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.api_key=(key)
|
15
|
+
@@api_key = key
|
16
|
+
end
|
17
|
+
|
18
|
+
# Constructs a Sunlight API-friendly URL
|
19
|
+
def self.construct_url(api_method, params)
|
20
|
+
if api_key == nil or api_key == ''
|
21
|
+
raise "Failed to provide Sunlight API Key"
|
22
|
+
else
|
23
|
+
"#{API_URL}#{api_method}.#{API_FORMAT}?apikey=#{api_key}#{hash2get(params)}"
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
# Converts a hash to a GET string
|
28
|
+
def self.hash2get(h)
|
29
|
+
|
30
|
+
get_string = ""
|
31
|
+
|
32
|
+
h.each_pair do |key, value|
|
33
|
+
get_string += "&#{key.to_s}=#{CGI::escape(value.to_s)}"
|
34
|
+
end
|
35
|
+
|
36
|
+
get_string
|
37
|
+
|
38
|
+
end # def hash2get
|
39
|
+
|
40
|
+
# Use the Net::HTTP and JSON libraries to make the API call
|
41
|
+
#
|
42
|
+
# Usage:
|
43
|
+
# Legislator::District.get_json_data("http://someurl.com") # returns Hash of data or nil
|
44
|
+
def self.get_json_data(url)
|
45
|
+
|
46
|
+
response = Net::HTTP.get_response(URI.parse(url))
|
47
|
+
if response.class == Net::HTTPOK
|
48
|
+
result = JSON.parse(response.body)
|
49
|
+
else
|
50
|
+
nil
|
51
|
+
end
|
52
|
+
|
53
|
+
end # self.get_json_data
|
54
|
+
|
55
|
+
end # class Base
|
56
|
+
|
57
|
+
end # module Sunlight
|
data/lib/sunlight/district.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
module Sunlight
|
2
2
|
|
3
|
-
class District <
|
3
|
+
class District < Base
|
4
4
|
|
5
5
|
attr_accessor :state, :number
|
6
6
|
|
@@ -11,8 +11,8 @@ module Sunlight
|
|
11
11
|
|
12
12
|
|
13
13
|
# Usage:
|
14
|
-
# District.get(:latitude => 33.876145, :longitude => -84.453789) # returns one District object or nil
|
15
|
-
# District.get(:address => "123 Fifth Ave New York, NY") # returns one District object or nil
|
14
|
+
# Sunlight::District.get(:latitude => 33.876145, :longitude => -84.453789) # returns one District object or nil
|
15
|
+
# Sunlight::District.get(:address => "123 Fifth Ave New York, NY") # returns one District object or nil
|
16
16
|
#
|
17
17
|
def self.get(params)
|
18
18
|
|
@@ -39,7 +39,7 @@ module Sunlight
|
|
39
39
|
|
40
40
|
|
41
41
|
# Usage:
|
42
|
-
# District.get_from_lat_long(-123, 123) # returns District object or nil
|
42
|
+
# Sunlight::District.get_from_lat_long(-123, 123) # returns District object or nil
|
43
43
|
#
|
44
44
|
def self.get_from_lat_long(latitude, longitude)
|
45
45
|
|
@@ -63,7 +63,7 @@ module Sunlight
|
|
63
63
|
|
64
64
|
|
65
65
|
# Usage:
|
66
|
-
# District.all_from_zipcode(90210) # returns array of District objects
|
66
|
+
# Sunlight::District.all_from_zipcode(90210) # returns array of District objects
|
67
67
|
#
|
68
68
|
def self.all_from_zipcode(zipcode)
|
69
69
|
|
@@ -87,7 +87,7 @@ module Sunlight
|
|
87
87
|
|
88
88
|
|
89
89
|
# Usage:
|
90
|
-
# District.zipcodes_in("NY", 29) # returns ["14009", "14024", "14029", ...]
|
90
|
+
# Sunlight::District.zipcodes_in("NY", 29) # returns ["14009", "14024", "14029", ...]
|
91
91
|
#
|
92
92
|
def self.zipcodes_in(state, number)
|
93
93
|
|
@@ -0,0 +1,119 @@
|
|
1
|
+
module Sunlight
|
2
|
+
|
3
|
+
class Filing < Base
|
4
|
+
attr_accessor :filing_id, :filing_period, :filing_date, :filing_amount,
|
5
|
+
:filing_year, :filing_type, :filing_pdf, :client_senate_id,
|
6
|
+
:client_name, :client_country, :client_state,
|
7
|
+
:client_ppb_country, :client_ppb_state, :client_description,
|
8
|
+
:client_contact_firstname, :client_contact_middlename,
|
9
|
+
:client_contact_lastname, :client_contact_suffix,
|
10
|
+
:registrant_senate_id, :registrant_name, :registrant_address,
|
11
|
+
:registrant_description, :registrant_country,
|
12
|
+
:registrant_ppb_country, :lobbyists, :issues
|
13
|
+
|
14
|
+
# Takes in a hash where the keys are strings (the format passed in by the JSON parser)
|
15
|
+
#
|
16
|
+
def initialize(params)
|
17
|
+
params.each do |key, value|
|
18
|
+
instance_variable_set("@#{key}", value) if Filing.instance_methods.include? key
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
#
|
23
|
+
# Get a filing based on filing ID.
|
24
|
+
#
|
25
|
+
# See the API documentation:
|
26
|
+
#
|
27
|
+
# http://wiki.sunlightlabs.com/index.php/Lobbyists.getFiling
|
28
|
+
#
|
29
|
+
# Returns:
|
30
|
+
#
|
31
|
+
# A Filing and corresponding Lobbyists and Issues matching
|
32
|
+
# the given ID, or nil if one wasn't found.
|
33
|
+
#
|
34
|
+
# Usage:
|
35
|
+
#
|
36
|
+
# filing = Sunlight::Filing.get("29D4D19E-CB7D-46D2-99F0-27FF15901A4C")
|
37
|
+
# filing.issues.each { |issue| ... }
|
38
|
+
# filing.lobbyists.each { |lobbyist| ... }
|
39
|
+
#
|
40
|
+
def self.get(id)
|
41
|
+
url = construct_url("lobbyists.getFiling", :id => id)
|
42
|
+
|
43
|
+
if (response = get_json_data(url))
|
44
|
+
if (f = response["response"]["filing"])
|
45
|
+
filing = Filing.new(f)
|
46
|
+
filing.lobbyists = filing.lobbyists.map do |lobbyist|
|
47
|
+
Lobbyist.new(lobbyist["lobbyist"])
|
48
|
+
end
|
49
|
+
filing.issues = filing.issues.map do |issue|
|
50
|
+
Issue.new(issue["issue"])
|
51
|
+
end
|
52
|
+
filing
|
53
|
+
else
|
54
|
+
nil
|
55
|
+
end
|
56
|
+
else
|
57
|
+
nil
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
#
|
62
|
+
# Search the filing database. At least one of client_name or
|
63
|
+
# registrant_name must be provided, along with an optional year.
|
64
|
+
# Note that year is recommended, as the full data set dating back
|
65
|
+
# to 1999 may be enormous.
|
66
|
+
#
|
67
|
+
# See the API documentation:
|
68
|
+
#
|
69
|
+
# http://wiki.sunlightlabs.com/index.php/Lobbyists.getFilingList
|
70
|
+
#
|
71
|
+
# Returns:
|
72
|
+
#
|
73
|
+
# An array of Filing objects that match the conditions
|
74
|
+
#
|
75
|
+
# Usage:
|
76
|
+
#
|
77
|
+
# filings = Filing.all_where(:client_name => "SUNLIGHT FOUNDATION")
|
78
|
+
# filings.each do |filing|
|
79
|
+
# ...
|
80
|
+
# filing.issues.each { |issue| ... }
|
81
|
+
# filing.lobbyists.each { |issue| ... }
|
82
|
+
# end
|
83
|
+
#
|
84
|
+
def self.all_where(params)
|
85
|
+
if params[:client_name].nil? and params[:registrant_name].nil?
|
86
|
+
nil
|
87
|
+
else
|
88
|
+
url = construct_url("lobbyists.getFilingList", params)
|
89
|
+
|
90
|
+
if (response = get_json_data(url))
|
91
|
+
filings = []
|
92
|
+
|
93
|
+
response["response"]["filings"].each do |result|
|
94
|
+
filing = Filing.new(result["filing"])
|
95
|
+
|
96
|
+
filing.lobbyists = filing.lobbyists.map do |lobbyist|
|
97
|
+
Lobbyist.new(lobbyist["lobbyist"])
|
98
|
+
end
|
99
|
+
filing.issues = filing.issues.map do |issue|
|
100
|
+
Issue.new(issue["issue"])
|
101
|
+
end
|
102
|
+
|
103
|
+
filings << filing
|
104
|
+
end
|
105
|
+
|
106
|
+
if filings.empty?
|
107
|
+
nil
|
108
|
+
else
|
109
|
+
filings
|
110
|
+
end
|
111
|
+
else
|
112
|
+
nil
|
113
|
+
end
|
114
|
+
end # if params
|
115
|
+
end # def self.all_where
|
116
|
+
|
117
|
+
end # class Filing
|
118
|
+
|
119
|
+
end # module Sunlight
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module Sunlight
|
2
|
+
|
3
|
+
class Issue < Base
|
4
|
+
attr_accessor :code, :specific_issue
|
5
|
+
|
6
|
+
# Takes in a hash where the keys are strings (the format passed in by the JSON parser)
|
7
|
+
#
|
8
|
+
def initialize(params)
|
9
|
+
params.each do |key, value|
|
10
|
+
instance_variable_set("@#{key}", value) if Issue.instance_methods.include? key
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
data/lib/sunlight/legislator.rb
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
module Sunlight
|
2
2
|
|
3
|
-
class Legislator <
|
3
|
+
class Legislator < Base
|
4
4
|
|
5
5
|
|
6
6
|
attr_accessor :title, :firstname, :middlename, :lastname, :name_suffix, :nickname,
|
7
7
|
:party, :state, :district, :gender, :phone, :fax, :website, :webform,
|
8
8
|
:email, :congress_office, :bioguide_id, :votesmart_id, :fec_id,
|
9
9
|
:govtrack_id, :crp_id, :event_id, :congresspedia_url, :youtube_url,
|
10
|
-
:twitter_id, :fuzzy_score
|
10
|
+
:twitter_id, :fuzzy_score, :in_office, :senate_class
|
11
11
|
|
12
12
|
# Takes in a hash where the keys are strings (the format passed in by the JSON parser)
|
13
13
|
#
|
@@ -18,7 +18,6 @@ module Sunlight
|
|
18
18
|
end
|
19
19
|
|
20
20
|
|
21
|
-
|
22
21
|
#
|
23
22
|
# Useful for getting the exact Legislators for a given district.
|
24
23
|
#
|
@@ -35,8 +34,8 @@ module Sunlight
|
|
35
34
|
# junior = officials[:junior_senator]
|
36
35
|
# rep = officials[:representative]
|
37
36
|
#
|
38
|
-
# Legislator.all_for(:address => "123 Fifth Ave New York, NY 10003")
|
39
|
-
# Legislator.all_for(:address => "90210") # it'll work, but use all_in_zip instead
|
37
|
+
# Sunlight::Legislator.all_for(:address => "123 Fifth Ave New York, NY 10003")
|
38
|
+
# Sunlight::Legislator.all_for(:address => "90210") # it'll work, but use all_in_zip instead
|
40
39
|
#
|
41
40
|
def self.all_for(params)
|
42
41
|
|
@@ -57,7 +56,7 @@ module Sunlight
|
|
57
56
|
#
|
58
57
|
# Usage:
|
59
58
|
#
|
60
|
-
# officials = Legislator.all_in_district(District.new("NJ", "7"))
|
59
|
+
# officials = Sunlight::Legislator.all_in_district(District.new("NJ", "7"))
|
61
60
|
#
|
62
61
|
def self.all_in_district(district)
|
63
62
|
|
@@ -82,9 +81,9 @@ module Sunlight
|
|
82
81
|
#
|
83
82
|
# Usage:
|
84
83
|
#
|
85
|
-
# johns = Legislator.all_where(:firstname => "John")
|
86
|
-
# floridians = Legislator.all_where(:state => "FL")
|
87
|
-
# dudes = Legislator.all_where(:gender => "M")
|
84
|
+
# johns = Sunlight::Legislator.all_where(:firstname => "John")
|
85
|
+
# floridians = Sunlight::Legislator.all_where(:state => "FL")
|
86
|
+
# dudes = Sunlight::Legislator.all_where(:gender => "M")
|
88
87
|
#
|
89
88
|
def self.all_where(params)
|
90
89
|
|
@@ -119,7 +118,7 @@ module Sunlight
|
|
119
118
|
#
|
120
119
|
# Usage:
|
121
120
|
#
|
122
|
-
# legislators = Legislator.all_in_zipcode(90210)
|
121
|
+
# legislators = Sunlight::Legislator.all_in_zipcode(90210)
|
123
122
|
#
|
124
123
|
def self.all_in_zipcode(zipcode)
|
125
124
|
|
@@ -156,8 +155,8 @@ module Sunlight
|
|
156
155
|
#
|
157
156
|
# Usage:
|
158
157
|
#
|
159
|
-
# legislators = Legislator.search_by_name("Teddy Kennedey")
|
160
|
-
# legislators = Legislator.search_by_name("Johnny Kerry", 0.9)
|
158
|
+
# legislators = Sunlight::Legislator.search_by_name("Teddy Kennedey")
|
159
|
+
# legislators = Sunlight::Legislator.search_by_name("Johnny Kerry", 0.9)
|
161
160
|
#
|
162
161
|
def self.search_by_name(name, threshold='0.8')
|
163
162
|
|
@@ -0,0 +1,63 @@
|
|
1
|
+
module Sunlight
|
2
|
+
|
3
|
+
class Lobbyist < Base
|
4
|
+
attr_accessor :firstname, :middlename, :lastname, :suffix,
|
5
|
+
:official_position, :filings, :fuzzy_score
|
6
|
+
|
7
|
+
# Takes in a hash where the keys are strings (the format passed in by the JSON parser)
|
8
|
+
#
|
9
|
+
def initialize(params)
|
10
|
+
params.each do |key, value|
|
11
|
+
instance_variable_set("@#{key}", value) if Lobbyist.instance_methods.include? key
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
#
|
16
|
+
# Fuzzy name searching of lobbyists. Returns possible matching Lobbyists
|
17
|
+
# along with a confidence score. Confidence scores below 0.8
|
18
|
+
# mean the lobbyist should not be used.
|
19
|
+
#
|
20
|
+
# See the API documentation:
|
21
|
+
#
|
22
|
+
# http://wiki.sunlightlabs.com/index.php/Lobbyists.search
|
23
|
+
#
|
24
|
+
# Returns:
|
25
|
+
#
|
26
|
+
# An array of Lobbyists, with the fuzzy_score set as an attribute
|
27
|
+
#
|
28
|
+
# Usage:
|
29
|
+
#
|
30
|
+
# lobbyists = Lobbyist.search("Nisha Thompsen")
|
31
|
+
# lobbyists = Lobbyist.search("Michael Klein", 0.95, 2007)
|
32
|
+
#
|
33
|
+
def self.search_by_name(name, threshold=0.9, year=Time.now.year)
|
34
|
+
|
35
|
+
url = construct_url("lobbyists.search", :name => name, :threshold => threshold, :year => year)
|
36
|
+
|
37
|
+
if (results = get_json_data(url))
|
38
|
+
lobbyists = []
|
39
|
+
results["response"]["results"].each do |result|
|
40
|
+
if result
|
41
|
+
lobbyist = Lobbyist.new(result["result"]["lobbyist"])
|
42
|
+
fuzzy_score = result["result"]["score"]
|
43
|
+
|
44
|
+
if threshold.to_f < fuzzy_score.to_f
|
45
|
+
lobbyist.fuzzy_score = fuzzy_score.to_f
|
46
|
+
lobbyists << lobbyist
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
if lobbyists.empty?
|
52
|
+
nil
|
53
|
+
else
|
54
|
+
lobbyists
|
55
|
+
end
|
56
|
+
|
57
|
+
else
|
58
|
+
nil
|
59
|
+
end
|
60
|
+
end # def self.search
|
61
|
+
end # class Lobbyist
|
62
|
+
|
63
|
+
end
|
data/sunlight.gemspec
CHANGED
@@ -1,13 +1,15 @@
|
|
1
1
|
Gem::Specification.new do |s|
|
2
2
|
s.name = "sunlight"
|
3
|
-
s.version = "0.
|
4
|
-
s.date = "2009-03-
|
3
|
+
s.version = "0.9.0"
|
4
|
+
s.date = "2009-03-15"
|
5
5
|
s.summary = "Library for accessing the Sunlight Labs API."
|
6
6
|
s.email = "luigi.montanez@gmail.com"
|
7
7
|
s.homepage = "http://github.com/luigi/sunlight"
|
8
8
|
s.authors = ["Luigi Montanez"]
|
9
|
-
s.files = ['sunlight.gemspec', 'lib/sunlight.rb', 'lib/sunlight/
|
10
|
-
|
9
|
+
s.files = ['sunlight.gemspec', 'lib/sunlight.rb', 'lib/sunlight/base.rb',
|
10
|
+
'lib/sunlight/district.rb', 'lib/sunlight/legislator.rb',
|
11
|
+
'lib/sunlight/filing.rb', 'lib/sunlight/issue.rb',
|
12
|
+
'lib/sunlight/lobbyist.rb','README.textile', 'CHANGES.textile']
|
11
13
|
s.add_dependency("json", [">= 1.1.3"])
|
12
14
|
s.add_dependency("ym4r", [">= 0.6.1"])
|
13
15
|
s.has_rdoc = true
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: luigi-sunlight
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.9.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Luigi Montanez
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-03-
|
12
|
+
date: 2009-03-15 00:00:00 -07:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
@@ -43,8 +43,12 @@ extra_rdoc_files: []
|
|
43
43
|
files:
|
44
44
|
- sunlight.gemspec
|
45
45
|
- lib/sunlight.rb
|
46
|
+
- lib/sunlight/base.rb
|
46
47
|
- lib/sunlight/district.rb
|
47
48
|
- lib/sunlight/legislator.rb
|
49
|
+
- lib/sunlight/filing.rb
|
50
|
+
- lib/sunlight/issue.rb
|
51
|
+
- lib/sunlight/lobbyist.rb
|
48
52
|
- README.textile
|
49
53
|
- CHANGES.textile
|
50
54
|
has_rdoc: true
|