campaign_cash 2.6.2 → 2.7
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/Gemfile +1 -2
- data/Gemfile.lock +24 -6
- data/README.rdoc +3 -2
- data/campaign_cash.gemspec +1 -1
- data/lib/campaign_cash/base.rb +4 -4
- data/lib/campaign_cash/candidate.rb +50 -51
- data/lib/campaign_cash/committee.rb +83 -83
- data/lib/campaign_cash/contribution.rb +35 -35
- data/lib/campaign_cash/electioneering_communication.rb +3 -3
- data/lib/campaign_cash/filing.rb +25 -25
- data/lib/campaign_cash/form.rb +2 -2
- data/lib/campaign_cash/independent_expenditure.rb +26 -26
- data/lib/campaign_cash/individual_contribution.rb +2 -9
- data/lib/campaign_cash/late_contribution.rb +6 -6
- data/lib/campaign_cash/president.rb +39 -39
- data/lib/campaign_cash/version.rb +1 -1
- data/test/campaign_cash/test_candidate.rb +82 -82
- data/test/campaign_cash/test_committee.rb +2 -2
- data/test/campaign_cash/test_electioneering_communication.rb +25 -12
- data/test/campaign_cash/test_independent_expenditure.rb +1 -1
- data/test/campaign_cash/test_individual_contribution.rb +14 -9
- data/test/campaign_cash/test_late_contribution.rb +16 -14
- metadata +17 -27
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 1f3b1de65d4075a661491c7b39845b149389069b
|
4
|
+
data.tar.gz: 9400600b140cb97b32b3d47c2739605f490ff7fc
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 092c6bae7e00ac042a0e31fd5fcb3cce57c4d256210bfd0495850547c3fd1c91919ce4eba0138e58d7ec1f7ab89654c709df6642bb819c407b274f2b125101e1
|
7
|
+
data.tar.gz: 047fae4dd3ea84fd7baaae4d34a2747cf7ec90f0c162d0c570a9657445433ffaf533fe30bd2c57ae7c8bb9c424c95a65824b2841eeba2c2b9f1795efed1cfcf5
|
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,15 +1,33 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
campaign_cash (2.
|
4
|
+
campaign_cash (2.7)
|
5
5
|
json
|
6
6
|
|
7
7
|
GEM
|
8
|
-
remote:
|
8
|
+
remote: https://rubygems.org/
|
9
9
|
specs:
|
10
|
-
|
11
|
-
|
12
|
-
|
10
|
+
activesupport (4.0.3)
|
11
|
+
i18n (~> 0.6, >= 0.6.4)
|
12
|
+
minitest (~> 4.2)
|
13
|
+
multi_json (~> 1.3)
|
14
|
+
thread_safe (~> 0.1)
|
15
|
+
tzinfo (~> 0.3.37)
|
16
|
+
atomic (1.1.15)
|
17
|
+
i18n (0.6.9)
|
18
|
+
json (1.8.1)
|
19
|
+
minitest (4.3.2)
|
20
|
+
multi_json (1.8.4)
|
21
|
+
rake (10.1.1)
|
22
|
+
shoulda (3.5.0)
|
23
|
+
shoulda-context (~> 1.0, >= 1.0.1)
|
24
|
+
shoulda-matchers (>= 1.4.1, < 3.0)
|
25
|
+
shoulda-context (1.1.6)
|
26
|
+
shoulda-matchers (2.5.0)
|
27
|
+
activesupport (>= 3.0.0)
|
28
|
+
thread_safe (0.2.0)
|
29
|
+
atomic (>= 1.1.7, < 2)
|
30
|
+
tzinfo (0.3.38)
|
13
31
|
|
14
32
|
PLATFORMS
|
15
33
|
ruby
|
@@ -17,5 +35,5 @@ PLATFORMS
|
|
17
35
|
DEPENDENCIES
|
18
36
|
bundler (>= 1.0.0)
|
19
37
|
campaign_cash!
|
20
|
-
rake (
|
38
|
+
rake (>= 10.0)
|
21
39
|
shoulda
|
data/README.rdoc
CHANGED
@@ -8,10 +8,11 @@
|
|
8
8
|
|
9
9
|
== DESCRIPTION:
|
10
10
|
|
11
|
-
Simple ruby wrapper for portions of The New York Times Campaign Finance API[http://developer.nytimes.com/docs/read/campaign_finance_api]. You'll need an API key. Tested under Ruby 1.
|
11
|
+
Simple ruby wrapper for portions of The New York Times Campaign Finance API[http://developer.nytimes.com/docs/read/campaign_finance_api]. You'll need an API key. Tested under Ruby 1.9.3, 2.0.0 and 2.1.0.
|
12
12
|
|
13
13
|
== News
|
14
14
|
|
15
|
+
* March 3, 2014: Version 2.7 released. Updated for Ruby 2.x support, dropped support for 1.8.7.
|
15
16
|
* July 22, 2013: Version 2.6.2 released. Changed current cycle to 2014.
|
16
17
|
* April 10, 2013: Version 2.6.1 released. Fixed bad attribute name for Filing#filing_id.
|
17
18
|
* April 9, 2013: Version 2.6 released. Added missing attribute accessors to Filing objects.
|
@@ -260,4 +261,4 @@ Electioneering Communications are broadcast ads funded by third party groups tha
|
|
260
261
|
|
261
262
|
== Copyright
|
262
263
|
|
263
|
-
Copyright (c)
|
264
|
+
Copyright (c) 2014 The New York Times Company. See LICENSE for details.
|
data/campaign_cash.gemspec
CHANGED
@@ -16,7 +16,7 @@ Gem::Specification.new do |s|
|
|
16
16
|
s.rubyforge_project = "campaign_cash"
|
17
17
|
s.add_runtime_dependency "json"
|
18
18
|
|
19
|
-
s.add_development_dependency "rake", "0
|
19
|
+
s.add_development_dependency "rake", ">= 10.0"
|
20
20
|
s.add_development_dependency "bundler", ">= 1.0.0"
|
21
21
|
s.add_development_dependency "shoulda"
|
22
22
|
|
data/lib/campaign_cash/base.rb
CHANGED
@@ -67,9 +67,9 @@ module CampaignCash
|
|
67
67
|
##
|
68
68
|
# Builds a request URI to call the API server
|
69
69
|
def build_request_url(path, params)
|
70
|
-
URI::HTTP.build :
|
71
|
-
|
72
|
-
:
|
70
|
+
URI::HTTP.build host: API_SERVER,
|
71
|
+
path: "#{API_BASE}/#{path}.json",
|
72
|
+
query: params.map {|k,v| "#{k}=#{v}"}.join('&')
|
73
73
|
end
|
74
74
|
|
75
75
|
def invoke(path, params={})
|
@@ -78,7 +78,7 @@ module CampaignCash
|
|
78
78
|
raise "You must initialize the API key before you run any API queries"
|
79
79
|
end
|
80
80
|
|
81
|
-
full_params = params.merge
|
81
|
+
full_params = params.merge({"api-key" => @@api_key})
|
82
82
|
full_params.delete_if {|k,v| v.nil?}
|
83
83
|
|
84
84
|
check_offset(params[:offset]) if params[:offset]
|
@@ -5,11 +5,11 @@ module CampaignCash
|
|
5
5
|
# A candidate is a person seeking a particular office within a particular two-year election
|
6
6
|
# cycle. Each candidate is assigned a unique ID within a cycle.
|
7
7
|
attr_reader :name, :id, :state, :district, :party, :fec_uri, :committee_id,
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
8
|
+
:mailing_city, :mailing_address, :mailing_state, :mailing_zip,
|
9
|
+
:total_receipts, :total_contributions, :total_from_individuals,
|
10
|
+
:total_from_pacs, :candidate_loans, :total_disbursements,
|
11
|
+
:total_refunds, :debts_owed, :begin_cash, :end_cash, :status,
|
12
|
+
:date_coverage_to, :date_coverage_from, :relative_uri, :office
|
13
13
|
|
14
14
|
def initialize(params={})
|
15
15
|
params.each_pair do |k,v|
|
@@ -19,42 +19,41 @@ module CampaignCash
|
|
19
19
|
|
20
20
|
# Creates a new candidate object from a JSON API response.
|
21
21
|
def self.create(params={})
|
22
|
-
self.new :
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
22
|
+
self.new name: params['name'],
|
23
|
+
id: params['id'],
|
24
|
+
state: parse_state(params['state']),
|
25
|
+
office: parse_office(params['id']),
|
26
|
+
district: parse_district(params['district']),
|
27
|
+
party: params['party'],
|
28
|
+
fec_uri: params['fec_uri'],
|
29
|
+
committee_id: parse_committee(params['committee']),
|
30
|
+
mailing_city: params['mailing_city'],
|
31
|
+
mailing_address: params['mailing_address'],
|
32
|
+
mailing_state: params['mailing_state'],
|
33
|
+
mailing_zip: params['mailing_zip'],
|
34
|
+
total_receipts: params['total_receipts'].to_f,
|
35
|
+
total_contributions: params['total_contributions'].to_f,
|
36
|
+
total_from_individuals: params['total_from_individuals'].to_f,
|
37
|
+
total_from_pacs: params['total_from_pacs'].to_f,
|
38
|
+
candidate_loans: params['candidate_loans'].to_f,
|
39
|
+
total_disbursements: params['total_disbursements'].to_f,
|
40
|
+
total_refunds: params['total_refunds'].to_f,
|
41
|
+
debts_owed: params['debts_owed'].to_f,
|
42
|
+
begin_cash: params['begin_cash'].to_f,
|
43
|
+
end_cash: params['end_cash'].to_f,
|
44
|
+
status: params['status'],
|
45
|
+
date_coverage_from: params['date_coverage_from'],
|
46
|
+
date_coverage_to: params['date_coverage_to']
|
47
47
|
end
|
48
48
|
|
49
49
|
def self.create_from_search_results(params={})
|
50
|
-
self.new :
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
50
|
+
self.new name: params['candidate']['name'],
|
51
|
+
id: params['candidate']['id'],
|
52
|
+
state: params['candidate']['id'][2..3],
|
53
|
+
office: parse_office(params['candidate']['id'][0..0]),
|
54
|
+
district: parse_district(params['district']),
|
55
|
+
party: params['candidate']['party'],
|
56
|
+
committee_id: parse_committee(params['committee'])
|
58
57
|
end
|
59
58
|
|
60
59
|
def self.parse_state(state)
|
@@ -82,15 +81,15 @@ module CampaignCash
|
|
82
81
|
|
83
82
|
def self.categories
|
84
83
|
{
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
84
|
+
individual_total: "Contributions from individuals",
|
85
|
+
contribution_total: "Total contributions",
|
86
|
+
candidate_loan: "Loans from candidate",
|
87
|
+
receipts_total: "Total receipts",
|
88
|
+
refund_total: "Total refunds",
|
89
|
+
pac_total: "Contributions from PACs",
|
90
|
+
disbursements_total: "Total disbursements",
|
91
|
+
end_cash: "Cash on hand",
|
92
|
+
debts_owed: "Debts owed by",
|
94
93
|
}
|
95
94
|
end
|
96
95
|
|
@@ -114,7 +113,7 @@ module CampaignCash
|
|
114
113
|
# Returns an array of candidates matching a search term within a cycle. Defaults to the
|
115
114
|
# current cycle.
|
116
115
|
def self.search(name, cycle=CURRENT_CYCLE, offset=nil)
|
117
|
-
reply = invoke("#{cycle}/candidates/search", {:
|
116
|
+
reply = invoke("#{cycle}/candidates/search", {query: name, offset: offset})
|
118
117
|
results = reply['results']
|
119
118
|
results.map{|c| self.create_from_search_results(c)}
|
120
119
|
end
|
@@ -122,7 +121,7 @@ module CampaignCash
|
|
122
121
|
# Returns an array of newly created FEC candidates within a current cycle. Defaults to the
|
123
122
|
# current cycle.
|
124
123
|
def self.new_candidates(cycle=CURRENT_CYCLE, offset=nil)
|
125
|
-
reply = invoke("#{cycle}/candidates/new",{:
|
124
|
+
reply = invoke("#{cycle}/candidates/new",{offset: offset})
|
126
125
|
results = reply['results']
|
127
126
|
results.map{|c| self.create(c)}
|
128
127
|
end
|
@@ -133,9 +132,9 @@ module CampaignCash
|
|
133
132
|
path = "#{cycle}/seats/#{state}"
|
134
133
|
if chamber
|
135
134
|
path += "/#{chamber}"
|
136
|
-
|
135
|
+
path += "/#{district}" if district
|
137
136
|
end
|
138
|
-
reply = invoke(path,{:
|
137
|
+
reply = invoke(path, {offset: offset})
|
139
138
|
results = reply['results']
|
140
139
|
results.map{|c| self.create_from_search_results(c)}
|
141
140
|
end
|
@@ -2,54 +2,54 @@ module CampaignCash
|
|
2
2
|
class Committee < Base
|
3
3
|
|
4
4
|
FILING_FREQUENCY = {
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
5
|
+
A: 'Administratively Terminated',
|
6
|
+
D: 'Debt',
|
7
|
+
M: 'Monthly',
|
8
|
+
Q: 'Quarterly',
|
9
|
+
T: 'Terminated',
|
10
|
+
W: 'Waived'
|
11
11
|
}
|
12
12
|
|
13
13
|
INTEREST_GROUP = {
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
14
|
+
C: 'Corporation',
|
15
|
+
L: 'Labor Union',
|
16
|
+
M: 'Membership',
|
17
|
+
T: 'Trade Association',
|
18
|
+
V: 'Cooperative',
|
19
|
+
W: 'Corporation without Capital Stock'
|
20
20
|
}
|
21
21
|
|
22
22
|
COMMITTEE_TYPE = {
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
23
|
+
C: 'Communication Cost',
|
24
|
+
D: 'Delegate',
|
25
|
+
E: 'Electioneering Communications',
|
26
|
+
H: 'House Candidate',
|
27
|
+
I: 'Independent Expenditure (Person or Group)',
|
28
|
+
N: 'Non-Party, Non-Qualified',
|
29
|
+
P: 'Presidential Candidate',
|
30
|
+
Q: 'Qualified Non-Party',
|
31
|
+
S: 'Senate Candidate',
|
32
|
+
X: 'Non-Qualified Party',
|
33
|
+
Y: 'Qualified Party',
|
34
|
+
Z: 'National Party Non-Federal'
|
35
35
|
}
|
36
36
|
|
37
37
|
COMMITTEE_DESIGNATION = {
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
38
|
+
A: 'Authorized by a Candidate',
|
39
|
+
J: 'Joint Fundraiser',
|
40
|
+
P: 'Principal Campaign Committee',
|
41
|
+
U: 'Unauthorized',
|
42
|
+
B: 'Lobbyist/Registrant PAC',
|
43
|
+
D: 'Leadership PAC'
|
44
44
|
}
|
45
45
|
|
46
46
|
attr_reader :name, :id, :state, :district, :party, :fec_uri, :candidate,
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
47
|
+
:city, :address, :state, :zip, :relative_uri, :sponsor_name,
|
48
|
+
:total_receipts, :total_contributions, :total_from_individuals,
|
49
|
+
:total_from_pacs, :candidate_loans, :total_disbursements,
|
50
|
+
:total_refunds, :debts_owed, :begin_cash, :end_cash,
|
51
|
+
:date_coverage_to, :date_coverage_from, :other_cycles, :super_pac, :filings,
|
52
|
+
:total_candidate_contributions, :total_independent_expenditures
|
53
53
|
|
54
54
|
def initialize(params={})
|
55
55
|
params.each_pair do |k,v|
|
@@ -58,52 +58,52 @@ module CampaignCash
|
|
58
58
|
end
|
59
59
|
|
60
60
|
def self.create(params={})
|
61
|
-
self.new :
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
61
|
+
self.new name: params['name'],
|
62
|
+
id: params['id'],
|
63
|
+
state: params['state'],
|
64
|
+
party: params['party'],
|
65
|
+
fec_uri: params['fec_uri'],
|
66
|
+
city: params['city'],
|
67
|
+
address: params['address'],
|
68
|
+
zip: params['zip'],
|
69
|
+
sponsor_name: params['sponsor_name'],
|
70
|
+
leadership: params['leadership'],
|
71
|
+
super_pac: params['super_pac'],
|
72
|
+
total_receipts: params['total_receipts'].to_f,
|
73
|
+
total_contributions: params['total_contributions'].to_f,
|
74
|
+
total_from_individuals: params['total_from_individuals'].to_f,
|
75
|
+
total_from_pacs: params['total_from_pacs'].to_f,
|
76
|
+
candidate_loans: params['candidate_loans'].to_f,
|
77
|
+
total_disbursements: params['total_disbursements'].to_f,
|
78
|
+
total_candidate_contributions: params['total_candidate_contributions'].to_f,
|
79
|
+
total_independent_expenditures: params['total_independent_expenditures'].to_f,
|
80
|
+
total_refunds: params['total_refunds'].to_f,
|
81
|
+
debts_owed: params['debts_owed'].to_f,
|
82
|
+
begin_cash: params['begin_cash'].to_f,
|
83
|
+
end_cash: params['end_cash'].to_f,
|
84
|
+
date_coverage_from: date_parser(params['date_coverage_from']),
|
85
|
+
date_coverage_to: date_parser(params['date_coverage_to']),
|
86
|
+
candidate_id: parse_candidate(params['candidate']),
|
87
|
+
filing_frequency: get_frequency(params['filing_frequency']),
|
88
|
+
interest_group: get_interest_group(params['interest_group']),
|
89
|
+
committee_type: get_committee_type(params['committee_type']),
|
90
|
+
designation: get_designation(params['designation']),
|
91
|
+
other_cycles: params['other_cycles'].map{|cycle| cycle['cycle']['cycle']}
|
92
92
|
end
|
93
93
|
|
94
94
|
def self.create_from_search_results(params={})
|
95
|
-
self.new :
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
95
|
+
self.new name: params['name'],
|
96
|
+
id: params['id'],
|
97
|
+
city: params['city'],
|
98
|
+
state: params['state'],
|
99
|
+
zip: params['zip'],
|
100
|
+
district: params['district'],
|
101
|
+
party: params['party'],
|
102
|
+
candidate_id: parse_candidate(params['candidate']),
|
103
|
+
treasurer: params['treasurer'],
|
104
|
+
fec_uri: params['fec_uri'],
|
105
|
+
leadership: params['leadership'],
|
106
|
+
super_pac: params['super_pac']
|
107
107
|
end
|
108
108
|
|
109
109
|
def self.get_frequency(frequency)
|
@@ -137,7 +137,7 @@ module CampaignCash
|
|
137
137
|
end
|
138
138
|
|
139
139
|
def self.search(name, cycle=CURRENT_CYCLE, offset=nil)
|
140
|
-
reply = invoke("#{cycle}/committees/search", {:
|
140
|
+
reply = invoke("#{cycle}/committees/search", {query: name, offset: offset})
|
141
141
|
results = reply['results']
|
142
142
|
results.map{|c| create_from_search_results(c)}
|
143
143
|
end
|
@@ -149,19 +149,19 @@ module CampaignCash
|
|
149
149
|
end
|
150
150
|
|
151
151
|
def self.superpacs(cycle=CURRENT_CYCLE, offset=nil)
|
152
|
-
reply = invoke("#{cycle}/committees/superpacs",{:
|
152
|
+
reply = invoke("#{cycle}/committees/superpacs",{offset: offset})
|
153
153
|
results = reply['results']
|
154
154
|
results.map{|c| create_from_search_results(c)}
|
155
155
|
end
|
156
156
|
|
157
157
|
def filings(cycle=CURRENT_CYCLE, offset=nil)
|
158
|
-
reply = Base.invoke("#{cycle}/committees/#{id}/filings",{:
|
158
|
+
reply = Base.invoke("#{cycle}/committees/#{id}/filings",{offset: offset})
|
159
159
|
results = reply['results']
|
160
160
|
results.map{|c| Filing.create(c)}
|
161
161
|
end
|
162
162
|
|
163
163
|
def unamended_filings(cycle=CURRENT_CYCLE, offset=nil)
|
164
|
-
reply = Base.invoke("#{cycle}/committees/#{id}/filings",{:
|
164
|
+
reply = Base.invoke("#{cycle}/committees/#{id}/filings",{offset: offset})
|
165
165
|
results = reply['results'].select{|f| f['amended'] == false}
|
166
166
|
results.map{|c| Filing.create(c, name=self.name)}
|
167
167
|
end
|