govkit 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
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