govkit 0.7.1 → 0.7.2
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/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
|
|