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.
Files changed (34) hide show
  1. data/README.markdown +2 -2
  2. data/Rakefile +4 -5
  3. data/VERSION +1 -1
  4. data/generators/govkit/templates/govkit.rb +4 -4
  5. data/govkit.gemspec +22 -7
  6. data/init.rb +4 -0
  7. data/lib/gov_kit/acts_as_citeable.rb +1 -1
  8. data/lib/gov_kit/configuration.rb +4 -4
  9. data/lib/gov_kit/follow_the_money.rb +30 -16
  10. data/lib/gov_kit/{fifty_states.rb → open_states.rb} +25 -13
  11. data/lib/gov_kit/railtie.rb +20 -0
  12. data/lib/gov_kit/resource.rb +17 -37
  13. data/lib/gov_kit/search_engines/google_news.rb +4 -4
  14. data/lib/gov_kit/search_engines/wikipedia.rb +21 -0
  15. data/lib/gov_kit/search_engines.rb +1 -0
  16. data/lib/gov_kit/vote_smart.rb +68 -4
  17. data/lib/gov_kit.rb +25 -24
  18. data/spec/fixtures/follow_the_money/business-page0.response +28 -0
  19. data/spec/fixtures/follow_the_money/business-page1.response +12 -0
  20. data/spec/fixtures/follow_the_money/contribution.response +12 -0
  21. data/spec/fixtures/follow_the_money/unauthorized.response +8 -0
  22. data/spec/fixtures/open_states/401.response +6 -0
  23. data/spec/fixtures/open_states/410.response +6 -0
  24. data/spec/fixtures/open_states/bill.response +240 -0
  25. data/spec/fixtures/open_states/bill_query.response +1990 -0
  26. data/spec/fixtures/open_states/legislator.response +34 -0
  27. data/spec/fixtures/open_states/legislator_query.response +144 -0
  28. data/spec/fixtures/open_states/state.response +60 -0
  29. data/spec/follow_the_money_spec.rb +57 -0
  30. data/spec/open_states_spec.rb +131 -0
  31. data/spec/spec_helper.rb +13 -0
  32. metadata +23 -14
  33. data/rails/init.rb +0 -3
  34. 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 Fifty States project](http://fiftystates-dev.sunlightlabs.com/), which has a RESTful API for accessing data about state legislators, bills, votes, etc.
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::FiftyStates::State.find_by_abbreviation('CA')
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 'spec/rake/spectask'
6
+ require 'rspec/core/rake_task'
8
7
  rescue LoadError
9
8
  begin
10
- gem 'rspec-rails', '>= 1.0.0'
11
- require 'spec/rake/spectask'
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 Fifty States API and the Project Vote Smart API.}
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
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 Fifty States project here:
3
+ # Get an API key for Sunlight's Open States project here:
4
4
  # http://services.sunlightlabs.com/accounts/register/
5
- config.fiftystates_apikey = 'YOUR_FIFTYSTATES_API_KEY'
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.1.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-06-10}
13
- s.description = %q{Govkit lets you quickly get encapsulated Ruby objects for common open government APIs. We're starting with Sunlight's Fifty States API and the Project Vote Smart API.}
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
- "rails/init.rb",
52
- "spec/fifty_states_spec.rb",
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/fifty_states_spec.rb",
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
@@ -0,0 +1,4 @@
1
+ require File.join(File.dirname(__FILE__), "lib", "govkit")
2
+ require 'gov_kit/railtie'
3
+
4
+ GovKit::Railtie.insert
@@ -37,4 +37,4 @@ module GovKit::ActsAsCiteable
37
37
  }
38
38
  end
39
39
  end
40
- end
40
+ end
@@ -1,13 +1,13 @@
1
1
  module GovKit
2
2
  class Configuration
3
- attr_accessor :fiftystates_apikey, :fiftystates_base_url
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
- @fiftystates_apikey = @votesmart_apikey = @ftm_apikey = ''
10
- @fiftystates_base_url = 'fiftystates-dev.sunlightlabs.com/api'
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.fiftystates_apikey = ''
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 == "no"
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 = Hpricot::XML(response)
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 == "no"
37
- response = get("/candidates.contributions.php", :query => {"imsp_candidate_id" => nimsp_id, :page => page_num})
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
- response = get("/candidates.top_contributor.php", :query => {"imsp_candidate_id" => nimsp_id})
53
- doc = Hpricot::XML(response)
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
- response = get("/candidates.industries.php", :query => {"imsp_candidate_id" => nimsp_id})
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
- response = get("/candidates.sectors.php", :query => {"imsp_candidate_id" => nimsp_id})
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
- response = get("/candidates.businesses.php", :query => {"imsp_candidate_id" => nimsp_id})
91
- doc = Hpricot::XML(response)
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 FiftyStatesResource < Resource
3
- default_params :output => 'json', :apikey => GovKit::configuration.fiftystates_apikey
4
- base_uri GovKit::configuration.fiftystates_base_url
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 FiftyStates
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 < FiftyStatesResource
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 < FiftyStatesResource
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 < FiftyStatesResource
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 Vote < FiftyStatesResource
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
@@ -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
- instantiate_record(json)
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, module_names)
82
- receiver = Object
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
- ancestors = self.class.name.split("::")
96
- if ancestors.size > 1
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
@@ -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("/Votes.getBill", :query => {"billId" => bill_id})
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("/Votes.getBillsByYearState", :query => {"year" => year, "stateId" => state_abbrev})
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("/Committee.getCommitteesByTypeState", :query => {"typeId" => type_id, "stateId" => state_abbrev})
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("/Committee.getCommittee", :query => {"committeeId" => committee_id})
110
+ response = get('/Committee.getCommittee', :query => {'committeeId' => committee_id})
47
111
  instantiate_record(response['committee'])
48
112
  end
49
113
  end