govkit-h 0.7.1.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/.document +5 -0
- data/.rspec +3 -0
- data/Gemfile +13 -0
- data/LICENSE +20 -0
- data/README.md +70 -0
- data/Rakefile +82 -0
- data/USAGE +1 -0
- data/VERSION +1 -0
- data/generators/govkit/govkit_generator.rb +24 -0
- data/generators/govkit/templates/govkit.rb +24 -0
- data/govkit.gemspec +130 -0
- data/init.rb +4 -0
- data/lib/generators/govkit/govkit_generator.rb +21 -0
- data/lib/generators/govkit/templates/create_mentions.rb +21 -0
- data/lib/generators/govkit/templates/govkit.rb +24 -0
- data/lib/generators/govkit/templates/mention.rb +15 -0
- data/lib/gov_kit.rb +45 -0
- data/lib/gov_kit/acts_as_noteworthy.rb +63 -0
- data/lib/gov_kit/configuration.rb +58 -0
- data/lib/gov_kit/follow_the_money.rb +176 -0
- data/lib/gov_kit/open_congress.rb +125 -0
- data/lib/gov_kit/open_congress/bill.rb +171 -0
- data/lib/gov_kit/open_congress/blog_post.rb +15 -0
- data/lib/gov_kit/open_congress/news_post.rb +15 -0
- data/lib/gov_kit/open_congress/person.rb +141 -0
- data/lib/gov_kit/open_congress/person_stat.rb +13 -0
- data/lib/gov_kit/open_congress/roll_call.rb +14 -0
- data/lib/gov_kit/open_congress/roll_call_comparison.rb +28 -0
- data/lib/gov_kit/open_congress/voting_comparison.rb +44 -0
- data/lib/gov_kit/open_states.rb +132 -0
- data/lib/gov_kit/railtie.rb +24 -0
- data/lib/gov_kit/resource.rb +190 -0
- data/lib/gov_kit/search_engines.rb +7 -0
- data/lib/gov_kit/search_engines/bing.rb +38 -0
- data/lib/gov_kit/search_engines/google_blog.rb +32 -0
- data/lib/gov_kit/search_engines/google_news.rb +47 -0
- data/lib/gov_kit/search_engines/technorati.rb +35 -0
- data/lib/gov_kit/search_engines/wikipedia.rb +27 -0
- data/lib/gov_kit/transparency_data.rb +144 -0
- data/lib/gov_kit/vote_smart.rb +126 -0
- data/lib/govkit.rb +1 -0
- data/spec/fixtures/bing/news_search.response +1 -0
- data/spec/fixtures/bing/no_results.response +1 -0
- 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_congress/person.response +8 -0
- data/spec/fixtures/open_states/401.response +10 -0
- data/spec/fixtures/open_states/404.response +9 -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/committee_find.response +53 -0
- data/spec/fixtures/open_states/committee_query.response +190 -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/fixtures/search_engines/google_news.response +8 -0
- data/spec/fixtures/transparency_data/contributions.response +18 -0
- data/spec/fixtures/transparency_data/entities_search.response +7 -0
- data/spec/fixtures/transparency_data/entities_search_limit_0.response +7 -0
- data/spec/fixtures/transparency_data/entities_search_limit_1.response +7 -0
- data/spec/fixtures/transparency_data/grants_find_all.response +7 -0
- data/spec/fixtures/transparency_data/lobbyists_find_all.response +7 -0
- data/spec/follow_the_money_spec.rb +61 -0
- data/spec/open_congress_spec.rb +108 -0
- data/spec/open_states_spec.rb +213 -0
- data/spec/search_engines_spec.rb +44 -0
- data/spec/spec_helper.rb +36 -0
- data/spec/transparency_data_spec.rb +106 -0
- metadata +258 -0
@@ -0,0 +1,15 @@
|
|
1
|
+
# A model to contain mentions of the :owner in the media
|
2
|
+
class Mention < ActiveRecord::Base
|
3
|
+
belongs_to :owner, :polymorphic => true
|
4
|
+
|
5
|
+
scope :since, lambda { |d| where(["mentions.date > ?", d]) }
|
6
|
+
|
7
|
+
# Returns the mentions in JSON form
|
8
|
+
#
|
9
|
+
# @params [Hash] A hash of options
|
10
|
+
# @return The mentions in JSON form
|
11
|
+
def as_json(opts = {})
|
12
|
+
default_opts = {:except => [:owner_id, :owner_type]}
|
13
|
+
super(default_opts.merge(opts))
|
14
|
+
end
|
15
|
+
end
|
data/lib/gov_kit.rb
ADDED
@@ -0,0 +1,45 @@
|
|
1
|
+
$LOAD_PATH.unshift(File.expand_path(File.dirname(__FILE__))) unless $LOAD_PATH.include?(File.expand_path(File.dirname(__FILE__)))
|
2
|
+
|
3
|
+
require 'digest/md5'
|
4
|
+
require 'active_support'
|
5
|
+
require 'nokogiri'
|
6
|
+
require 'iconv'
|
7
|
+
require 'httparty'
|
8
|
+
require 'open-uri'
|
9
|
+
require 'json'
|
10
|
+
require 'gov_kit/configuration'
|
11
|
+
require 'csv'
|
12
|
+
|
13
|
+
if RUBY_VERSION[0,3] == "1.8"
|
14
|
+
require 'fastercsv'
|
15
|
+
end
|
16
|
+
|
17
|
+
module GovKit
|
18
|
+
autoload :Resource, 'gov_kit/resource'
|
19
|
+
autoload :OpenStates, 'gov_kit/open_states'
|
20
|
+
autoload :TransparencyData, 'gov_kit/transparency_data'
|
21
|
+
autoload :VoteSmart, 'gov_kit/vote_smart'
|
22
|
+
autoload :ActsAsNoteworthy, 'gov_kit/acts_as_noteworthy'
|
23
|
+
autoload :FollowTheMoney, 'gov_kit/follow_the_money'
|
24
|
+
autoload :OpenCongress, 'gov_kit/open_congress'
|
25
|
+
autoload :SearchEngines, 'gov_kit/search_engines'
|
26
|
+
|
27
|
+
# Convenience class to represent a news story or blog post.
|
28
|
+
# Used by GovKit::SearchEngines classes.
|
29
|
+
class Mention
|
30
|
+
attr_accessor :url, :excerpt, :title, :source, :date, :weight, :search_source
|
31
|
+
end
|
32
|
+
|
33
|
+
class GovKitError < StandardError
|
34
|
+
end
|
35
|
+
|
36
|
+
class NotAuthorized < GovKitError; end
|
37
|
+
|
38
|
+
class InvalidRequest < GovKitError; end
|
39
|
+
|
40
|
+
class ResourceNotFound < GovKitError; end
|
41
|
+
|
42
|
+
class ServerError < GovKitError; end
|
43
|
+
|
44
|
+
class ClientError < GovKitError; end
|
45
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
module GovKit::ActsAsNoteworthy
|
2
|
+
|
3
|
+
def self.included(base)
|
4
|
+
base.extend ActMethods
|
5
|
+
end
|
6
|
+
|
7
|
+
# Module to make a rails model act as a noteworthy object, linking it to govkit's mention model
|
8
|
+
module ActMethods
|
9
|
+
# Sets up the relationship between the model and the mention model
|
10
|
+
#
|
11
|
+
# @param [Hash] opts a hash of options to be used by the relationship
|
12
|
+
def acts_as_noteworthy(options={})
|
13
|
+
class_inheritable_accessor :options
|
14
|
+
self.options = options
|
15
|
+
|
16
|
+
unless included_modules.include? InstanceMethods
|
17
|
+
instance_eval do
|
18
|
+
has_many :mentions, :as => :owner, :order => 'date desc'
|
19
|
+
|
20
|
+
with_options :as => :owner, :class_name => "Mention" do |c|
|
21
|
+
c.has_many :google_news_mentions, :conditions => {:search_source => "Google News"}, :order => 'date desc'
|
22
|
+
c.has_many :google_blog_mentions, :conditions => {:search_source => "Google Blogs"}, :order => 'date desc'
|
23
|
+
# c.has_many :technorati_mentions, :conditions => {:search_source => "Technorati"}, :order => 'date desc'
|
24
|
+
c.has_many :bing_mentions, :conditions => {:search_source => "Bing"}, :order => 'date desc'
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
extend ClassMethods
|
29
|
+
include InstanceMethods
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
module ClassMethods
|
35
|
+
end
|
36
|
+
|
37
|
+
# A module that adds methods to individual instances of the noteworthy class.
|
38
|
+
module InstanceMethods
|
39
|
+
# Generates the raw mentions to be loaded into the Mention objects
|
40
|
+
#
|
41
|
+
# @return [Hash] a hash of all the mentions found of the object in question.
|
42
|
+
def raw_mentions
|
43
|
+
opts = self.options.clone
|
44
|
+
attributes = opts.delete(:with)
|
45
|
+
|
46
|
+
if opts[:geo]
|
47
|
+
opts[:geo] = self.instance_eval("#{opts[:geo]}")
|
48
|
+
end
|
49
|
+
|
50
|
+
query = []
|
51
|
+
attributes.each do |attr|
|
52
|
+
query << self.instance_eval("#{attr}")
|
53
|
+
end
|
54
|
+
|
55
|
+
{
|
56
|
+
:google_news => GovKit::SearchEngines::GoogleNews.search(query, opts),
|
57
|
+
:google_blogs => GovKit::SearchEngines::GoogleBlog.search(query, opts),
|
58
|
+
# :technorati => GovKit::SearchEngines::Technorati.search(query),
|
59
|
+
:bing => GovKit::SearchEngines::Bing.search(query, opts)
|
60
|
+
}
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
module GovKit
|
2
|
+
class Configuration
|
3
|
+
attr_accessor :sunlight_apikey, :openstates_base_url, :transparency_data_base_url, :transparency_data_categories_url
|
4
|
+
attr_accessor :votesmart_apikey, :votesmart_base_url
|
5
|
+
attr_accessor :openstates_apikey, :ftm_apikey, :ftm_base_url
|
6
|
+
attr_accessor :opencongress_apikey, :opencongress_base_url
|
7
|
+
attr_accessor :technorati_apikey, :technorati_base_url
|
8
|
+
attr_accessor :google_blog_base_url, :google_news_base_url
|
9
|
+
attr_accessor :wikipedia_base_url
|
10
|
+
attr_accessor :bing_appid, :bing_base_url
|
11
|
+
|
12
|
+
def initialize
|
13
|
+
@sunlight_apikey = @openstates_apikey = @votesmart_apikey = @ftm_apikey = ''
|
14
|
+
@openstates_base_url = 'openstates.sunlightlabs.com/api/v1/'
|
15
|
+
@transparency_data_base_url = 'transparencydata.com/api/1.0/'
|
16
|
+
@votesmart_base_url = 'api.votesmart.org/'
|
17
|
+
@ftm_base_url = 'api.followthemoney.org/'
|
18
|
+
@opencongress_base_url = 'www.opencongress.org/'
|
19
|
+
@technorati_base_url = 'api.technorati.com'
|
20
|
+
@bing_base_url = 'api.search.live.net'
|
21
|
+
@google_blog_base_url = 'blogsearch.google.com'
|
22
|
+
@google_news_base_url = 'news.google.com'
|
23
|
+
@wikipedia_base_url = 'en.wikipedia.org'
|
24
|
+
|
25
|
+
# Permant home for contribution category mappings
|
26
|
+
@transparency_data_categories_url = 'http://assets.transparencydata.org.s3.amazonaws.com/docs/catcodes.csv'
|
27
|
+
end
|
28
|
+
|
29
|
+
def opencongress_apikey= key
|
30
|
+
warn "[DEPRECATION] OpenCongress no longer requires an API Key. Ability to set it will be removed in future versions"
|
31
|
+
@opencongress_apikey = key
|
32
|
+
end
|
33
|
+
|
34
|
+
def openstates_apikey= key
|
35
|
+
warn "[DEPRECATION] Use sunlight_apikey instead of openstates_apikey. Ability to set it will be removed in future versions"
|
36
|
+
@sunlight_apikey = key
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
class << self
|
41
|
+
attr_accessor :configuration
|
42
|
+
|
43
|
+
def configuration
|
44
|
+
@configuration = Configuration.new if @configuration.nil?
|
45
|
+
@configuration
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
# Configure GovKit in config/initializers/govkit.rb
|
50
|
+
#
|
51
|
+
# @example
|
52
|
+
# GovKit.configure do |config|
|
53
|
+
# config.sunlight_apikey = ''
|
54
|
+
# end
|
55
|
+
def self.configure
|
56
|
+
yield(configuration)
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,176 @@
|
|
1
|
+
module GovKit
|
2
|
+
|
3
|
+
# Subclass of {Resource} for FollowTheMoney data. This
|
4
|
+
# is subclassed further for each of the different types of record
|
5
|
+
# returned by FollowTheMoney.
|
6
|
+
#
|
7
|
+
# For the details on the FollowTheMoney queries, see {http://www.followthemoney.org/services/methods.phtml the FollowTheMoney API documentation}.
|
8
|
+
class FollowTheMoneyResource < Resource
|
9
|
+
default_params :key => GovKit::configuration.ftm_apikey
|
10
|
+
base_uri GovKit::configuration.ftm_base_url
|
11
|
+
|
12
|
+
# Common method used by subclasses to get data from the service.
|
13
|
+
#
|
14
|
+
# @return [Nokogiri::XML::Document] a {http://nokogiri.org/Nokogiri/HTML/Document.html Nokogiri XML::Document} object
|
15
|
+
# @param [String] path query path that specifies the required data
|
16
|
+
# @param [Hash] options query options
|
17
|
+
#
|
18
|
+
# @example
|
19
|
+
# doc = get_xml("/base_level.industries.list.php", :query => {:page => page_num})
|
20
|
+
#
|
21
|
+
def self.get_xml(path, options)
|
22
|
+
doc = Nokogiri::XML(get(path, options))
|
23
|
+
|
24
|
+
e = doc.search("//error")
|
25
|
+
|
26
|
+
# Deal with whatever error comes back
|
27
|
+
if e.size > 0
|
28
|
+
raise case e.first.attributes['code'].value
|
29
|
+
when "100"
|
30
|
+
GovKit::NotAuthorized
|
31
|
+
when "300"
|
32
|
+
GovKit::InvalidRequest
|
33
|
+
when "200"
|
34
|
+
GovKit::ResourceNotFound
|
35
|
+
else
|
36
|
+
GovKit::InvalidRequest
|
37
|
+
end, e.first.attributes['text'].value
|
38
|
+
end
|
39
|
+
|
40
|
+
doc
|
41
|
+
end
|
42
|
+
|
43
|
+
# Convert the hash array returned by Nokogiri, which has Nokogiri::XML::Attr objects as values,
|
44
|
+
# to an array of hashes with string values.
|
45
|
+
#
|
46
|
+
# @param [Array] result array of hashes, with object values.
|
47
|
+
# @return [Array] array of hashes, with string values.
|
48
|
+
def self.stringify_values_of(result)
|
49
|
+
result.collect! { |r| r.inject({}) {|h, (k, v)| h[k] = v.to_s; h } }
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
# Provides classes to wrap {http://www.followthemoney.org/index.phtml FollowTheMoney} data.
|
54
|
+
#
|
55
|
+
# For the details on the FollowTheMoney queries, see {http://www.followthemoney.org/services/methods.phtml the FollowTheMoney API documentation}.
|
56
|
+
module FollowTheMoney
|
57
|
+
|
58
|
+
# Wrap {http://www.followthemoney.org/services/method_doc.phtml?a=11 Industry data}
|
59
|
+
class Business < FollowTheMoneyResource
|
60
|
+
|
61
|
+
# Return a list of all business, industry, and sector categories. See the {http://www.followthemoney.org/services/method_doc.phtml?a=11 FollowTheMoney API}.
|
62
|
+
#
|
63
|
+
# @return [Business] A list of Business objects.
|
64
|
+
def self.list
|
65
|
+
next_page, result, page_num = "yes", [], 0
|
66
|
+
|
67
|
+
until next_page != "yes"
|
68
|
+
# puts "Getting batch number #{page_num}"
|
69
|
+
|
70
|
+
doc = get_xml("/base_level.industries.list.php", :query => {:page => page_num})
|
71
|
+
|
72
|
+
next_page = doc.children.first.attributes['next_page'].value
|
73
|
+
|
74
|
+
page_num += 1
|
75
|
+
|
76
|
+
result += doc.search('//business_detail').collect { |x| x.attributes }
|
77
|
+
end
|
78
|
+
|
79
|
+
stringify_values_of(result)
|
80
|
+
parse(result)
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
# Wrap contributions to a candidate. See the {http://www.followthemoney.org/services/method_doc.phtml?a=32 FollowTheMoney API}.
|
85
|
+
class Contribution < FollowTheMoneyResource
|
86
|
+
|
87
|
+
# Return contributions to a candidate. See the {http://www.followthemoney.org/services/method_doc.phtml?a=32 FollowTheMoney API}.
|
88
|
+
#
|
89
|
+
# @param [Integer] nimsp_id the candidate id.
|
90
|
+
#
|
91
|
+
# @return [Contribution] a Contribution object, or array of Contribution objects, representing the contributions.
|
92
|
+
def self.find(nimsp_id)
|
93
|
+
next_page, result, page_num = "yes", [], 0
|
94
|
+
|
95
|
+
until next_page != "yes"
|
96
|
+
doc = get_xml("/candidates.contributions.php", :query => {"imsp_candidate_id" => nimsp_id, :page => page_num})
|
97
|
+
|
98
|
+
next_page = doc.children.first.attributes['next_page'].value
|
99
|
+
|
100
|
+
page_num += 1
|
101
|
+
|
102
|
+
result += doc.search('//contribution').collect { |x| x.attributes }
|
103
|
+
end
|
104
|
+
|
105
|
+
stringify_values_of(result)
|
106
|
+
parse(result)
|
107
|
+
end
|
108
|
+
|
109
|
+
# Return a list of the top contributors to a candidate. See the {http://www.followthemoney.org/services/method_doc.phtml?a=20 FollowTheMoney API}.
|
110
|
+
#
|
111
|
+
# @param [Integer] nimsp_id the candidate id.
|
112
|
+
#
|
113
|
+
# @return [[Contribution]] an array of Contribution objects.
|
114
|
+
def self.top(nimsp_id)
|
115
|
+
doc = get_xml("/candidates.top_contributor.php", :query => {"imsp_candidate_id" => nimsp_id})
|
116
|
+
result = doc.search('//top_contributor').collect { |x| x.attributes }
|
117
|
+
|
118
|
+
stringify_values_of(result)
|
119
|
+
parse(result)
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
# Wrap contributions by industry to a candidate. See the {http://www.followthemoney.org/services/method_doc.phtml?a=24 FollowTheMoney API}.
|
124
|
+
#
|
125
|
+
class IndustryContribution < Contribution
|
126
|
+
# Return contributions by industry.
|
127
|
+
#
|
128
|
+
# @param [Integer] nimsp_id the candidate id.
|
129
|
+
#
|
130
|
+
# @return [[Contribution]] an array of Contribution objects.
|
131
|
+
def self.find(nimsp_id)
|
132
|
+
doc = get_xml("/candidates.industries.php", :query => {"imsp_candidate_id" => nimsp_id})
|
133
|
+
result = doc.search('//candidate_industry').collect { |x| x.attributes }
|
134
|
+
|
135
|
+
stringify_values_of(result)
|
136
|
+
parse(result)
|
137
|
+
end
|
138
|
+
end
|
139
|
+
|
140
|
+
# Wrap contributions by sector to a candidate. See the {http://www.followthemoney.org/services/method_doc.phtml?a=23 FollowTheMoney API}.
|
141
|
+
#
|
142
|
+
class SectorContribution < Contribution
|
143
|
+
# Return conributions by sector.
|
144
|
+
#
|
145
|
+
# @param [Integer] nimsp_id the candidate id.
|
146
|
+
#
|
147
|
+
# @return [[Contribution]] an array of Contribution objects.
|
148
|
+
def self.find(nimsp_id)
|
149
|
+
doc = get_xml("/candidates.sectors.php", :query => {"imsp_candidate_id" => nimsp_id})
|
150
|
+
|
151
|
+
result = doc.search('//candidate_sector').collect { |x| x.attributes }
|
152
|
+
|
153
|
+
stringify_values_of(result)
|
154
|
+
parse(result)
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
# Wrap contributions by business to a candidate. See the {http://www.followthemoney.org/services/method_doc.phtml?a=25 FollowTheMoney API}.
|
159
|
+
#
|
160
|
+
class BusinessContribution < Contribution
|
161
|
+
# Return contributions by business.
|
162
|
+
#
|
163
|
+
# @param [Integer] nimsp_id the candidate id.
|
164
|
+
#
|
165
|
+
# @return [[Contribution]] an array of Contribution objects.
|
166
|
+
def self.find(nimsp_id)
|
167
|
+
doc = get_xml("/candidates.businesses.php", :query => {"imsp_candidate_id" => nimsp_id})
|
168
|
+
|
169
|
+
result = doc.search('//candidate_business').collect { |x| x.attributes }
|
170
|
+
|
171
|
+
stringify_values_of(result)
|
172
|
+
parse(result)
|
173
|
+
end
|
174
|
+
end
|
175
|
+
end
|
176
|
+
end
|
@@ -0,0 +1,125 @@
|
|
1
|
+
require 'nokogiri'
|
2
|
+
require 'open-uri'
|
3
|
+
require 'json'
|
4
|
+
require 'CGI'
|
5
|
+
|
6
|
+
module GovKit::OpenCongress
|
7
|
+
autoload :Bill, 'gov_kit/open_congress/bill'
|
8
|
+
autoload :BlogPost, 'gov_kit/open_congress/blog_post'
|
9
|
+
autoload :NewsPost, 'gov_kit/open_congress/news_post'
|
10
|
+
autoload :VotingComparison, 'gov_kit/open_congress/voting_comparison'
|
11
|
+
autoload :RollCallComparison, 'gov_kit/open_congress/roll_call_comparison'
|
12
|
+
autoload :Person, 'gov_kit/open_congress/person'
|
13
|
+
autoload :PersonStat, 'gov_kit/open_congress/person_stat'
|
14
|
+
|
15
|
+
# Parent class for classes that wrap {http://www.opencongress.org/api OpenCongress data}.
|
16
|
+
#
|
17
|
+
# Unlike the wrapper classes for data from {FollowTheMoneyResource FollowTheMoney},
|
18
|
+
# {OpenStatesResource OpenStates}, {TransparencyDataResource TransparencyData},
|
19
|
+
# and {VoteSmartResource VoteSmart}, OpenCongressObject does not inherit
|
20
|
+
# from {GovKit::Resource}
|
21
|
+
#
|
22
|
+
class OpenCongressObject
|
23
|
+
|
24
|
+
def initialize(obj, params)
|
25
|
+
params.each do |key, value|
|
26
|
+
key = key.to_sym if RUBY_VERSION[0,3] == "1.9"
|
27
|
+
instance_variable_set("@#{key}", value) if obj.instance_methods.include? key
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
# Create a query url, by adding the method path and query parameters to the
|
32
|
+
# base url of {http://www.opencongress.org/api}.
|
33
|
+
def self.construct_url(api_method, params)
|
34
|
+
url = nil
|
35
|
+
getkey = GovKit::configuration.opencongress_apikey.nil? ? "" : "&key=#{GovKit::configuration.opencongress_apikey}"
|
36
|
+
url = "http://#{GovKit::configuration.opencongress_base_url}api/#{api_method}?format=json#{hash2get(params)}#{getkey}"
|
37
|
+
return url
|
38
|
+
end
|
39
|
+
|
40
|
+
# Convert a hash to a string of query parameters.
|
41
|
+
#
|
42
|
+
# @param [Hash] h a hash.
|
43
|
+
# @return [String] a string of query parameters.
|
44
|
+
def self.hash2get(h)
|
45
|
+
get_string = ""
|
46
|
+
|
47
|
+
h.each_pair do |key, value|
|
48
|
+
get_string += "&#{key.to_s}=#{CGI::escape(value.to_s)}"
|
49
|
+
end
|
50
|
+
|
51
|
+
get_string
|
52
|
+
end
|
53
|
+
|
54
|
+
# Iterates through the array returned by {make_call},
|
55
|
+
# converting each hash to an OpenCongressObject subclass.
|
56
|
+
#
|
57
|
+
# @param [Hash] results the array returned by make_call.
|
58
|
+
# @return a hash of arrays of OpenCongressObject objects, with these keys:
|
59
|
+
# * :also_supporting_bills
|
60
|
+
# * :also_opposing_bills
|
61
|
+
# * :also_disapproved_senators
|
62
|
+
# * :also_disapproved_representatives
|
63
|
+
# * :also_approved_senators
|
64
|
+
# * :also_approved_representatives
|
65
|
+
def self.parse_supporting_results(result)
|
66
|
+
working = result["opencongress_users_tracking"]
|
67
|
+
|
68
|
+
also_supporting_bills = []
|
69
|
+
working["also_supporting_bills"]["bill"].each do |bill|
|
70
|
+
also_supporting_bills << Bill.new(bill)
|
71
|
+
end
|
72
|
+
|
73
|
+
also_opposing_bills = []
|
74
|
+
working["also_opposing_bills"]["bill"].each do |bill|
|
75
|
+
also_opposing_bills << Bill.new(bill)
|
76
|
+
end
|
77
|
+
|
78
|
+
also_disapproved_senators = []
|
79
|
+
working["also_disapproved_senators"]["person"].each do |person|
|
80
|
+
also_disapproved_senators << Person.new(person)
|
81
|
+
end
|
82
|
+
|
83
|
+
also_disapproved_representatives = []
|
84
|
+
working["also_disapproved_representatives"]["person"].each do |person|
|
85
|
+
also_disapproved_representatives << Person.new(person)
|
86
|
+
end
|
87
|
+
|
88
|
+
also_approved_senators = []
|
89
|
+
working["also_approved_senators"]["person"].each do |person|
|
90
|
+
also_approved_senators << Person.new(person)
|
91
|
+
end
|
92
|
+
|
93
|
+
also_approved_representatives = []
|
94
|
+
working["also_approved_representatives"]["person"].each do |person|
|
95
|
+
also_approved_representatives << Person.new(person)
|
96
|
+
end
|
97
|
+
|
98
|
+
return {:also_supporting_bills => also_supporting_bills,
|
99
|
+
:also_opposing_bills => also_opposing_bills,
|
100
|
+
:also_disapproved_senators => also_disapproved_senators,
|
101
|
+
:also_disapproved_representatives => also_disapproved_representatives,
|
102
|
+
:also_approved_senators => also_approved_senators,
|
103
|
+
:also_approved_representatives => also_approved_representatives}
|
104
|
+
|
105
|
+
end
|
106
|
+
|
107
|
+
# Get the data from {http://www.opencongress.org/api OpenCongress data}. Called by subclasses.
|
108
|
+
#
|
109
|
+
# Parses the data using {http://flori.github.com/json/doc/index.html JSON.parse}, which
|
110
|
+
# returns an array of hashes.
|
111
|
+
#
|
112
|
+
# @return the returned data, as an array of hashes.
|
113
|
+
def self.make_call(this_url)
|
114
|
+
result = nil
|
115
|
+
begin
|
116
|
+
result = JSON.parse(open(this_url).read)
|
117
|
+
rescue => e
|
118
|
+
puts e
|
119
|
+
end
|
120
|
+
|
121
|
+
return result
|
122
|
+
|
123
|
+
end
|
124
|
+
end
|
125
|
+
end
|