govkit 0.7.1 → 0.7.2
Sign up to get free protection for your applications and to get access to all the features.
- data/Gemfile +2 -2
- data/README.md +8 -0
- data/VERSION +1 -1
- data/generators/govkit/govkit_generator.rb +4 -0
- data/generators/govkit/templates/create_mentions.rb +21 -0
- data/generators/govkit/templates/govkit.rb +1 -5
- data/generators/govkit/templates/mention.rb +15 -0
- data/govkit.gemspec +24 -7
- data/lib/generators/govkit/govkit_generator.rb +6 -2
- data/lib/generators/govkit/templates/create_mentions.rb +21 -0
- data/lib/generators/govkit/templates/govkit.rb +4 -5
- data/lib/generators/govkit/templates/mention.rb +15 -0
- data/lib/gov_kit/acts_as_noteworthy.rb +10 -3
- data/lib/gov_kit/configuration.rb +17 -3
- data/lib/gov_kit/follow_the_money.rb +62 -2
- data/lib/gov_kit/open_congress.rb +39 -12
- data/lib/gov_kit/resource.rb +26 -16
- data/lib/gov_kit.rb +0 -1
- data/spec/fixtures/open_congress/501.response +8 -0
- data/spec/fixtures/open_congress/bill.response +8 -0
- data/spec/fixtures/open_congress/empty.response +8 -0
- data/spec/fixtures/open_congress/fl01.response +8 -0
- data/spec/open_congress_spec.rb +73 -1
- data/spec/spec_helper.rb +0 -1
- metadata +56 -66
data/Gemfile
CHANGED
@@ -2,7 +2,7 @@ source 'http://rubygems.org'
|
|
2
2
|
|
3
3
|
gemspec
|
4
4
|
|
5
|
-
gem "active_support
|
5
|
+
gem "activesupport", :require => 'active_support'
|
6
6
|
gem "nokogiri"
|
7
7
|
gem "httparty"
|
8
8
|
gem "i18n"
|
@@ -10,4 +10,4 @@ gem "i18n"
|
|
10
10
|
group :test do
|
11
11
|
gem "rspec"
|
12
12
|
gem "fakeweb"
|
13
|
-
end
|
13
|
+
end
|
data/README.md
CHANGED
@@ -20,6 +20,14 @@ Add govkit to your environment.rb or Gemfile
|
|
20
20
|
|
21
21
|
Run <code>rails generate govkit</code> (Rails 3.x) or <code>script/generate govkit</code> (Rails 2.x) to copy a config file into <code>config/initializers/govkit.rb</code>. You will need to add your API keys to this config file.
|
22
22
|
|
23
|
+
Outside of Rails you can configure your API keys like so:
|
24
|
+
|
25
|
+
>> GovKit.configure do |config|
|
26
|
+
>> config.sunlight_apikey = 'YOUR_SUNLIGHT_API_KEY'
|
27
|
+
>> config.votesmart_apikey = 'YOUR_VOTESMART_API_KEY'
|
28
|
+
>> config.ftm_apikey = 'YOUR_FTM_API_KEY'
|
29
|
+
>> end
|
30
|
+
|
23
31
|
# Usage Examples
|
24
32
|
|
25
33
|
>> GovKit::OpenStates::State.find_by_abbreviation('CA')
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.7.
|
1
|
+
0.7.2
|
@@ -8,6 +8,10 @@ class GovkitGenerator < Rails::Generator::Base
|
|
8
8
|
record do |m|
|
9
9
|
m.directory File.join('config', 'initializers')
|
10
10
|
m.template 'govkit.rb', File.join('config', 'initializers', 'govkit.rb')
|
11
|
+
m.directory File.join('app', 'models')
|
12
|
+
m.template 'mention.rb', File.join('app', 'models', 'mention.rb')
|
13
|
+
m.directory File.join('db', 'migrate')
|
14
|
+
m.template 'create_mentions.rb', File.join('db', 'migrate', 'create_mentions.rb')
|
11
15
|
end
|
12
16
|
end
|
13
17
|
|
@@ -0,0 +1,21 @@
|
|
1
|
+
class CreateMentions < ActiveRecord::Migration
|
2
|
+
def self.up
|
3
|
+
create_table :mentions, :force => true do |t|
|
4
|
+
t.string "url", :limit => 8000
|
5
|
+
t.string "excerpt", :limit => 4000
|
6
|
+
t.string "title", :limit => 1000
|
7
|
+
t.string "source"
|
8
|
+
t.datetime "date"
|
9
|
+
t.float "weight"
|
10
|
+
t.integer "owner_id"
|
11
|
+
t.string "owner_type"
|
12
|
+
t.string "search_source"
|
13
|
+
t.datetime "created_at"
|
14
|
+
t.datetime "updated_at"
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.down
|
19
|
+
drop_table :mentions
|
20
|
+
end
|
21
|
+
end
|
@@ -11,13 +11,9 @@ if defined? GovKit
|
|
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
|
-
|
15
|
-
# Api key for OpenCongress
|
16
|
-
# http://www.opencongress.org/api
|
17
|
-
config.opencongress_apikey = 'YOUR_OPENCONGRESS_API_KEY'
|
18
14
|
|
19
15
|
# Technorati API key
|
20
|
-
config.technorati_apikey = 'YOUR_TECHNORATI_APIKEY'
|
16
|
+
# config.technorati_apikey = 'YOUR_TECHNORATI_APIKEY'
|
21
17
|
|
22
18
|
# Bing App ID
|
23
19
|
config.bing_appid = 'YOUR_BING_APPID'
|
@@ -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/govkit.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{govkit}
|
8
|
-
s.version = "0.7.
|
8
|
+
s.version = "0.7.2"
|
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{
|
12
|
+
s.date = %q{2012-01-23}
|
13
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{develop@opencongress.org}
|
15
15
|
s.extra_rdoc_files = [
|
@@ -26,11 +26,15 @@ Gem::Specification.new do |s|
|
|
26
26
|
"USAGE",
|
27
27
|
"VERSION",
|
28
28
|
"generators/govkit/govkit_generator.rb",
|
29
|
+
"generators/govkit/templates/create_mentions.rb",
|
29
30
|
"generators/govkit/templates/govkit.rb",
|
31
|
+
"generators/govkit/templates/mention.rb",
|
30
32
|
"govkit.gemspec",
|
31
33
|
"init.rb",
|
32
34
|
"lib/generators/govkit/govkit_generator.rb",
|
35
|
+
"lib/generators/govkit/templates/create_mentions.rb",
|
33
36
|
"lib/generators/govkit/templates/govkit.rb",
|
37
|
+
"lib/generators/govkit/templates/mention.rb",
|
34
38
|
"lib/gov_kit.rb",
|
35
39
|
"lib/gov_kit/acts_as_noteworthy.rb",
|
36
40
|
"lib/gov_kit/configuration.rb",
|
@@ -62,6 +66,10 @@ Gem::Specification.new do |s|
|
|
62
66
|
"spec/fixtures/follow_the_money/business-page1.response",
|
63
67
|
"spec/fixtures/follow_the_money/contribution.response",
|
64
68
|
"spec/fixtures/follow_the_money/unauthorized.response",
|
69
|
+
"spec/fixtures/open_congress/501.response",
|
70
|
+
"spec/fixtures/open_congress/bill.response",
|
71
|
+
"spec/fixtures/open_congress/empty.response",
|
72
|
+
"spec/fixtures/open_congress/fl01.response",
|
65
73
|
"spec/fixtures/open_congress/person.response",
|
66
74
|
"spec/fixtures/open_states/401.response",
|
67
75
|
"spec/fixtures/open_states/404.response",
|
@@ -89,15 +97,24 @@ Gem::Specification.new do |s|
|
|
89
97
|
]
|
90
98
|
s.homepage = %q{http://github.com/opengovernment/govkit}
|
91
99
|
s.require_paths = ["lib"]
|
92
|
-
s.rubygems_version = %q{1.6
|
100
|
+
s.rubygems_version = %q{1.3.6}
|
93
101
|
s.summary = %q{Simple access to open government APIs around the web}
|
102
|
+
s.test_files = [
|
103
|
+
"spec/follow_the_money_spec.rb",
|
104
|
+
"spec/open_congress_spec.rb",
|
105
|
+
"spec/open_states_spec.rb",
|
106
|
+
"spec/search_engines_spec.rb",
|
107
|
+
"spec/spec_helper.rb",
|
108
|
+
"spec/transparency_data_spec.rb"
|
109
|
+
]
|
94
110
|
|
95
111
|
if s.respond_to? :specification_version then
|
112
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
96
113
|
s.specification_version = 3
|
97
114
|
|
98
|
-
if Gem::Version.new(Gem::
|
115
|
+
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
99
116
|
s.add_runtime_dependency(%q<govkit>, [">= 0"])
|
100
|
-
s.add_runtime_dependency(%q<
|
117
|
+
s.add_runtime_dependency(%q<activesupport>, [">= 0"])
|
101
118
|
s.add_runtime_dependency(%q<nokogiri>, [">= 0"])
|
102
119
|
s.add_runtime_dependency(%q<httparty>, [">= 0"])
|
103
120
|
s.add_runtime_dependency(%q<i18n>, [">= 0"])
|
@@ -107,7 +124,7 @@ Gem::Specification.new do |s|
|
|
107
124
|
s.add_runtime_dependency(%q<fastercsv>, [">= 1.5.3"])
|
108
125
|
else
|
109
126
|
s.add_dependency(%q<govkit>, [">= 0"])
|
110
|
-
s.add_dependency(%q<
|
127
|
+
s.add_dependency(%q<activesupport>, [">= 0"])
|
111
128
|
s.add_dependency(%q<nokogiri>, [">= 0"])
|
112
129
|
s.add_dependency(%q<httparty>, [">= 0"])
|
113
130
|
s.add_dependency(%q<i18n>, [">= 0"])
|
@@ -118,7 +135,7 @@ Gem::Specification.new do |s|
|
|
118
135
|
end
|
119
136
|
else
|
120
137
|
s.add_dependency(%q<govkit>, [">= 0"])
|
121
|
-
s.add_dependency(%q<
|
138
|
+
s.add_dependency(%q<activesupport>, [">= 0"])
|
122
139
|
s.add_dependency(%q<nokogiri>, [">= 0"])
|
123
140
|
s.add_dependency(%q<httparty>, [">= 0"])
|
124
141
|
s.add_dependency(%q<i18n>, [">= 0"])
|
@@ -1,17 +1,21 @@
|
|
1
1
|
require 'rails/generators'
|
2
2
|
|
3
|
+
# Generator to setup rails app for using GovKit
|
3
4
|
class GovkitGenerator < Rails::Generators::Base
|
4
5
|
|
5
6
|
def initialize(*runtime_args)
|
6
7
|
super
|
7
8
|
end
|
8
9
|
|
9
|
-
desc "Copies
|
10
|
+
desc "Copies files necessary to use govkit"
|
10
11
|
|
11
12
|
source_root File.join(File.dirname(__FILE__), 'templates')
|
12
|
-
|
13
|
+
|
14
|
+
# Copies the files necessary to use govkit (initializer, migrations, and models)
|
13
15
|
def copy_initializer_file
|
14
16
|
copy_file 'govkit.rb', File.join('config', 'initializers', 'govkit.rb')
|
17
|
+
copy_file 'mention.rb', File.join('app', 'models', 'mention.rb')
|
18
|
+
copy_file 'create_mentions.rb', File.join('db', 'migrate', "#{ Time.now.utc.strftime "%Y%m%d%H%M%S" }create_mentions.rb")
|
15
19
|
end
|
16
20
|
|
17
21
|
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
class CreateMentions < ActiveRecord::Migration
|
2
|
+
def self.up
|
3
|
+
create_table :mentions, :force => true do |t|
|
4
|
+
t.string "url", :limit => 8000
|
5
|
+
t.string "excerpt", :limit => 4000
|
6
|
+
t.string "title", :limit => 1000
|
7
|
+
t.string "source"
|
8
|
+
t.datetime "date"
|
9
|
+
t.float "weight"
|
10
|
+
t.integer "owner_id"
|
11
|
+
t.string "owner_type"
|
12
|
+
t.string "search_source"
|
13
|
+
t.datetime "created_at"
|
14
|
+
t.datetime "updated_at"
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.down
|
19
|
+
drop_table :mentions
|
20
|
+
end
|
21
|
+
end
|
@@ -11,13 +11,12 @@ if defined? GovKit
|
|
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
|
-
|
15
|
-
# Api key for OpenCongress
|
16
|
-
# http://www.opencongress.org/api
|
17
|
-
config.opencongress_apikey = 'YOUR_OPENCONGRESS_API_KEY'
|
18
14
|
|
19
15
|
# Technorati API key
|
20
|
-
config.technorati_apikey = 'YOUR_TECHNORATI_APIKEY'
|
16
|
+
# config.technorati_apikey = 'YOUR_TECHNORATI_APIKEY'
|
17
|
+
|
18
|
+
# Bing App ID
|
19
|
+
config.bing_appid = 'YOUR_BING_APPID'
|
21
20
|
|
22
21
|
# Other things you could set here include alternate URLs for
|
23
22
|
# the APIs. See GovKit::Configuration for available attributes.
|
@@ -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
|
@@ -4,7 +4,11 @@ module GovKit::ActsAsNoteworthy
|
|
4
4
|
base.extend ActMethods
|
5
5
|
end
|
6
6
|
|
7
|
+
# Module to make a rails model act as a noteworthy object, linking it to govkit's mention model
|
7
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
|
8
12
|
def acts_as_noteworthy(options={})
|
9
13
|
class_inheritable_accessor :options
|
10
14
|
self.options = options
|
@@ -16,7 +20,7 @@ module GovKit::ActsAsNoteworthy
|
|
16
20
|
with_options :as => :owner, :class_name => "Mention" do |c|
|
17
21
|
c.has_many :google_news_mentions, :conditions => {:search_source => "Google News"}, :order => 'date desc'
|
18
22
|
c.has_many :google_blog_mentions, :conditions => {:search_source => "Google Blogs"}, :order => 'date desc'
|
19
|
-
c.has_many :technorati_mentions, :conditions => {:search_source => "Technorati"}, :order => 'date desc'
|
23
|
+
# c.has_many :technorati_mentions, :conditions => {:search_source => "Technorati"}, :order => 'date desc'
|
20
24
|
c.has_many :bing_mentions, :conditions => {:search_source => "Bing"}, :order => 'date desc'
|
21
25
|
end
|
22
26
|
end
|
@@ -29,9 +33,12 @@ module GovKit::ActsAsNoteworthy
|
|
29
33
|
|
30
34
|
module ClassMethods
|
31
35
|
end
|
32
|
-
|
36
|
+
|
37
|
+
# A module that adds methods to individual instances of the noteworthy class.
|
33
38
|
module InstanceMethods
|
34
|
-
|
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.
|
35
42
|
def raw_mentions
|
36
43
|
opts = self.options.clone
|
37
44
|
attributes = opts.delete(:with)
|
@@ -10,7 +10,7 @@ module GovKit
|
|
10
10
|
attr_accessor :bing_appid, :bing_base_url
|
11
11
|
|
12
12
|
def initialize
|
13
|
-
@openstates_apikey = @votesmart_apikey = @ftm_apikey = ''
|
13
|
+
@sunlight_apikey = @openstates_apikey = @votesmart_apikey = @ftm_apikey = ''
|
14
14
|
@openstates_base_url = 'openstates.sunlightlabs.com/api/v1/'
|
15
15
|
@transparency_data_base_url = 'transparencydata.com/api/1.0/'
|
16
16
|
@votesmart_base_url = 'api.votesmart.org/'
|
@@ -25,20 +25,34 @@ module GovKit
|
|
25
25
|
# Permant home for contribution category mappings
|
26
26
|
@transparency_data_categories_url = 'http://assets.transparencydata.org.s3.amazonaws.com/docs/catcodes.csv'
|
27
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
|
28
38
|
end
|
29
39
|
|
30
40
|
class << self
|
31
41
|
attr_accessor :configuration
|
42
|
+
|
43
|
+
def configuration
|
44
|
+
@configuration = Configuration.new if @configuration.nil?
|
45
|
+
@configuration
|
46
|
+
end
|
32
47
|
end
|
33
48
|
|
34
49
|
# Configure GovKit in config/initializers/govkit.rb
|
35
50
|
#
|
36
51
|
# @example
|
37
52
|
# GovKit.configure do |config|
|
38
|
-
# config.
|
53
|
+
# config.sunlight_apikey = ''
|
39
54
|
# end
|
40
55
|
def self.configure
|
41
|
-
self.configuration ||= Configuration.new
|
42
56
|
yield(configuration)
|
43
57
|
end
|
44
58
|
end
|
@@ -1,8 +1,23 @@
|
|
1
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}.
|
2
8
|
class FollowTheMoneyResource < Resource
|
3
9
|
default_params :key => GovKit::configuration.ftm_apikey
|
4
10
|
base_uri GovKit::configuration.ftm_base_url
|
5
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
|
+
#
|
6
21
|
def self.get_xml(path, options)
|
7
22
|
doc = Nokogiri::XML(get(path, options))
|
8
23
|
|
@@ -25,15 +40,27 @@ module GovKit
|
|
25
40
|
doc
|
26
41
|
end
|
27
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.
|
28
48
|
def self.stringify_values_of(result)
|
29
|
-
# result is an array of hashes, but all the values are Nokogiri::XML::Attr objects, not strings.
|
30
|
-
# We want them to be strings.
|
31
49
|
result.collect! { |r| r.inject({}) {|h, (k, v)| h[k] = v.to_s; h } }
|
32
50
|
end
|
33
51
|
end
|
34
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}.
|
35
56
|
module FollowTheMoney
|
57
|
+
|
58
|
+
# Wrap {http://www.followthemoney.org/services/method_doc.phtml?a=11 Industry data}
|
36
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.
|
37
64
|
def self.list
|
38
65
|
next_page, result, page_num = "yes", [], 0
|
39
66
|
|
@@ -54,7 +81,14 @@ module GovKit
|
|
54
81
|
end
|
55
82
|
end
|
56
83
|
|
84
|
+
# Wrap contributions to a candidate. See the {http://www.followthemoney.org/services/method_doc.phtml?a=32 FollowTheMoney API}.
|
57
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.
|
58
92
|
def self.find(nimsp_id)
|
59
93
|
next_page, result, page_num = "yes", [], 0
|
60
94
|
|
@@ -72,6 +106,11 @@ module GovKit
|
|
72
106
|
parse(result)
|
73
107
|
end
|
74
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.
|
75
114
|
def self.top(nimsp_id)
|
76
115
|
doc = get_xml("/candidates.top_contributor.php", :query => {"imsp_candidate_id" => nimsp_id})
|
77
116
|
result = doc.search('//top_contributor').collect { |x| x.attributes }
|
@@ -81,7 +120,14 @@ module GovKit
|
|
81
120
|
end
|
82
121
|
end
|
83
122
|
|
123
|
+
# Wrap contributions by industry to a candidate. See the {http://www.followthemoney.org/services/method_doc.phtml?a=24 FollowTheMoney API}.
|
124
|
+
#
|
84
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.
|
85
131
|
def self.find(nimsp_id)
|
86
132
|
doc = get_xml("/candidates.industries.php", :query => {"imsp_candidate_id" => nimsp_id})
|
87
133
|
result = doc.search('//candidate_industry').collect { |x| x.attributes }
|
@@ -91,7 +137,14 @@ module GovKit
|
|
91
137
|
end
|
92
138
|
end
|
93
139
|
|
140
|
+
# Wrap contributions by sector to a candidate. See the {http://www.followthemoney.org/services/method_doc.phtml?a=23 FollowTheMoney API}.
|
141
|
+
#
|
94
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.
|
95
148
|
def self.find(nimsp_id)
|
96
149
|
doc = get_xml("/candidates.sectors.php", :query => {"imsp_candidate_id" => nimsp_id})
|
97
150
|
|
@@ -102,7 +155,14 @@ module GovKit
|
|
102
155
|
end
|
103
156
|
end
|
104
157
|
|
158
|
+
# Wrap contributions by business to a candidate. See the {http://www.followthemoney.org/services/method_doc.phtml?a=25 FollowTheMoney API}.
|
159
|
+
#
|
105
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.
|
106
166
|
def self.find(nimsp_id)
|
107
167
|
doc = get_xml("/candidates.businesses.php", :query => {"imsp_candidate_id" => nimsp_id})
|
108
168
|
|
@@ -4,14 +4,21 @@ require 'json'
|
|
4
4
|
require 'CGI'
|
5
5
|
|
6
6
|
module GovKit::OpenCongress
|
7
|
-
autoload :Bill,
|
8
|
-
autoload :BlogPost,
|
9
|
-
autoload :NewsPost,
|
10
|
-
autoload :VotingComparison,
|
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
11
|
autoload :RollCallComparison, 'gov_kit/open_congress/roll_call_comparison'
|
12
|
-
autoload :Person,
|
13
|
-
autoload :PersonStat,
|
12
|
+
autoload :Person, 'gov_kit/open_congress/person'
|
13
|
+
autoload :PersonStat, 'gov_kit/open_congress/person_stat'
|
14
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
|
+
#
|
15
22
|
class OpenCongressObject
|
16
23
|
|
17
24
|
def initialize(obj, params)
|
@@ -21,16 +28,19 @@ module GovKit::OpenCongress
|
|
21
28
|
end
|
22
29
|
end
|
23
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}.
|
24
33
|
def self.construct_url(api_method, params)
|
25
34
|
url = nil
|
26
|
-
|
27
|
-
|
28
|
-
else
|
29
|
-
url = "http://#{GovKit::configuration.opencongress_base_url}api/#{api_method}?key=#{GovKit::configuration.opencongress_apikey}#{hash2get(params)}&format=json"
|
30
|
-
end
|
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}"
|
31
37
|
return url
|
32
38
|
end
|
33
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.
|
34
44
|
def self.hash2get(h)
|
35
45
|
get_string = ""
|
36
46
|
|
@@ -41,6 +51,17 @@ module GovKit::OpenCongress
|
|
41
51
|
get_string
|
42
52
|
end
|
43
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
|
44
65
|
def self.parse_supporting_results(result)
|
45
66
|
working = result["opencongress_users_tracking"]
|
46
67
|
|
@@ -83,6 +104,12 @@ module GovKit::OpenCongress
|
|
83
104
|
|
84
105
|
end
|
85
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.
|
86
113
|
def self.make_call(this_url)
|
87
114
|
result = nil
|
88
115
|
begin
|
@@ -95,4 +122,4 @@ module GovKit::OpenCongress
|
|
95
122
|
|
96
123
|
end
|
97
124
|
end
|
98
|
-
end
|
125
|
+
end
|
data/lib/gov_kit/resource.rb
CHANGED
@@ -1,29 +1,30 @@
|
|
1
1
|
module GovKit
|
2
2
|
|
3
|
-
|
3
|
+
|
4
|
+
# This is the parent class for the classes that wrap
|
4
5
|
# the data returned to govkit.
|
5
6
|
#
|
6
|
-
#
|
7
|
-
# different web services; Resource will then parse the
|
7
|
+
# Subclasses are responsible for fetching the data from
|
8
|
+
# different web services; Resource will then parse the returned data,
|
8
9
|
# converting returned fields to instance methods.
|
9
10
|
#
|
10
11
|
# Initialize a Resource with a hash of attributes, or an array of hashes.
|
11
12
|
# For each attribute, add a getter and setter to this instance.
|
12
|
-
#
|
13
|
+
# @example
|
13
14
|
# res = Resource.new { "aaa" => "111", "bbb" => "222", "ccc" => "333" }
|
14
|
-
# then
|
15
15
|
# res.aaa == "111"
|
16
16
|
# res.bbb == "222"
|
17
17
|
# res.ccc == "333"
|
18
18
|
#
|
19
|
-
# Includes HTTParty, which provides convenience methods like get().
|
20
|
-
#
|
21
|
-
# See http://rdoc.info/github/jnunemaker/httparty/master/HTTParty/ClassMethods
|
19
|
+
# Includes {http://rdoc.info/github/jnunemaker/httparty/master/HTTParty/ClassMethods HTTParty}, which provides convenience methods like get().
|
22
20
|
class Resource
|
23
21
|
include HTTParty
|
24
22
|
format :json
|
25
23
|
|
24
|
+
# The attributes data returned by the service.
|
26
25
|
attr_reader :attributes
|
26
|
+
|
27
|
+
# The response returned by the service.
|
27
28
|
attr_reader :raw_response
|
28
29
|
|
29
30
|
def initialize(attributes = {})
|
@@ -33,21 +34,22 @@ module GovKit
|
|
33
34
|
unload(attributes)
|
34
35
|
end
|
35
36
|
|
36
|
-
#
|
37
|
-
# on sync
|
37
|
+
# @return [Hash] the response object, potentially useful for comparison on sync
|
38
38
|
#
|
39
39
|
def to_md5
|
40
40
|
Digest::MD5.hexdigest(@raw_response.body)
|
41
41
|
end
|
42
42
|
|
43
|
-
# Handles the basic responses we might get back from
|
44
|
-
# On success, returns a new Resource based on the response.
|
43
|
+
# Handles the basic responses we might get back from a web service.
|
45
44
|
#
|
46
45
|
# On failure, throws an error.
|
47
46
|
#
|
48
47
|
# If a service returns something other than a 404 when an object is not found,
|
49
48
|
# you'll need to handle that in the subclass.
|
50
49
|
#
|
50
|
+
# @param [Object] response the object.
|
51
|
+
# @return [Resource] a new Resource created from the response.
|
52
|
+
#
|
51
53
|
def self.parse(response)
|
52
54
|
|
53
55
|
if response.class == HTTParty::Response
|
@@ -72,8 +74,8 @@ module GovKit
|
|
72
74
|
|
73
75
|
# Instantiate new GovKit::Resources.
|
74
76
|
#
|
75
|
-
#
|
76
|
-
#
|
77
|
+
# @param [Hash] record a hash of values returned by a service, or an array of hashes.
|
78
|
+
# @return [Resource]
|
77
79
|
#
|
78
80
|
# If +record+ is a hash, return a single GovKit::Resource.
|
79
81
|
# If it is an array, return an array of GovKit::Resources.
|
@@ -86,16 +88,24 @@ module GovKit
|
|
86
88
|
end
|
87
89
|
end
|
88
90
|
|
91
|
+
# Instantiate a set of records.
|
92
|
+
#
|
93
|
+
# @return [Array] Array of records
|
94
|
+
# @param [Array] collection An array of records
|
89
95
|
def self.instantiate_collection(collection)
|
90
96
|
collection.collect! { |record| new(record) }
|
91
97
|
end
|
92
98
|
|
93
|
-
# Given a hash of attributes, assign it to the @attributes member
|
94
|
-
#
|
99
|
+
# Given a hash of attributes, assign it to the @attributes member.
|
100
|
+
# Then for each attribute, create or set a pair of member accessors with the name
|
95
101
|
# of the attribute's key.
|
102
|
+
#
|
96
103
|
# If the value of the attribute is itself an array or a hash,
|
97
104
|
# then create a new class with the (singularized) key as a name, and with a parent class of Resource,
|
98
105
|
# and initialize it with the hash.
|
106
|
+
#
|
107
|
+
# @param [Hash] attributes the attributes returned by the web service.
|
108
|
+
#
|
99
109
|
def unload(attributes)
|
100
110
|
raise ArgumentError, "expected an attributes Hash, got #{attributes.inspect}" unless attributes.is_a?(Hash)
|
101
111
|
|