govkit 0.1.0 → 0.2.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/README.markdown +2 -2
- data/Rakefile +4 -5
- data/VERSION +1 -1
- data/generators/govkit/templates/govkit.rb +4 -4
- data/govkit.gemspec +22 -7
- data/init.rb +4 -0
- data/lib/gov_kit/acts_as_citeable.rb +1 -1
- data/lib/gov_kit/configuration.rb +4 -4
- data/lib/gov_kit/follow_the_money.rb +30 -16
- data/lib/gov_kit/{fifty_states.rb → open_states.rb} +25 -13
- data/lib/gov_kit/railtie.rb +20 -0
- data/lib/gov_kit/resource.rb +17 -37
- data/lib/gov_kit/search_engines/google_news.rb +4 -4
- data/lib/gov_kit/search_engines/wikipedia.rb +21 -0
- data/lib/gov_kit/search_engines.rb +1 -0
- data/lib/gov_kit/vote_smart.rb +68 -4
- data/lib/gov_kit.rb +25 -24
- data/spec/fixtures/follow_the_money/business-page0.response +28 -0
- data/spec/fixtures/follow_the_money/business-page1.response +12 -0
- data/spec/fixtures/follow_the_money/contribution.response +12 -0
- data/spec/fixtures/follow_the_money/unauthorized.response +8 -0
- data/spec/fixtures/open_states/401.response +6 -0
- data/spec/fixtures/open_states/410.response +6 -0
- data/spec/fixtures/open_states/bill.response +240 -0
- data/spec/fixtures/open_states/bill_query.response +1990 -0
- data/spec/fixtures/open_states/legislator.response +34 -0
- data/spec/fixtures/open_states/legislator_query.response +144 -0
- data/spec/fixtures/open_states/state.response +60 -0
- data/spec/follow_the_money_spec.rb +57 -0
- data/spec/open_states_spec.rb +131 -0
- data/spec/spec_helper.rb +13 -0
- metadata +23 -14
- data/rails/init.rb +0 -3
- data/spec/fifty_states_spec.rb +0 -90
data/README.markdown
CHANGED
@@ -3,7 +3,7 @@
|
|
3
3
|
Govkit is a Ruby gem that provides simple access to open government APIs around the web, including:
|
4
4
|
|
5
5
|
* [OpenCongress](http://www.opencongress.org/api), which has an API for federal bills, votes, people, and news and blog coverage
|
6
|
-
* [The
|
6
|
+
* [The Open States project](http://fiftystates-dev.sunlightlabs.com/), which has a RESTful API for accessing data about state legislators, bills, votes, etc.
|
7
7
|
* [Project Vote Smart](http://www.votesmart.org/services_api.php), which has an API with congressional addresses, etc.
|
8
8
|
* [Follow The Money](http://www.followthemoney.org/), whose API reveals campaign contribution data for state officials.
|
9
9
|
|
@@ -21,7 +21,7 @@ Run <code>./script/generate govkit</code> to copy a config file into <code>confi
|
|
21
21
|
|
22
22
|
# Examples
|
23
23
|
|
24
|
-
>> Govkit::
|
24
|
+
>> Govkit::OpenStates::State.find_by_abbreviation('CA')
|
25
25
|
>> Govkit::VoteSmart::Address.find(votesmart_candidate_id)
|
26
26
|
>> GovKit::OpenCongress::Bill.find(:number => 5479, :type => 'h', :congress => '111')
|
27
27
|
|
data/Rakefile
CHANGED
@@ -2,13 +2,12 @@ require 'rubygems'
|
|
2
2
|
require 'rake'
|
3
3
|
require 'rake/rdoctask'
|
4
4
|
|
5
|
-
|
6
5
|
begin
|
7
|
-
require '
|
6
|
+
require 'rspec/core/rake_task'
|
8
7
|
rescue LoadError
|
9
8
|
begin
|
10
|
-
gem 'rspec-rails', '>=
|
11
|
-
require '
|
9
|
+
gem 'rspec-rails', '>= 2.0.0'
|
10
|
+
require 'rspec/core/rake_task'
|
12
11
|
rescue LoadError
|
13
12
|
puts "[govkit:] RSpec - or one of it's dependencies - is not available. Install it with: sudo gem install rspec-rails"
|
14
13
|
end
|
@@ -19,7 +18,7 @@ begin
|
|
19
18
|
Jeweler::Tasks.new do |gem|
|
20
19
|
gem.name = "govkit"
|
21
20
|
gem.summary = %Q{Simple access to open government APIs around the web}
|
22
|
-
gem.description = %Q{Govkit lets you quickly get encapsulated Ruby objects for common open government APIs. We're starting with Sunlight's
|
21
|
+
gem.description = %Q{Govkit lets you quickly get encapsulated Ruby objects for common open government APIs. We're starting with Sunlight's Open States API and the Project Vote Smart API.}
|
23
22
|
gem.email = "carl@ppolitics.org"
|
24
23
|
gem.homepage = "http://github.com/opengovernment/govkit"
|
25
24
|
gem.authors = ["Participatory Politics Foundation", "Srinivas Aki", "Carl Tashian"]
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.2.0
|
@@ -1,17 +1,17 @@
|
|
1
1
|
if defined? GovKit
|
2
2
|
GovKit.configure do |config|
|
3
|
-
# Get an API key for Sunlight's
|
3
|
+
# Get an API key for Sunlight's Open States project here:
|
4
4
|
# http://services.sunlightlabs.com/accounts/register/
|
5
|
-
config.
|
5
|
+
config.openstates_apikey = 'YOUR_OPENSTATES_API_KEY'
|
6
6
|
|
7
7
|
##API key for Votesmart
|
8
8
|
# http://votesmart.org/services_api.php
|
9
9
|
config.votesmart_apikey = 'YOUR_VOTESMART_API_KEY'
|
10
|
-
|
10
|
+
|
11
11
|
# API key for NIMSP. Request one here:
|
12
12
|
# http://www.followthemoney.org/membership/settings.phtml
|
13
13
|
config.ftm_apikey = 'YOUR_FTM_API_KEY'
|
14
|
-
|
14
|
+
|
15
15
|
# Api key for OpenCongress
|
16
16
|
# http://www.opencongress.org/api
|
17
17
|
config.opencongress_apikey = 'YOUR_OPENCONGRESS_API_KEY'
|
data/govkit.gemspec
CHANGED
@@ -5,12 +5,12 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{govkit}
|
8
|
-
s.version = "0.
|
8
|
+
s.version = "0.2.0"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Participatory Politics Foundation", "Srinivas Aki", "Carl Tashian"]
|
12
|
-
s.date = %q{2010-
|
13
|
-
s.description = %q{Govkit lets you quickly get encapsulated Ruby objects for common open government APIs. We're starting with Sunlight's
|
12
|
+
s.date = %q{2010-08-31}
|
13
|
+
s.description = %q{Govkit lets you quickly get encapsulated Ruby objects for common open government APIs. We're starting with Sunlight's Open States API and the Project Vote Smart API.}
|
14
14
|
s.email = %q{carl@ppolitics.org}
|
15
15
|
s.extra_rdoc_files = [
|
16
16
|
"LICENSE",
|
@@ -27,10 +27,10 @@ Gem::Specification.new do |s|
|
|
27
27
|
"generators/govkit/govkit_generator.rb",
|
28
28
|
"generators/govkit/templates/govkit.rb",
|
29
29
|
"govkit.gemspec",
|
30
|
+
"init.rb",
|
30
31
|
"lib/gov_kit.rb",
|
31
32
|
"lib/gov_kit/acts_as_citeable.rb",
|
32
33
|
"lib/gov_kit/configuration.rb",
|
33
|
-
"lib/gov_kit/fifty_states.rb",
|
34
34
|
"lib/gov_kit/follow_the_money.rb",
|
35
35
|
"lib/gov_kit/open_congress.rb",
|
36
36
|
"lib/gov_kit/open_congress/bill.rb",
|
@@ -41,15 +41,29 @@ Gem::Specification.new do |s|
|
|
41
41
|
"lib/gov_kit/open_congress/roll_call.rb",
|
42
42
|
"lib/gov_kit/open_congress/roll_call_comparison.rb",
|
43
43
|
"lib/gov_kit/open_congress/voting_comparison.rb",
|
44
|
+
"lib/gov_kit/open_states.rb",
|
45
|
+
"lib/gov_kit/railtie.rb",
|
44
46
|
"lib/gov_kit/resource.rb",
|
45
47
|
"lib/gov_kit/search_engines.rb",
|
46
48
|
"lib/gov_kit/search_engines/google_blog.rb",
|
47
49
|
"lib/gov_kit/search_engines/google_news.rb",
|
48
50
|
"lib/gov_kit/search_engines/technorati.rb",
|
51
|
+
"lib/gov_kit/search_engines/wikipedia.rb",
|
49
52
|
"lib/gov_kit/vote_smart.rb",
|
50
53
|
"lib/govkit.rb",
|
51
|
-
"
|
52
|
-
"spec/
|
54
|
+
"spec/fixtures/follow_the_money/business-page0.response",
|
55
|
+
"spec/fixtures/follow_the_money/business-page1.response",
|
56
|
+
"spec/fixtures/follow_the_money/contribution.response",
|
57
|
+
"spec/fixtures/follow_the_money/unauthorized.response",
|
58
|
+
"spec/fixtures/open_states/401.response",
|
59
|
+
"spec/fixtures/open_states/410.response",
|
60
|
+
"spec/fixtures/open_states/bill.response",
|
61
|
+
"spec/fixtures/open_states/bill_query.response",
|
62
|
+
"spec/fixtures/open_states/legislator.response",
|
63
|
+
"spec/fixtures/open_states/legislator_query.response",
|
64
|
+
"spec/fixtures/open_states/state.response",
|
65
|
+
"spec/follow_the_money_spec.rb",
|
66
|
+
"spec/open_states_spec.rb",
|
53
67
|
"spec/spec.opts",
|
54
68
|
"spec/spec_helper.rb"
|
55
69
|
]
|
@@ -59,7 +73,8 @@ Gem::Specification.new do |s|
|
|
59
73
|
s.rubygems_version = %q{1.3.7}
|
60
74
|
s.summary = %q{Simple access to open government APIs around the web}
|
61
75
|
s.test_files = [
|
62
|
-
"spec/
|
76
|
+
"spec/follow_the_money_spec.rb",
|
77
|
+
"spec/open_states_spec.rb",
|
63
78
|
"spec/spec_helper.rb"
|
64
79
|
]
|
65
80
|
|
data/init.rb
ADDED
@@ -1,13 +1,13 @@
|
|
1
1
|
module GovKit
|
2
2
|
class Configuration
|
3
|
-
attr_accessor :
|
3
|
+
attr_accessor :openstates_apikey, :openstates_base_url
|
4
4
|
attr_accessor :votesmart_apikey, :votesmart_base_url
|
5
5
|
attr_accessor :ftm_apikey, :ftm_base_url
|
6
6
|
attr_accessor :opencongress_apikey, :opencongress_base_url
|
7
7
|
|
8
8
|
def initialize
|
9
|
-
@
|
10
|
-
@
|
9
|
+
@openstates_apikey = @votesmart_apikey = @ftm_apikey = ''
|
10
|
+
@openstates_base_url = 'fiftystates-dev.sunlightlabs.com/api'
|
11
11
|
@votesmart_base_url = 'api.votesmart.org/'
|
12
12
|
@ftm_base_url = 'api.followthemoney.org/'
|
13
13
|
@opencongress_base_url = 'www.opencongress.org/'
|
@@ -22,7 +22,7 @@ module GovKit
|
|
22
22
|
#
|
23
23
|
# @example
|
24
24
|
# GovKit.configure do |config|
|
25
|
-
# config.
|
25
|
+
# config.openstates_apikey = ''
|
26
26
|
# end
|
27
27
|
def self.configure
|
28
28
|
self.configuration ||= Configuration.new
|
@@ -2,6 +2,25 @@ module GovKit
|
|
2
2
|
class FollowTheMoneyResource < Resource
|
3
3
|
default_params :key => GovKit::configuration.ftm_apikey
|
4
4
|
base_uri GovKit::configuration.ftm_base_url
|
5
|
+
|
6
|
+
def self.get_xml(path, options)
|
7
|
+
response = get(path, options)
|
8
|
+
doc = Hpricot::XML(response)
|
9
|
+
|
10
|
+
e = doc.search("//error")
|
11
|
+
|
12
|
+
# API Key invalid
|
13
|
+
if e.size > 0
|
14
|
+
raise case e.first.attributes['code']
|
15
|
+
when "100"
|
16
|
+
GovKit::NotAuthorized
|
17
|
+
when "300"
|
18
|
+
GovKit::InvalidRequest
|
19
|
+
end, e.first.attributes['text']
|
20
|
+
end
|
21
|
+
|
22
|
+
doc
|
23
|
+
end
|
5
24
|
end
|
6
25
|
|
7
26
|
module FollowTheMoney
|
@@ -9,12 +28,10 @@ module GovKit
|
|
9
28
|
def self.list
|
10
29
|
next_page, result, page_num = "yes", [], 0
|
11
30
|
|
12
|
-
until next_page
|
13
|
-
puts "Getting batch number #{page_num}"
|
14
|
-
|
15
|
-
response = get("/base_level.industries.list.php", :query => {:page => page_num})
|
31
|
+
until next_page != "yes"
|
32
|
+
# puts "Getting batch number #{page_num}"
|
16
33
|
|
17
|
-
doc =
|
34
|
+
doc = get_xml("/base_level.industries.list.php", :query => {:page => page_num})
|
18
35
|
|
19
36
|
next_page = doc.search("/").first.attributes['next_page']
|
20
37
|
|
@@ -33,9 +50,8 @@ module GovKit
|
|
33
50
|
def self.find(nimsp_id)
|
34
51
|
next_page, result, page_num = "yes", [], 0
|
35
52
|
|
36
|
-
until next_page
|
37
|
-
|
38
|
-
doc = Hpricot::XML(response)
|
53
|
+
until next_page != "yes"
|
54
|
+
doc = get_xml("/candidates.contributions.php", :query => {"imsp_candidate_id" => nimsp_id, :page => page_num})
|
39
55
|
|
40
56
|
next_page = doc.search("/").first.attributes['next_page']
|
41
57
|
|
@@ -49,8 +65,8 @@ module GovKit
|
|
49
65
|
end
|
50
66
|
|
51
67
|
def self.top(nimsp_id)
|
52
|
-
|
53
|
-
|
68
|
+
doc = get_xml("/candidates.top_contributor.php", :query => {"imsp_candidate_id" => nimsp_id})
|
69
|
+
|
54
70
|
result = doc.search('//top_contributor').collect do |contribution|
|
55
71
|
contribution.attributes.to_hash
|
56
72
|
end
|
@@ -61,8 +77,7 @@ module GovKit
|
|
61
77
|
|
62
78
|
class IndustryContribution < Contribution
|
63
79
|
def self.find(nimsp_id)
|
64
|
-
|
65
|
-
doc = Hpricot::XML(response)
|
80
|
+
doc = get_xml("/candidates.industries.php", :query => {"imsp_candidate_id" => nimsp_id})
|
66
81
|
|
67
82
|
result = doc.search('//candidate_industry').collect do |contribution|
|
68
83
|
contribution.attributes.to_hash
|
@@ -74,8 +89,7 @@ module GovKit
|
|
74
89
|
|
75
90
|
class SectorContribution < Contribution
|
76
91
|
def self.find(nimsp_id)
|
77
|
-
|
78
|
-
doc = Hpricot::XML(response)
|
92
|
+
doc = get_xml("/candidates.sectors.php", :query => {"imsp_candidate_id" => nimsp_id})
|
79
93
|
|
80
94
|
result = doc.search('//candidate_sector').collect do |contribution|
|
81
95
|
contribution.attributes.to_hash
|
@@ -87,8 +101,8 @@ module GovKit
|
|
87
101
|
|
88
102
|
class BusinessContribution < Contribution
|
89
103
|
def self.find(nimsp_id)
|
90
|
-
|
91
|
-
|
104
|
+
doc = get_xml("/candidates.businesses.php", :query => {"imsp_candidate_id" => nimsp_id})
|
105
|
+
|
92
106
|
result = doc.search('//candidate_business').collect do |contribution|
|
93
107
|
contribution.attributes.to_hash
|
94
108
|
end
|
@@ -1,23 +1,23 @@
|
|
1
1
|
module GovKit
|
2
|
-
class
|
3
|
-
default_params :output => 'json', :apikey => GovKit::configuration.
|
4
|
-
base_uri GovKit::configuration.
|
2
|
+
class OpenStatesResource < Resource
|
3
|
+
default_params :output => 'json', :apikey => GovKit::configuration.openstates_apikey
|
4
|
+
base_uri GovKit::configuration.openstates_base_url
|
5
5
|
end
|
6
6
|
|
7
|
-
module
|
7
|
+
module OpenStates
|
8
8
|
ROLE_MEMBER = "member"
|
9
9
|
ROLE_COMMITTEE_MEMBER = "committee member"
|
10
10
|
CHAMBER_UPPER = "upper"
|
11
11
|
CHAMBER_LOWER = "lower"
|
12
12
|
|
13
|
-
class State <
|
13
|
+
class State < OpenStatesResource
|
14
14
|
def self.find_by_abbreviation(abbreviation)
|
15
|
-
response = get("/#{abbreviation}")
|
15
|
+
response = get("/#{abbreviation}/")
|
16
16
|
instantiate_record(response)
|
17
17
|
end
|
18
18
|
end
|
19
19
|
|
20
|
-
class Bill <
|
20
|
+
class Bill < OpenStatesResource
|
21
21
|
# http://fiftystates-dev.sunlightlabs.com/api/ca/20092010/lower/bills/AB667/
|
22
22
|
def self.find(state_abbrev, session, chamber, bill_id)
|
23
23
|
response = get("/#{state_abbrev}/#{session}/#{chamber}/bills/#{bill_id}/")
|
@@ -25,7 +25,7 @@ module GovKit
|
|
25
25
|
end
|
26
26
|
|
27
27
|
def self.search(query, options = {})
|
28
|
-
response = get('/bills/search', :query => {:q => query}.merge(options))
|
28
|
+
response = get('/bills/search/', :query => {:q => query}.merge(options))
|
29
29
|
instantiate_collection(response)
|
30
30
|
end
|
31
31
|
|
@@ -35,21 +35,33 @@ module GovKit
|
|
35
35
|
end
|
36
36
|
end
|
37
37
|
|
38
|
-
class Legislator <
|
38
|
+
class Legislator < OpenStatesResource
|
39
39
|
def self.find(legislator_id)
|
40
|
-
response = get("/legislators/#{legislator_id}")
|
40
|
+
response = get("/legislators/#{legislator_id}/")
|
41
41
|
instantiate_record(response)
|
42
42
|
end
|
43
43
|
|
44
44
|
def self.search(options = {})
|
45
|
-
response = get('/legislators/search', :query => options)
|
45
|
+
response = get('/legislators/search/', :query => options)
|
46
46
|
instantiate_collection(response)
|
47
47
|
end
|
48
48
|
end
|
49
49
|
|
50
|
-
class
|
50
|
+
class Role < OpenStatesResource; end
|
51
|
+
|
52
|
+
class Sponsor < OpenStatesResource; end
|
53
|
+
|
54
|
+
class Version < OpenStatesResource; end
|
55
|
+
|
56
|
+
class Source < OpenStatesResource; end
|
57
|
+
|
58
|
+
class Address < OpenStatesResource; end
|
59
|
+
|
60
|
+
class Action < OpenStatesResource; end
|
61
|
+
|
62
|
+
class Vote < OpenStatesResource
|
51
63
|
def self.find(vote_id)
|
52
|
-
response = get("/votes/#{vote_id}")
|
64
|
+
response = get("/votes/#{vote_id}/")
|
53
65
|
instantiate_record(response)
|
54
66
|
end
|
55
67
|
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'govkit'
|
2
|
+
|
3
|
+
module GovKit
|
4
|
+
if defined? Rails::Railtie
|
5
|
+
require 'rails'
|
6
|
+
class Railtie < Rails::Railtie
|
7
|
+
initializer 'govkit.insert_into_active_record' do
|
8
|
+
ActiveSupport.on_load :active_record do
|
9
|
+
GovKit::Railtie.insert
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
class Railtie
|
16
|
+
def self.insert
|
17
|
+
ActiveRecord::Base.send(:include, GovKit::ActsAsCiteable)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
data/lib/gov_kit/resource.rb
CHANGED
@@ -1,29 +1,4 @@
|
|
1
1
|
module GovKit
|
2
|
-
class GovKitError < StandardError
|
3
|
-
attr_reader :response
|
4
|
-
|
5
|
-
def initialize(response, message = nil)
|
6
|
-
@response = response
|
7
|
-
@message = message
|
8
|
-
end
|
9
|
-
|
10
|
-
def to_s
|
11
|
-
"Failed with #{response.code} #{response.message if response.respond_to?(:message)}"
|
12
|
-
end
|
13
|
-
end
|
14
|
-
|
15
|
-
class NotauthorizedError < GovKitError;
|
16
|
-
end
|
17
|
-
|
18
|
-
class InvalidRequestError < GovKitError;
|
19
|
-
end
|
20
|
-
|
21
|
-
class NotFoundError < GovKitError;
|
22
|
-
end
|
23
|
-
|
24
|
-
class NameError < GovKitError;
|
25
|
-
end
|
26
|
-
|
27
2
|
class Resource
|
28
3
|
include HTTParty
|
29
4
|
format :json
|
@@ -37,6 +12,7 @@ module GovKit
|
|
37
12
|
|
38
13
|
class << self
|
39
14
|
def instantiate_record(record)
|
15
|
+
raise ResourceNotFound, "Resource not found" unless !record.blank?
|
40
16
|
new(record)
|
41
17
|
end
|
42
18
|
|
@@ -45,7 +21,16 @@ module GovKit
|
|
45
21
|
end
|
46
22
|
|
47
23
|
def parse(json)
|
48
|
-
|
24
|
+
instantiate(json)
|
25
|
+
end
|
26
|
+
|
27
|
+
def instantiate(record)
|
28
|
+
case record
|
29
|
+
when Array
|
30
|
+
instantiate_collection(record)
|
31
|
+
when Hash
|
32
|
+
instantiate_record(record)
|
33
|
+
end
|
49
34
|
end
|
50
35
|
end
|
51
36
|
|
@@ -78,12 +63,8 @@ module GovKit
|
|
78
63
|
find_or_create_resource_for(name.to_s.singularize)
|
79
64
|
end
|
80
65
|
|
81
|
-
def find_resource_in_modules(resource_name,
|
82
|
-
|
83
|
-
namespaces = module_names[0, module_names.size-1].map do |module_name|
|
84
|
-
receiver = receiver.const_get(module_name)
|
85
|
-
end
|
86
|
-
if namespace = namespaces.reverse.detect { |ns| ns.const_defined?(resource_name) }
|
66
|
+
def find_resource_in_modules(resource_name, ancestors)
|
67
|
+
if namespace = ancestors.detect { |a| a.constants.include?(resource_name.to_sym) }
|
87
68
|
return namespace.const_get(resource_name)
|
88
69
|
else
|
89
70
|
raise NameError, "Namespace for #{namespace} not found"
|
@@ -91,10 +72,9 @@ module GovKit
|
|
91
72
|
end
|
92
73
|
|
93
74
|
def find_or_create_resource_for(name)
|
94
|
-
resource_name = name.to_s.camelize
|
95
|
-
|
96
|
-
|
97
|
-
find_resource_in_modules(resource_name, ancestors)
|
75
|
+
resource_name = name.to_s.gsub(/^_/,'').gsub(/^(\d)/, "n#{$1}").gsub(/\s/, '').camelize
|
76
|
+
if self.class.parents.size > 1
|
77
|
+
find_resource_in_modules(resource_name, self.class.parents)
|
98
78
|
else
|
99
79
|
self.class.const_get(resource_name)
|
100
80
|
end
|
@@ -114,7 +94,7 @@ module GovKit
|
|
114
94
|
when "="
|
115
95
|
attributes[method_name.first(-1)] = arguments.first
|
116
96
|
when "?"
|
117
|
-
attributes[method_name.first(-1)]
|
97
|
+
!attributes[method_name.first(-1)].blank?
|
118
98
|
when "]"
|
119
99
|
attributes[arguments.first.to_s]
|
120
100
|
else
|
@@ -18,11 +18,11 @@ module GovKit
|
|
18
18
|
stories.each do |story|
|
19
19
|
citation = GovKit::Citation.new
|
20
20
|
|
21
|
-
citation.title = story.at("h2.title a").inner_text.html_safe
|
21
|
+
citation.title = story.at("h2.title a").inner_text.html_safe
|
22
22
|
citation.url = story.at("h2.title a").attributes["href"]
|
23
|
-
citation.date = story.at("div.sub-title > span.date").inner_html.html_safe
|
24
|
-
citation.source = story.at("div.sub-title > span.source").inner_html.html_safe
|
25
|
-
citation.excerpt = story.at("div.body > div.snippet").inner_html.html_safe
|
23
|
+
citation.date = story.at("div.sub-title > span.date").inner_html.html_safe
|
24
|
+
citation.source = story.at("div.sub-title > span.source").inner_html.html_safe
|
25
|
+
citation.excerpt = story.at("div.body > div.snippet").inner_html.html_safe
|
26
26
|
|
27
27
|
citations << citation
|
28
28
|
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module GovKit
|
2
|
+
module SearchEngines
|
3
|
+
class Wikipedia
|
4
|
+
include HTTParty
|
5
|
+
default_params :format => 'xml'
|
6
|
+
base_uri "en.wikipedia.org"
|
7
|
+
headers 'User-Agent' => 'GovKit +http://opengovernment.org'
|
8
|
+
|
9
|
+
def self.search(query, options={})
|
10
|
+
response = get("/wiki/#{query}")
|
11
|
+
doc = Hpricot(Iconv.conv('utf-8//IGNORE', 'gb2312', response))
|
12
|
+
|
13
|
+
doc.at('#bodyContent > table.toc').previous_sibling.inner_html.scrub rescue ""
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.make_request(host, path)
|
17
|
+
response = Net::HTTP.get(host, path)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -2,4 +2,5 @@ module GovKit::SearchEngines
|
|
2
2
|
autoload :GoogleNews, 'gov_kit/search_engines/google_news'
|
3
3
|
autoload :GoogleBlog, 'gov_kit/search_engines/google_blog'
|
4
4
|
autoload :Technorati, 'gov_kit/search_engines/technorati'
|
5
|
+
autoload :Wikipedia, 'gov_kit/search_engines/wikipedia'
|
5
6
|
end
|
data/lib/gov_kit/vote_smart.rb
CHANGED
@@ -19,16 +19,80 @@ module GovKit
|
|
19
19
|
end
|
20
20
|
end
|
21
21
|
|
22
|
+
class Bio < VoteSmartResource
|
23
|
+
def self.find(candidate_id)
|
24
|
+
response = get("/CandidateBio.getBio", :query => {"candidateId" => candidate_id})
|
25
|
+
instantiate_record(response['bio']['candidate'])
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
class Category < VoteSmartResource
|
30
|
+
def self.list(state_id)
|
31
|
+
response = get("/Rating.getCategories", :query => {"stateId" => state_id})
|
32
|
+
instantiate(response['categories']['category'])
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
class SIG < VoteSmartResource
|
37
|
+
def self.list(category_id, state_id)
|
38
|
+
response = get("/Rating.getSigList", :query => {"categoryId" => category_id, "stateId" => state_id})
|
39
|
+
|
40
|
+
raise(ResourceNotFound, response['error']['errorMessage']) if response['error'] && response['error']['errorMessage'] == 'No SIGs fit this criteria.'
|
41
|
+
|
42
|
+
instantiate(response['sigs']['sig'])
|
43
|
+
end
|
44
|
+
|
45
|
+
def self.find(sig_id)
|
46
|
+
response = get("/Rating.getSig", :query => {"sigId" => sig_id})
|
47
|
+
instantiate(response['sig'])
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
class Rating < VoteSmartResource
|
52
|
+
def self.find(candidate_id, sig_id)
|
53
|
+
response = get("/Rating.getCandidateRating", :query => {"candidateId" => candidate_id, "sigId" => sig_id})
|
54
|
+
|
55
|
+
raise(ResourceNotFound, response['error']['errorMessage']) if response['error'] && response['error']['errorMessage'] == 'No Ratings fit this criteria.'
|
56
|
+
|
57
|
+
instantiate(response['candidateRating']['rating'])
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
22
61
|
class Bill < VoteSmartResource
|
23
62
|
def self.find(bill_id)
|
24
|
-
response = get(
|
63
|
+
response = get('/Votes.getBill', :query => {'billId' => bill_id})
|
25
64
|
instantiate_record(response['bill'])
|
26
65
|
end
|
27
66
|
|
28
67
|
def self.find_by_year_and_state(year, state_abbrev)
|
29
|
-
response = get(
|
68
|
+
response = get('/Votes.getBillsByYearState', :query => {'year' => year, 'stateId' => state_abbrev})
|
69
|
+
raise(ResourceNotFound, response['error']['errorMessage']) if response['error'] && response['error']['errorMessage'] == 'No bills for this state and year.'
|
70
|
+
|
71
|
+
instantiate_record(response['bills'])
|
72
|
+
end
|
73
|
+
|
74
|
+
def self.find_recent_by_state(state_abbrev)
|
75
|
+
response = get('/Votes.getBillsByStateRecent', :query => {'stateId' => state_abbrev})
|
30
76
|
instantiate_record(response['bills'])
|
31
77
|
end
|
78
|
+
|
79
|
+
def self.find_by_category_and_year_and_state(category_id, year, state_abbrev = nil)
|
80
|
+
response = get('/Votes.getBillsByCategoryYearState', :query => {'stateId' => state_abbrev, 'year' => year, 'categoryId' => category_id})
|
81
|
+
raise(ResourceNotFound, response['error']['errorMessage']) if response['error'] && response['error']['errorMessage'] == 'No bills for this state, category, and year.'
|
82
|
+
|
83
|
+
instantiate_record(response['bills'])
|
84
|
+
end
|
85
|
+
|
86
|
+
def self.find_by_category_and_year(category_id, year)
|
87
|
+
find_by_category_and_year_and_state(category_id, year)
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
class BillCategory < VoteSmartResource
|
92
|
+
def self.find(year, state_abbrev)
|
93
|
+
response = get("/Votes.getCategories", :query => {'year' => year, 'stateId' => state_abbrev})
|
94
|
+
instantiate(response['categories']['category'])
|
95
|
+
end
|
32
96
|
end
|
33
97
|
|
34
98
|
# See http://api.votesmart.org/docs/Committee.html
|
@@ -37,13 +101,13 @@ module GovKit
|
|
37
101
|
# If type_id is nil, defaults to all types.
|
38
102
|
# This method maps to Committee.getCommitteesByTypeState()
|
39
103
|
def self.find_by_type_and_state(type_id, state_abbrev)
|
40
|
-
response = get(
|
104
|
+
response = get('/Committee.getCommitteesByTypeState', :query => {'typeId' => type_id, 'stateId' => state_abbrev})
|
41
105
|
instantiate_record(response['committees'])
|
42
106
|
end
|
43
107
|
|
44
108
|
# Find a committee by VoteSmart committeeId. Maps to Committee.getCommittee()
|
45
109
|
def self.find(committee_id)
|
46
|
-
response = get(
|
110
|
+
response = get('/Committee.getCommittee', :query => {'committeeId' => committee_id})
|
47
111
|
instantiate_record(response['committee'])
|
48
112
|
end
|
49
113
|
end
|