campaign_cash 1.8 → 2.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +151 -11
- data/campaign_cash.gemspec +1 -1
- data/lib/campaign_cash.rb +1 -1
- data/lib/campaign_cash/base.rb +10 -0
- data/lib/campaign_cash/candidate.rb +17 -7
- data/lib/campaign_cash/committee.rb +82 -10
- data/lib/campaign_cash/contribution.rb +40 -22
- data/lib/campaign_cash/filing.rb +18 -8
- data/lib/campaign_cash/independent_expenditure.rb +16 -16
- data/lib/campaign_cash/president.rb +72 -0
- data/lib/campaign_cash/version.rb +1 -1
- data/test/campaign_cash/test_candidate.rb +1 -1
- data/test/campaign_cash/test_committee.rb +3 -3
- data/test/campaign_cash/test_independent_expenditure.rb +1 -1
- data/test/campaign_cash/test_president.rb +42 -0
- data/test/test_helper.rb +1 -1
- metadata +9 -6
data/README.rdoc
CHANGED
@@ -1,6 +1,10 @@
|
|
1
|
-
= campaign_cash
|
2
1
|
|
3
|
-
|
2
|
+
____ _ ____ _
|
3
|
+
/ ___|__ _ _ __ ___ _ __ __ _(_) __ _ _ __ / ___|__ _ ___| |__
|
4
|
+
| | / _` | '_ ` _ \| '_ \ / _` | |/ _` | '_ \ | | / _` / __| '_ \
|
5
|
+
| |__| (_| | | | | | | |_) | (_| | | (_| | | | | | |__| (_| \__ \ | | |
|
6
|
+
\____\__,_|_| |_| |_| .__/ \__,_|_|\__, |_| |_| \____\__,_|___/_| |_|
|
7
|
+
|_| |___/
|
4
8
|
|
5
9
|
== DESCRIPTION:
|
6
10
|
|
@@ -18,25 +22,161 @@ For use in a Rails 3 application, put the following in your Gemfile:
|
|
18
22
|
|
19
23
|
then issue the 'bundle install' command. Campaign Cash has been tested under Ruby 1.8.7 and 1.9.2.
|
20
24
|
|
21
|
-
==
|
25
|
+
== GETTING STARTED:
|
22
26
|
|
23
27
|
require 'rubygems'
|
24
28
|
require 'campaign_cash'
|
25
29
|
|
26
30
|
You'll want to set your API key as an environment variable in order to run the tests. Otherwise, you'll need to set it like so:
|
27
31
|
|
32
|
+
include CampaignCash
|
28
33
|
Base.api_key = YOUR_API_KEY
|
29
34
|
|
30
|
-
Currently there are methods to support retrieving candidates, committees, electronic filings, committee contributions and independent expenditures. Almost every method requires at least one parameter, the election cycle.
|
35
|
+
Currently there are methods to support retrieving candidates, presidential candidates, committees, electronic filings, committee contributions and independent expenditures. Almost every method requires at least one parameter, the election cycle.
|
31
36
|
|
32
|
-
|
33
|
-
Committee.search("Growth", 2012) # find all committees in the 2012 cycle with the word 'Growth' in the name.
|
34
|
-
Candidate.search("Udall", 2010) # find all candidates in the 2010 cycle with the name 'Udall'
|
35
|
-
Filing.today # find all the electronic filings made today.
|
36
|
-
Contribution.find("C00458588",2010,"H0NC02059") # find all contributions by the committee to the candidate in the 2010 cycle.
|
37
|
-
IndependentExpenditure.candidate("P60003654", 2012) # find independent expenditures about Newt Gingrich in the 2012 cycle.
|
37
|
+
== Candidates
|
38
38
|
|
39
|
-
|
39
|
+
Candidate objects can be created in several ways. To locate a candidate by last name, supply the name and cycle:
|
40
|
+
|
41
|
+
Candidate.search("Bass", 2012)
|
42
|
+
#=> [#<CampaignCash::Candidate:0x101bb3d00 @name="BASS, CHARLES F.", @state="NH", @party="REP", @district=2, @committee_id="C00302570", @office="house", @id="H0NH02017">, #<CampaignCash::Candidate:0x101bb2f90 @name="BASS, KAREN", @state="CA", @party="DEM", @district=33, @committee_id="C00476523", @office="house", @id="H0CA33117">]
|
43
|
+
|
44
|
+
Search returns an array of basic information about candidates, including the unique Federal Election Commission-provided identifier, which begins with an "H" for House candidates, "S" for Senate candidates and "P" for presidential candidates. The id, along with the election cycle, can be used to retrieve more information about a candidate:
|
45
|
+
|
46
|
+
Candidate.find("H0NH02017", 2012)
|
47
|
+
#=> #<CampaignCash::Candidate:0x101b9af80 @name="BASS, CHARLES F.", @state="NH", @fec_uri="http://query.nictusa.com/cgi-bin/fecimg/?H0NH02017", @total_disbursements=120650.0, @total_contributions=570853.0, @mailing_address="PO BOX 210", @begin_cash=31676.0, @party="REP", @candidate_loans=nil, @total_receipts=577512.0, @date_coverage_from="2011-01-01", @mailing_city="PETERBOROUGH", @debts_owed=nil, @district=2, @total_from_pacs=414250.0, @mailing_zip="03458", @date_coverage_to="2011-09-30", @committee_id="C00302570", @total_refunds=nil, @office="house", @total_from_individuals=156603.0, @id="H0NH02017", @mailing_state="NH", @end_cash=488538.0, @status="I">
|
48
|
+
|
49
|
+
Candidate.find returns an object containing more detailed information for a candidate, including the latest financial summary from the F.E.C. and the candidate's committee ID, which can be used to make other method calls.
|
50
|
+
|
51
|
+
Several other canned queries are available. To list the top 20 candidates in terms of one of the financial categories (available by calling Candidate.categories or listed at http://developer.nytimes.com/docs/read/campaign_finance_api#h3-candidate-leaders), supply the category and cycle:
|
52
|
+
|
53
|
+
Candidate.leaders('end-cash', 2012)
|
54
|
+
#=> [#<CampaignCash::Candidate:0x101b76b80 @name="OBAMA, BARACK", @state=nil, @fec_uri=nil, @total_disbursements=29327600.0, @total_contributions=65393200.0, @mailing_address=nil, @begin_cash=2303400.0, @party="DEM", @candidate_loans=nil, @total_receipts=nil, @date_coverage_from="2011-01-01", @mailing_city=nil, @debts_owed=1709300.0, @district=0, @total_from_pacs=nil, @mailing_zip=nil, @date_coverage_to="2011-09-30", @committee_id="C00430892", @total_refunds=944100.0, @office=nil, @total_from_individuals=65393200.0, @id=nil, @mailing_state=nil, @end_cash=61400700.0, @status="I">, #<CampaignCash::Candidate:0x101b75730 @name="SHELBY, RICHARD C", @state="AL", @fec_uri=nil, @total_disbursements=1508100.0, @total_contributions=4693320.0, @mailing_address=nil, @begin_cash=13381000.0, @party="REP", @candidate_loans=nil, @total_receipts=nil, @date_coverage_from="2009-01-01", @mailing_city=nil, @debts_owed=nil, @district=0, @total_from_pacs=1671200.0, @mailing_zip=nil, @date_coverage_to="2010-12-31", @committee_id="C00193623", @total_refunds=25800.0, @office=nil, @total_from_individuals=3022120.0, @id=nil, @mailing_state=nil, @end_cash=17156600.0, @status="I"> ...]
|
55
|
+
|
56
|
+
Please note that not all candidates file on the same schedule, so some of the "date_coverage_to" will be different for these responses. Senate candidates, in particular, often file twice a year during the odd-numbered years prior to a general election.
|
57
|
+
|
58
|
+
To retrieve an array of the 20 newest candidates (the F.E.C.'s data is updated every Monday), use the new_candidates class method:
|
59
|
+
|
60
|
+
Candidate.new_candidates
|
61
|
+
#=> [#<CampaignCash::Candidate:0x101b11d20 @name="ANDERSON, JASON EDWARD", @state="AL", @fec_uri="http://query.nictusa.com/cgi-bin/fecimg/?H2AL05086", @total_disbursements=nil, @total_contributions=nil, @mailing_address=nil, @begin_cash=nil, @party="REP", @candidate_loans=nil, @total_receipts=nil, @date_coverage_from=nil, @mailing_city="HAZEL GREEN", @debts_owed=nil, @district=5, @total_from_pacs=nil, @mailing_zip="35750", @date_coverage_to=nil, @committee_id="C00508374", @total_refunds=nil, @office="house", @total_from_individuals=nil, @id="H2AL05086", @mailing_state="AL", @end_cash=nil, @status=nil>, #<CampaignCash::Candidate:0x101b10420 @name="NORRIS, PHILLIP DWIGHT", @state="AL", @fec_uri="http://query.nictusa.com/cgi-bin/fecimg/?H2AL07165", @total_disbursements=nil, @total_contributions=nil, @mailing_address=nil, @begin_cash=nil, @party="REP", @candidate_loans=nil, @total_receipts=nil, @date_coverage_from=nil, @mailing_city="HOOVER", @debts_owed=nil, @district=7, @total_from_pacs=nil, @mailing_zip="35216", @date_coverage_to=nil, @committee_id="C00508382", @total_refunds=nil, @office="house", @total_from_individuals=nil, @id="H2AL07165", @mailing_state="AL", @end_cash=nil, @status=nil>,
|
62
|
+
|
63
|
+
To retrieve an array of candidates for a particular seat, supply a state abbreviation, chamber ('house' or 'senate'), district (an integer or nil) and cycle. For example, the following asks for candidates for Maryland's 6th Congressional District in 2012:
|
64
|
+
|
65
|
+
Candidate.state_chamber('MD', 'house', 6, 2012)
|
66
|
+
#=> [#<CampaignCash::Candidate:0x101abea58 @name="CLARK, CASEY", @state="MD", @party="DEM", @district=0, @committee_id="C00460436", @office="house", @id="H0MD06173">, #<CampaignCash::Candidate:0x101abe2b0 @name="TAYLOR, STEVEN MICHAEL", @state="MD", @party="REP", @district=0, @committee_id="C00481788", @office="house", @id="H0MD06181">, #<CampaignCash::Candidate:0x101abdb08 @name="BARTLETT, ROSCOE G. REP.", @state="MD", @party="REP", @district=0, @committee_id="C00255190", @office="house", @id="H2MD06054">,...]
|
67
|
+
|
68
|
+
== President
|
69
|
+
|
70
|
+
Presidential candidate objects are like regular Candidates, except that they have additional financial attributes that are calculated by The New York Times from electronic filings. There are two President methods. To retrieve a listing of all presidential candidates being tracked by The Times:
|
71
|
+
|
72
|
+
President.summary
|
73
|
+
#=> [#<CampaignCash::President:0x101be6c78 @name="Barack Obama", @party="D", @total_receipts="99597680.72", @date_coverage_from="2011-01-01", @date_coverage_to="2011-09-30", @committee_id="C00431445", @id="P80003338", @end_cash="61403710.55", @total_disbursements="106877585.73">, #<CampaignCash::President:0x101be6688 @name="Mitt Romney", @party="R", @total_receipts="32605827.32", @date_coverage_from="2010-10-01", @date_coverage_to="2011-09-30", @committee_id="C00431171", @id="P80003353", @end_cash="14656965.83", @total_disbursements="17953283.44">,...]
|
74
|
+
|
75
|
+
To retrieve detailed information for a single presidential candidate, pass the appropriate committee_id and cycle:
|
76
|
+
|
77
|
+
President.detail('C00431171', 2012)
|
78
|
+
#=> [#<CampaignCash::President:0x101bd3d58 @name="Romney, Mitt", @party="R", @contributions_less_than_200="3393540.5", @total_receipts="32605827.32", @date_coverage_from="2010-10-01", @net_candidate_contributions="0.0", @contributions_1500_2499="1566753.77", @federal_funds="0.0", @date_coverage_to="2011-09-30", @net_party_contributions="0.0", @committee_id="C00431171", @total_refunds="270101.47", @contributions_500_1499="5965455.03", @net_general_contributions="0.0", @id="P80003353", @end_cash="14656965.83", @net_pac_contributions="177301.13", @total_disbursements="17953283.44", @contributions_200_499="977647.0", @total_contributions="32482490.51", @net_primary_contributions="14656965.83", @net_individual_contributions="32035087.91", @contributions_max="19930000.0">]
|
79
|
+
|
80
|
+
Among the calculated attributes are totals for five ranges of contribution size (the maximum individual contribution for the 2012 cycle is $2,500 per person, per election, while in 2008 it was $2,300).
|
81
|
+
|
82
|
+
== Committees
|
83
|
+
|
84
|
+
Committee objects have information about F.E.C.-registered committees that may or may not be affiliated to a candidate. If a committee is associated with a candidate, it will have values for the district, party and candidate_id attributes. Party committees should also have the party attribute set. If it is defined as a leadership committee, a committee's leadership attribute will be set to True; a similar attribute, super_pac, is set to True if the committee is registered with the F.E.C. as a "Super PAC" able to raise unlimited amounts for independent expenditures.
|
85
|
+
|
86
|
+
Searching for a committee currently executes a "begins with" query, so to find all committees in the 2012 cycle that start with the word 'Growth':
|
87
|
+
|
88
|
+
Committee.search("Growth", 2012)
|
89
|
+
#=> [#<CampaignCash::Committee:0x101bebb38 @name="GROWTH AND PROSPERITY POLITICAL ACTION COMMITTEE", @state="AL", @party="", @super_pac=nil, @leadership=true, @district=nil, @city="BIRMINGHAM", @id="C00388793", @treasurer="DOBBS, JOEY", @fec_uri="http://query.nictusa.com/cgi-bin/dcdev/forms/C00388793/", @zip="35222", @candidate_id=nil>, #<CampaignCash::Committee:0x101beb368 @name="GROWTH ENERGY PAC", @state="DC", @party="", @super_pac=nil, @leadership=false, @district=nil, @city="WASHINGTON", @id="C00475665", @treasurer="BUTTERFIELD, BEN", @fec_uri="http://query.nictusa.com/cgi-bin/dcdev/forms/C00475665/", @zip="20002", @candidate_id=nil>]
|
90
|
+
|
91
|
+
As with Candidate.search, the results of Committee.search return a subset of all Committee attributes. The full Committee object includes the most recent financial summary data available, plus the other election cycles that the committee is registered in dating back to 1980. Some committees have a sponsor, which could be a corporation, association or candidate. Also included are several F.E.C.-defined categories, including filing frequency, committee designation (who controls it, essentially), committee type (House, Senate, etc.) and interest group category (corporation, labor union, etc.). These last four attributes are not universally present in the data, which is why a Committee object has an independent leadership attribute even though the designation should indicate if it is a leadership committee. More details these codes is available from the F.E.C.: ftp://ftp.fec.gov/FEC/cm_dictionary.txt.
|
92
|
+
|
93
|
+
To fetch the details for a single committee in a cycle:
|
94
|
+
|
95
|
+
Committee.find("C00326389", 2012)
|
96
|
+
#=> #<CampaignCash::Committee:0x101bd4118 @name="SNAKE RIVER SUGAR COMPANY POLITICAL ACTION COMMITTEE", @state="ID", @party="", @candidate_loans=nil, @total_receipts=30363.3, @date_coverage_from="2011-01-01", @designation="Unauthorized", @other_cycles=[2010, 2008, 2006, 2004, 2002, 2000, 1998], @city="BOISE", @debts_owed=nil, @total_from_pacs=nil, @date_coverage_to="2011-11-30", @filing_frequency="Monthly", @sponsor_name=nil, @total_refunds=nil, @total_from_individuals=30363.3, @id="C00326389", @leadership=false, @zip="83709", @end_cash=16845.2, @committee_type=nil, @fec_uri="http://query.nictusa.com/cgi-bin/dcdev/forms/C00326389/", @total_disbursements=46500.0, @total_contributions=30363.3, @interest_group="Cooperative", @super_pac=false, @address="1951 SOUTH SATURN WAY", @begin_cash=32981.9, @candidate_id=nil>
|
97
|
+
|
98
|
+
Individual Committee objects can retrieve an array of filings they have made during a given cycle:
|
99
|
+
|
100
|
+
committee = Committee.find("C00326389", 2012)
|
101
|
+
committee.filings
|
102
|
+
#=> [#<CampaignCash::Filing:0x101bc9100 @amended_uri=nil, @paper=false, @amended=false, @committee_name=nil, @date_coverage_from=#<Date: 4911793/2,0,2299161>, @original_uri=nil, @report_title="YEAR-END", @date_coverage_to=#<Date: 4911853/2,0,2299161>, @form_type="F3", @committee=nil, @original_filing=nil, @fec_uri="http://query.nictusa.com/cgi-bin/dcdev/forms/C00326389/756540/">,...]
|
103
|
+
|
104
|
+
For more information on Filing objects, see Filings below.
|
105
|
+
|
106
|
+
To retrieve a list of the 20 most recently added committees (note that no cycle parameter is needed; this method always uses the most recent cycle):
|
107
|
+
|
108
|
+
Committee.latest
|
109
|
+
#=> [#<CampaignCash::Committee:0x101be6020 @name="AMERICA'S IMPACT POLITICAL FUND", @state="DC", @party="", @super_pac=false, @leadership=false, @district=nil, @city="WASHINGTON", @id="C00508366", @treasurer="BENJAMIN GOLDSMITH", @fec_uri="http://query.nictusa.com/cgi-bin/dcdev/forms/C00508366/", @zip="20005", @candidate_id=nil>, #<CampaignCash::Committee:0x101be55a8 @name="JASON ANDERSON FOR CONGRESS", @state="AL", @party="REP", @super_pac=false, @leadership=false, @district=nil, @city="HAZEL GREEN", @id="C00508374", @treasurer="CHRISTOPHER MARK ANDREWS", @fec_uri="http://query.nictusa.com/cgi-bin/dcdev/forms/C00508374/", @zip="35750", @candidate_id="H2AL05086">, ...]
|
110
|
+
|
111
|
+
"Super PACs" are independent-expenditure only committees formed in the wake of the 2010 Citizens United decision by the U.S. Supreme Court. They can raise money in unlimited donations from individuals, corporations, labor unions and other sources, but must register their intent to do so with the F.E.C. To retrieve the 20 most recent "Super PAC" registrations:
|
112
|
+
|
113
|
+
Committee.superpacs
|
114
|
+
#=> [#<CampaignCash::Committee:0x101bcfe10 @name="HUMAN RIGHTS CAMPAIGN EQUALITY VOTES", @state="DC", @party="", @designation="Unauthorized", @city="WASHINGTON", @treasurer="JAMES M RINEFIERD", @district=nil, @filing_frequency="Quarterly", @id="C00508440", @leadership=false, @zip="20036", @committee_type=nil, @fec_uri="http://query.nictusa.com/cgi-bin/dcdev/forms/C00508440/", @interest_group=nil, @super_pac=true, @candidate_id=nil>, #<CampaignCash::Committee:0x101bcf348 @name="LEADERS FOR FAMILIES SUPER PAC INC", @state="IN", @party="", @designation="Unauthorized", @city="TERRE HAUTE", @treasurer="CHARLES HURLEY", @district=nil, @filing_frequency="Quarterly", @id="C00508317", @leadership=false, @zip="47807", @committee_type=nil, @fec_uri="http://query.nictusa.com/cgi-bin/dcdev/forms/C00508317/", @interest_group=nil, @super_pac=true, @candidate_id=nil>,...]
|
115
|
+
|
116
|
+
Committees make contributions to candidates, among other activities. Given a committee, cycle and recipient candidate, to see any contributions from the committee to the candidate:
|
117
|
+
|
118
|
+
Contribution.find('C00388793',2012,'H0NY19139')
|
119
|
+
#=> #<CampaignCash::Contribution:0x101b6af60 @results=[#<OpenStruct party="REP", date=#<Date: 4911301/2,0,2299161>, primary_general="General", state="NY", amount=5000.0, image_uri="http://images.nictusa.com/cgi-bin/fecimg/?11932087309", name="HAYWORTH, NAN", district="19", candidate="H0NY19139">, #<OpenStruct party="REP", date=#<Date: 4911289/2,0,2299161>, primary_general="Primary", state="NY", amount=5000.0, image_uri="http://images.nictusa.com/cgi-bin/fecimg/?11932087308", name="HAYWORTH, NAN", district="19", candidate="H0NY19139">], @cycle=2012, @total_amount=10000.0, @committee="C00388793">
|
120
|
+
|
121
|
+
Removing the candidate's id from the previous method will yield an array of all contributions to candidates made by the committee during that cycle:
|
122
|
+
|
123
|
+
Contribution.find('C00388793',2012)
|
124
|
+
#=> #<CampaignCash::Contribution:0x101b8c098 @results=[#<OpenStruct party="REP", date=#<Date: 4911479/2,0,2299161>, primary_general="Primary", state="IL", amount=2000.0, image_uri="http://images.nictusa.com/cgi-bin/fecimg/?11932087311", name="KINZINGER, ADAM", district="11", candidate=nil>, #<OpenStruct party="REP", date=#<Date: 4911471/2,0,2299161>, primary_general="Primary", state="MI", amount=2500.0, image_uri="http://images.nictusa.com/cgi-bin/fecimg/?11932087316", name="WALBERG, TIMOTHY L. HON.", district="07", candidate=nil>,...]
|
125
|
+
|
126
|
+
Both of the contribution responses have a results method that contains one or more contributions, assembled using Ruby's OpenStruct library. The image_uri attribute is a link to the page of the filing on fec.gov that contains that transaction.
|
127
|
+
|
128
|
+
== Filings
|
129
|
+
|
130
|
+
Committees file reports with the F.E.C. detailing their fundraising and expenditures, as well as administrative matters such as a change of address or in committee status. Campaign Cash provides access to both electronic filings, the method used by most committees, and images of paper filings, which are submitted by Senate candidates and two Senate party committees. To retrieve the most recent 20 filings from today:
|
131
|
+
|
132
|
+
Filing.today
|
133
|
+
#=> [#<CampaignCash::Filing:0x101be03a0 @original_uri="http://query.nictusa.com/cgi-bin/dcdev/forms/C00016899/741687/", @amended_uri=nil, @amended=false, @committee_name="OHIO DEMOCRATIC PARTY", @date_coverage_from=#<Date: 4911487/2,0,2299161>, @original_filing=741687, @report_title="AUG MONTHLY", @date_coverage_to=#<Date: 4911547/2,0,2299161>, @form_type="F3", @committee="C00016899", @paper=nil, @fec_uri="http://query.nictusa.com/cgi-bin/dcdev/forms/C00016899/756832/">, #<CampaignCash::Filing:0x101bd9eb0 @original_uri=nil, @amended_uri=nil, @amended=false, @committee_name="CITIZENS FOR PAUL FEINER", @date_coverage_from=#<Date: 4911671/2,0,2299161>, @original_filing=nil, @report_title="YEAR-END", @date_coverage_to=#<Date: 4911853/2,0,2299161>, @form_type="F3", @committee="C00332411", @paper=nil, @fec_uri="http://query.nictusa.com/cgi-bin/dcdev/forms/C00332411/756831/">,...]
|
134
|
+
|
135
|
+
Each filing object contains several attributes that help place it into context. If the filing is amended by another filing, amended will be True and an amended_uri, the link to the updated filing, will appear. If a filing was submitted on paper, paper will be True. To retrieve filings from a specific date:
|
136
|
+
|
137
|
+
Filing.date(2012,1,9) # Jan. 9, 2012
|
138
|
+
#=> [#<CampaignCash::Filing:0x101aa5e68 @original_uri=nil, @amended_uri=nil, @amended=false, @committee_name="HOYT HILSMAN FOR CONGRESS", @date_coverage_from=#<Date: 4911671/2,0,2299161>, @original_filing=nil, @report_title="YEAR-END", @date_coverage_to=#<Date: 4911853/2,0,2299161>, @form_type="F3", @committee="C00435966", @paper=nil, @fec_uri="http://query.nictusa.com/cgi-bin/dcdev/forms/C00435966/756828/">, #<CampaignCash::Filing:0x101a9f978 @original_uri=nil, @amended_uri=nil, @amended=false, @committee_name="MARY PALLANT FOR CONGRESS", @date_coverage_from=#<Date: 4911671/2,0,2299161>, @original_filing=nil, @report_title="YEAR-END", @date_coverage_to=#<Date: 4911853/2,0,2299161>, @form_type="F3", @committee="C00415943", @paper=nil, @fec_uri="http://query.nictusa.com/cgi-bin/dcdev/forms/C00415943/756827/">,...]
|
139
|
+
|
140
|
+
To retrieve a list of Filing form types, which explain a little more about the form_type attributes on Filing objects:
|
141
|
+
|
142
|
+
Filing.form_types
|
143
|
+
#=> [#<OpenStruct name="STATEMENT OF ORGANIZATION", id="F1">, #<OpenStruct name="24-HOUR NOTICE OF EXPENDITURES FROM CANDIDATE PERSONAL FUNDS", id="F10">, #<OpenStruct name="24-HOUR NOTICE OF EXPENDITURES FROM OPPONENT'S PERSONAL FUNDS", id="F11">, #<OpenStruct name="24-HOUR NOTICE OF SUSPENSION OF INDIVIDUAL CONTRIBUTION LIMITS", id="F12">,...]
|
144
|
+
|
145
|
+
The form type IDs can be used to retrieve the most recent filings of that type:
|
146
|
+
|
147
|
+
Filing.by_type(2012,'F1') # Latest Statements of Organization
|
148
|
+
#=> [#<CampaignCash::Filing:0x101c5fee8 @original_uri=nil, @amended_uri=nil, @amended=false, @committee_name="DUNCAN D. HUNTER FOR CONGRESS", @date_coverage_from=nil, @original_filing=nil, @report_title="STATEMENT OF ORGANIZATION", @date_coverage_to=nil, @form_type=nil, @committee="C00433524", @paper=nil, @fec_uri="http://query.nictusa.com/cgi-bin/dcdev/forms/C00433524/756824/">, #<CampaignCash::Filing:0x101c5f448 @original_uri=nil, @amended_uri=nil, @amended=false, @committee_name="THE BILL KEATING COMMITTEE", @date_coverage_from=nil, @original_filing=nil, @report_title="STATEMENT OF ORGANIZATION", @date_coverage_to=nil, @form_type=nil, @committee="C00479063", @paper=nil, @fec_uri="http://query.nictusa.com/cgi-bin/dcdev/forms/C00479063/756813/">,...]
|
149
|
+
|
150
|
+
All Filing methods, with the exception of Filing.form_types, support the optional offset parameter, using multiples of 20.
|
151
|
+
|
152
|
+
== Independent Expenditures
|
153
|
+
|
154
|
+
Committees can spend money to elect or defeat candidates independently of their campaigns; such activities are called independent expenditures and are {specifically reported to the F.E.C.}[http://www.fec.gov/finance/disclosure/ie_reports.shtml]. To retrieve the 20 most recent IE transactions:
|
155
|
+
|
156
|
+
IndependentExpenditure.latest
|
157
|
+
#=> [#<CampaignCash::IndependentExpenditure:0x101bd3920 @date_received=#<Date: 4911871/2,0,2299161>, @amount=200.0, @purpose="Online Advertising - 01/08/2012", @committee="C00503789", @district=0, @date=#<Date: 4911869/2,0,2299161>, @candidate="P20002721", @support_or_oppose="O", @committee_name="DGA ACTION", @office="President", @payee="Facebook", @state="", @fec_uri="http://images.nictusa.com/cgi-bin/fecimg/?12950041238">,...]
|
158
|
+
|
159
|
+
The support_or_oppose attribute contains either an "S" (for "Support") or "O" (for "Oppose"), indicating whether the expenditure is in favor or against the candidate identified. IEs should contain both the candidate mentioned in the expenditure and the office (state and district) that person is running for, but in practice some filings either omit this information or contain an incorrect candidate ID (usually a previous one for the correct candidate). The API does not guarantee that such mistakes will be corrected when you retrieve records. To retrieve recent IEs about a specific candidate, use that candidate's ID:
|
160
|
+
|
161
|
+
IndependentExpenditure.candidate("P60003654", 2012) # find independent expenditures about Newt Gingrich.
|
162
|
+
#=> [#<CampaignCash::IndependentExpenditure:0x101bd8470 @date_received=#<Date: 4911865/2,0,2299161>, @amount=89961.8, @purpose="Direct Mail", @committee="C00490045", @district=0, @committee_name="RESTORE OUR FUTURE, INC.", @date=#<Date: 4911861/2,0,2299161>, @candidate="P60003654", @support_or_oppose="O", @office="President", @payee="Arena Communications", @state="FL", @fec_uri="http://images.nictusa.com/cgi-bin/fecimg/?12950036002">, #<CampaignCash::IndependentExpenditure:0x101bd1c38 @date_received=#<Date: 4911861/2,0,2299161>, @amount=108982.0, @purpose="National Email Communication and Production", @committee="C00507525", @district=0, @committee_name="WINNING OUR FUTURE", @date=#<Date: 4911859/2,0,2299161>, @candidate="P60003654", @support_or_oppose="S", @office="President", @payee="Marketel Media, Inc.", @state="", @fec_uri="http://images.nictusa.com/cgi-bin/fecimg/?12970039675">,...]
|
163
|
+
|
164
|
+
To retrieve IEs by date, use a string date in MM/DD/YYYY format:
|
165
|
+
|
166
|
+
IndependentExpenditure.date('12/28/2011')
|
167
|
+
#=> #<CampaignCash::IndependentExpenditure:0x101a41968 @date_received=#<Date: 4911849/2,0,2299161>, @amount=19210.0, @purpose="TV Ad", @committee="C00508317", @district=0, @date=#<Date: 4911847/2,0,2299161>, @candidate="P20002721", @support_or_oppose="S", @committee_name="Leaders for Families Super PAC, Inc.", @office="President", @payee="NCC Media", @state="", @fec_uri="http://images.nictusa.com/cgi-bin/fecimg/?11953345841">, #<CampaignCash::IndependentExpenditure:0x101a3b130 @date_received=#<Date: 4911849/2,0,2299161>, @amount=10450.0, @purpose="TV Ad", @committee="C00508317", @district=0, @date=#<Date: 4911847/2,0,2299161>, @candidate="P20002721", @support_or_oppose="S", @committee_name="Leaders for Families Super PAC, Inc.", @office="President", @payee="WHO", @state="", @fec_uri="http://images.nictusa.com/cgi-bin/fecimg/?11953345842">,...]
|
168
|
+
|
169
|
+
Another way to fetch IEs is by the committee that paid for them, using the committee ID:
|
170
|
+
|
171
|
+
IndependentExpenditure.committee('C00508317', 2012)
|
172
|
+
#=> [#<CampaignCash::IndependentExpenditure:0x1019c5638 @date_received=#<Date: 4911865/2,0,2299161>, @amount=4235.0, @purpose="Radio Ad Buy", @committee="C00508317", @district=0, @date=#<Date: 4911865/2,0,2299161>, @candidate="P20002721", @support_or_oppose="S", @committee_name="Leaders for Families Super PAC, Inc.", @office="President", @payee="WGIR-FM & WQSO-FM", @state="NH", @fec_uri="http://images.nictusa.com/cgi-bin/fecimg/?12950035907">,...]
|
173
|
+
|
174
|
+
There's also the option to retrieve the 20 most recent IEs for the presidential race:
|
175
|
+
|
176
|
+
IndependentExpenditure.president
|
177
|
+
#=> [#<CampaignCash::IndependentExpenditure:0x10192a728 @date_received=#<Date: 4911855/2,0,2299161>, @amount=350.0, @purpose="Font Purchase", @committee="C00508002", @district=0, @date=#<Date: 4911915/2,0,2299161>, @candidate="", @support_or_oppose="S", @committee_name="ENDORSE LIBERTY INC", @office="President", @payee="Commercial Type", @state="", @fec_uri="http://images.nictusa.com/cgi-bin/fecimg/?12970010100">,...]
|
178
|
+
|
179
|
+
The IE responses also accept an optional offset argument, using multiples of 20.
|
40
180
|
|
41
181
|
== Note on Patches/Pull Requests
|
42
182
|
|
data/campaign_cash.gemspec
CHANGED
@@ -9,7 +9,7 @@ Gem::Specification.new do |s|
|
|
9
9
|
s.authors = ['Derek Willis']
|
10
10
|
s.email = ['dwillis@nytimes.com']
|
11
11
|
s.homepage = "http://rubygems.org/gems/campaign_cash"
|
12
|
-
s.description = "A
|
12
|
+
s.description = "A client for The New York Times Campaign Finance API"
|
13
13
|
s.summary = "Following the money."
|
14
14
|
|
15
15
|
s.required_rubygems_version = ">= 1.3.6"
|
data/lib/campaign_cash.rb
CHANGED
data/lib/campaign_cash/base.rb
CHANGED
@@ -45,6 +45,16 @@ module CampaignCash
|
|
45
45
|
date ? Date.strptime(date, '%Y-%m-%d') : nil
|
46
46
|
end
|
47
47
|
|
48
|
+
def parse_candidate(candidate)
|
49
|
+
return nil if candidate.nil?
|
50
|
+
candidate.split('/').last.split('.').first
|
51
|
+
end
|
52
|
+
|
53
|
+
def parse_committee(committee)
|
54
|
+
return nil if committee.nil?
|
55
|
+
committee.split('/').last.split('.').first
|
56
|
+
end
|
57
|
+
|
48
58
|
# Returns the election cycle (even-numbered) from a date.
|
49
59
|
def cycle_from_date(date=Date.today)
|
50
60
|
date.year.even? ? date.year : date.year+1
|
@@ -26,7 +26,7 @@ module CampaignCash
|
|
26
26
|
:district => parse_district(params['district']),
|
27
27
|
:party => params['party'],
|
28
28
|
:fec_uri => params['fec_uri'],
|
29
|
-
:committee_id =>
|
29
|
+
:committee_id => parse_committee(params['committee']),
|
30
30
|
:mailing_city => params['mailing_city'],
|
31
31
|
:mailing_address => params['mailing_address'],
|
32
32
|
:mailing_state => params['mailing_state'],
|
@@ -53,7 +53,7 @@ module CampaignCash
|
|
53
53
|
:office => parse_office(params['candidate']['id'][0..0]),
|
54
54
|
:district => parse_district(params['district']),
|
55
55
|
:party => params['candidate']['party'],
|
56
|
-
:
|
56
|
+
:committee => parse_committee(params['committee'])
|
57
57
|
|
58
58
|
end
|
59
59
|
|
@@ -61,10 +61,6 @@ module CampaignCash
|
|
61
61
|
state.split('/').last[0..1] if state
|
62
62
|
end
|
63
63
|
|
64
|
-
def self.parse_committee_id(committee)
|
65
|
-
committee.nil? ? nil : committee.split('/').last[0..8]
|
66
|
-
end
|
67
|
-
|
68
64
|
def self.parse_office(id)
|
69
65
|
return nil unless id
|
70
66
|
if id[0..0] == "H"
|
@@ -84,6 +80,20 @@ module CampaignCash
|
|
84
80
|
end
|
85
81
|
end
|
86
82
|
|
83
|
+
def self.categories
|
84
|
+
{
|
85
|
+
"individual_total" => "Contributions from individuals",
|
86
|
+
"contribution_total" => "Total contributions",
|
87
|
+
"candidate_loan" => "Loans from candidate",
|
88
|
+
"receipts_total" => "Total receipts",
|
89
|
+
"refund_total" => "Total refunds",
|
90
|
+
"pac_total" => "Contributions from PACs",
|
91
|
+
"disbursements_total" => "Total disbursements",
|
92
|
+
"end_cash" => "Cash on hand",
|
93
|
+
"debts_owed" => "Debts owed by",
|
94
|
+
}
|
95
|
+
end
|
96
|
+
|
87
97
|
# Retrieve a candidate object via its FEC candidate id within a cycle.
|
88
98
|
# Defaults to the current cycle.
|
89
99
|
def self.find(fecid, cycle=CURRENT_CYCLE)
|
@@ -113,7 +123,7 @@ module CampaignCash
|
|
113
123
|
# current cycle.
|
114
124
|
def self.new_candidates(cycle=CURRENT_CYCLE)
|
115
125
|
reply = invoke("#{cycle}/candidates/new",{})
|
116
|
-
results = reply['results']
|
126
|
+
results = reply['results']
|
117
127
|
results.map{|c| self.create(c)}
|
118
128
|
end
|
119
129
|
|
@@ -1,12 +1,54 @@
|
|
1
1
|
module CampaignCash
|
2
2
|
class Committee < Base
|
3
3
|
|
4
|
+
FILING_FREQUENCY = {
|
5
|
+
'A' => 'Administratively Terminated',
|
6
|
+
'D' => 'Debt',
|
7
|
+
'M' => 'Monthly',
|
8
|
+
'Q' => 'Quarterly',
|
9
|
+
'T' => 'Terminated',
|
10
|
+
'W' => 'Waived'
|
11
|
+
}
|
12
|
+
|
13
|
+
INTEREST_GROUP = {
|
14
|
+
'C' => 'Corporation',
|
15
|
+
'L' => 'Labor Union',
|
16
|
+
'M' => 'Membership',
|
17
|
+
'T' => 'Trade Association',
|
18
|
+
'V' => 'Cooperative',
|
19
|
+
'W' => 'Corporation without Capital Stock'
|
20
|
+
}
|
21
|
+
|
22
|
+
COMMITTEE_TYPE = {
|
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
|
+
}
|
36
|
+
|
37
|
+
COMMITTEE_DESIGNATION = {
|
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
|
+
}
|
45
|
+
|
4
46
|
attr_reader :name, :id, :state, :district, :party, :fec_uri, :candidate,
|
5
47
|
:city, :address, :state, :zip, :relative_uri, :sponsor_name,
|
6
48
|
:total_receipts, :total_contributions, :total_from_individuals,
|
7
49
|
:total_from_pacs, :candidate_loans, :total_disbursements,
|
8
50
|
:total_refunds, :debts_owed, :begin_cash, :end_cash,
|
9
|
-
:date_coverage_to, :date_coverage_from, :other_cycles, :super_pac
|
51
|
+
:date_coverage_to, :date_coverage_from, :other_cycles, :super_pac, :filings
|
10
52
|
|
11
53
|
def initialize(params={})
|
12
54
|
params.each_pair do |k,v|
|
@@ -23,6 +65,9 @@ module CampaignCash
|
|
23
65
|
:city => params['city'],
|
24
66
|
:address => params['address'],
|
25
67
|
:zip => params['zip'],
|
68
|
+
:sponsor_name => params['sponsor_name'],
|
69
|
+
:leadership => params['leadership'],
|
70
|
+
:super_pac => params['super_pac'],
|
26
71
|
:total_receipts => params['total_receipts'],
|
27
72
|
:total_contributions => params['total_contributions'],
|
28
73
|
:total_from_individuals => params['total_from_individuals'],
|
@@ -36,6 +81,10 @@ module CampaignCash
|
|
36
81
|
:date_coverage_from => params['date_coverage_from'],
|
37
82
|
:date_coverage_to => params['date_coverage_to'],
|
38
83
|
:candidate_id => parse_candidate(params['candidate']),
|
84
|
+
:filing_frequency => get_frequency(params['filing_frequency']),
|
85
|
+
:interest_group => get_interest_group(params['interest_group']),
|
86
|
+
:committee_type => get_committee_type(params['get_committee_type']),
|
87
|
+
:designation => get_designation(params['designation']),
|
39
88
|
:other_cycles => params['other_cycles'].map{|cycle| cycle['cycle']['fec_committee']['cycle']}
|
40
89
|
end
|
41
90
|
|
@@ -47,18 +96,35 @@ module CampaignCash
|
|
47
96
|
:zip => params['zip'],
|
48
97
|
:district => params['district'],
|
49
98
|
:party => params['party'],
|
50
|
-
:relative_uri => params['relative_uri'],
|
51
99
|
:candidate_id => parse_candidate(params['candidate']),
|
52
100
|
:treasurer => params['treasurer'],
|
53
101
|
:fec_uri => params['fec_uri'],
|
54
|
-
:
|
55
|
-
:
|
56
|
-
|
102
|
+
:leadership => params['leadership'],
|
103
|
+
:super_pac => params['super_pac']
|
57
104
|
end
|
58
105
|
|
59
|
-
def self.
|
60
|
-
|
61
|
-
|
106
|
+
def self.get_frequency(frequency)
|
107
|
+
if frequency
|
108
|
+
FILING_FREQUENCY[frequency.strip] unless frequency.empty?
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
def self.get_interest_group(interest_group)
|
113
|
+
if interest_group
|
114
|
+
INTEREST_GROUP[interest_group.strip] unless interest_group.empty?
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
def self.get_committee_type(committee_type)
|
119
|
+
if committee_type
|
120
|
+
COMMITTEE_TYPE[committee_type.strip] unless committee_type.empty?
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
def self.get_designation(designation)
|
125
|
+
if designation
|
126
|
+
COMMITTEE_DESIGNATION[designation.strip] unless designation.empty?
|
127
|
+
end
|
62
128
|
end
|
63
129
|
|
64
130
|
def self.find(fecid, cycle=CURRENT_CYCLE)
|
@@ -73,10 +139,10 @@ module CampaignCash
|
|
73
139
|
results.map{|c| create_from_search_results(c)}
|
74
140
|
end
|
75
141
|
|
76
|
-
def self.
|
142
|
+
def self.latest(cycle=CURRENT_CYCLE)
|
77
143
|
reply = invoke("#{cycle}/committees/new",{})
|
78
144
|
results = reply['results']
|
79
|
-
results.map{|c|
|
145
|
+
results.map{|c| create_from_search_results(c)}
|
80
146
|
end
|
81
147
|
|
82
148
|
def self.superpacs(cycle=CURRENT_CYCLE, offset=0)
|
@@ -85,5 +151,11 @@ module CampaignCash
|
|
85
151
|
results.map{|c| create_from_search_results(c)}
|
86
152
|
end
|
87
153
|
|
154
|
+
def filings(cycle=CURRENT_CYCLE, offset=0)
|
155
|
+
reply = Base.invoke("#{cycle}/committees/#{id}/filings",{:offset => offset})
|
156
|
+
results = reply['results']
|
157
|
+
results.map{|c| Filing.create(c)}
|
158
|
+
end
|
159
|
+
|
88
160
|
end
|
89
161
|
end
|
@@ -9,32 +9,50 @@ module CampaignCash
|
|
9
9
|
end
|
10
10
|
end
|
11
11
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
12
|
+
def self.to_candidate(params={})
|
13
|
+
self.new :committee => parse_committee(params['committee']),
|
14
|
+
:cycle => params['cycle'],
|
15
|
+
:total_amount => params['total_amount'],
|
16
|
+
:results => params['results'].map{|c| OpenStruct.new({
|
17
|
+
:candidate => parse_candidate(params['candidate_uri']),
|
18
18
|
:date => date_parser(c['date']),
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
19
|
+
:primary_general => c['primary_general'],
|
20
|
+
:amount => c['amount'],
|
21
|
+
:state => c['state'],
|
22
|
+
:name => c['name'],
|
23
|
+
:image_uri => c['image_uri'],
|
24
|
+
:party => c['party'],
|
25
|
+
:district => c['district']})}
|
26
|
+
|
27
|
+
end
|
28
|
+
|
29
|
+
def self.all_candidates(params={})
|
30
|
+
self.new :committee => parse_committee(params['committee']),
|
31
|
+
:cycle => params['cycle'],
|
32
|
+
:total_amount => params['total_amount'],
|
33
|
+
:total_results => params['total_results'],
|
34
|
+
:results => params['results'].map{|c| OpenStruct.new({
|
35
|
+
:date => date_parser(c['date']),
|
36
|
+
:candidate => parse_candidate(c['candidate_uri']),
|
37
|
+
:primary_general => c['primary_general'],
|
38
|
+
:amount => c['amount'],
|
39
|
+
:state => c['state'],
|
40
|
+
:name => c['name'],
|
41
|
+
:image_uri => c['image_uri'],
|
42
|
+
:party => c['party'],
|
43
|
+
:district => c['district']})}
|
44
|
+
|
45
|
+
end
|
46
|
+
|
30
47
|
def self.find(fecid, cycle=CURRENT_CYCLE, candidate=nil)
|
31
48
|
if candidate
|
32
49
|
reply = invoke("#{cycle}/committees/#{fecid}/contributions/candidates/#{candidate}")
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
50
|
+
to_candidate(reply)
|
51
|
+
else
|
52
|
+
reply = invoke("#{cycle}/committees/#{fecid}/contributions")
|
53
|
+
all_candidates(reply)
|
54
|
+
end
|
37
55
|
end
|
38
|
-
|
56
|
+
|
39
57
|
end
|
40
58
|
end
|
data/lib/campaign_cash/filing.rb
CHANGED
@@ -13,11 +13,14 @@ module CampaignCash
|
|
13
13
|
self.new :committee_name => params['committee_name'],
|
14
14
|
:date_coverage_from => date_parser(params['date_coverage_from']),
|
15
15
|
:date_coverage_to => date_parser(params['date_coverage_to']),
|
16
|
-
:committee => params['committee'],
|
16
|
+
:committee => parse_committee(params['committee']),
|
17
17
|
:report_title => params['report_title'].strip,
|
18
18
|
:fec_uri => params['fec_uri'],
|
19
19
|
:amended => params['amended'],
|
20
20
|
:amended_uri => params['amended_uri'],
|
21
|
+
:original_filing => params['original_filing'],
|
22
|
+
:original_uri => params['original_uri'],
|
23
|
+
:paper => params['paper'],
|
21
24
|
:form_type => params['form_type']
|
22
25
|
end
|
23
26
|
|
@@ -34,25 +37,32 @@ module CampaignCash
|
|
34
37
|
end
|
35
38
|
|
36
39
|
|
37
|
-
def self.today
|
40
|
+
def self.today(offset=0)
|
38
41
|
cycle=CURRENT_CYCLE
|
39
|
-
reply = Base.invoke("#{cycle}/filings", {})
|
42
|
+
reply = Base.invoke("#{cycle}/filings", {:offset => offset})
|
40
43
|
results = reply['results']
|
41
|
-
|
44
|
+
results.map{|c| Filing.create(c)}
|
42
45
|
end
|
43
46
|
|
44
|
-
def self.date(year, month, day)
|
47
|
+
def self.date(year, month, day, offset=0)
|
45
48
|
cycle = cycle_from_date(Date.strptime("#{month}/#{day}/#{year}", '%m/%d/%Y'))
|
46
|
-
reply = Base.invoke("#{cycle}/filings/#{year}/#{month}/#{day}", {})
|
49
|
+
reply = Base.invoke("#{cycle}/filings/#{year}/#{month}/#{day}", {:offset => offset})
|
47
50
|
results = reply['results']
|
48
|
-
|
51
|
+
results.map{|c| Filing.create(c)}
|
52
|
+
end
|
53
|
+
|
54
|
+
def self.form_types
|
55
|
+
cycle=CURRENT_CYCLE
|
56
|
+
reply = Base.invoke("#{cycle}/filings/types",{})
|
57
|
+
results = reply['results']
|
58
|
+
results.map{|ft| OpenStruct.new({:id => ft['id'], :name => ft['name'].strip})}
|
49
59
|
end
|
50
60
|
|
51
61
|
def self.by_type(cycle, form_type)
|
52
62
|
cycle = cycle
|
53
63
|
reply = Base.invoke("#{cycle}/filings/types/#{form_type}")
|
54
64
|
results = reply['results']
|
55
|
-
|
65
|
+
results.map{|c| Filing.create(c)}
|
56
66
|
end
|
57
67
|
end
|
58
68
|
end
|
@@ -1,7 +1,7 @@
|
|
1
1
|
module CampaignCash
|
2
2
|
class IndependentExpenditure < Base
|
3
3
|
|
4
|
-
attr_reader :
|
4
|
+
attr_reader :committee, :district, :state, :committee_name, :purpose, :candidate, :support_or_oppose, :date, :amount, :office, :amendment, :date_received, :payee, :fec_uri
|
5
5
|
|
6
6
|
def initialize(params={})
|
7
7
|
params.each_pair do |k,v|
|
@@ -10,9 +10,9 @@ module CampaignCash
|
|
10
10
|
end
|
11
11
|
|
12
12
|
def self.create(params={})
|
13
|
-
self.new :
|
14
|
-
:
|
15
|
-
:
|
13
|
+
self.new :committee => parse_committee(params['fec_committee']),
|
14
|
+
:committee_name => params['fec_committee_name'],
|
15
|
+
:candidate => parse_candidate(params['fec_candidate']),
|
16
16
|
:office => params['office'],
|
17
17
|
:state => params['state'].strip,
|
18
18
|
:district => params['district'],
|
@@ -25,10 +25,10 @@ module CampaignCash
|
|
25
25
|
:date_received => date_parser(params['date_received'])
|
26
26
|
end
|
27
27
|
|
28
|
-
def self.latest
|
29
|
-
reply = Base.invoke("#{Base::CURRENT_CYCLE}/independent_expenditures")
|
28
|
+
def self.latest(offset=0)
|
29
|
+
reply = Base.invoke("#{Base::CURRENT_CYCLE}/independent_expenditures",{:offset => offset})
|
30
30
|
results = reply['results']
|
31
|
-
|
31
|
+
results.map{|c| IndependentExpenditure.create(c)}
|
32
32
|
end
|
33
33
|
|
34
34
|
def self.date(date,offset=0)
|
@@ -36,37 +36,37 @@ module CampaignCash
|
|
36
36
|
cycle = cycle_from_date(d)
|
37
37
|
reply = Base.invoke("#{cycle}/independent_expenditures/#{d.year}/#{d.month}/#{d.day}",{:offset => offset})
|
38
38
|
results = reply['results']
|
39
|
-
|
39
|
+
results.map{|c| IndependentExpenditure.create(c)}
|
40
40
|
end
|
41
41
|
|
42
42
|
def self.committee(id, cycle, offset=0)
|
43
|
-
|
43
|
+
independent_expenditures = []
|
44
44
|
reply = Base.invoke("#{cycle}/committees/#{id}/independent_expenditures",{:offset => offset})
|
45
45
|
results = reply['results']
|
46
46
|
comm = reply['fec_committee']
|
47
47
|
results.each do |result|
|
48
48
|
result['fec_committee'] = comm
|
49
|
-
|
49
|
+
independent_expenditures << IndependentExpenditure.create(result)
|
50
50
|
end
|
51
|
-
|
51
|
+
independent_expenditures
|
52
52
|
end
|
53
53
|
|
54
54
|
def self.candidate(id, cycle, offset=0)
|
55
|
-
|
55
|
+
independent_expenditures = []
|
56
56
|
reply = Base.invoke("#{cycle}/candidates/#{id}/independent_expenditures",{:offset => offset})
|
57
57
|
results = reply['results']
|
58
58
|
cand = reply['fec_candidate']
|
59
59
|
results.each do |result|
|
60
60
|
result['fec_candidate'] = cand
|
61
|
-
|
61
|
+
independent_expenditures << IndependentExpenditure.create(result)
|
62
62
|
end
|
63
|
-
|
63
|
+
independent_expenditures
|
64
64
|
end
|
65
65
|
|
66
|
-
def self.president(cycle=
|
66
|
+
def self.president(cycle=CURRENT_CYCLE,offset=0)
|
67
67
|
reply = Base.invoke("#{cycle}/president/independent_expenditures",{:offset => offset})
|
68
68
|
results = reply['results']
|
69
|
-
|
69
|
+
results.map{|c| IndependentExpenditure.create(c)}
|
70
70
|
end
|
71
71
|
|
72
72
|
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
module CampaignCash
|
2
|
+
class President < Base
|
3
|
+
|
4
|
+
attr_reader :committee_id, :name, :id, :party, :date_coverage_from, :date_coverage_to, :total_receipts, :total_disbursements,
|
5
|
+
:end_cash, :total_refunds, :total_contributions, :net_individual_contributions, :net_pac_contributions,
|
6
|
+
:net_party_contributions, :net_candidate_contributions, :net_primary_contributions, :net_general_contributions,
|
7
|
+
:federal_funds, :contributions_less_than_200, :contributions_200_499, :contributions_500_1499, :contributions_1500_2499,
|
8
|
+
:contributions_max
|
9
|
+
|
10
|
+
def initialize(params={})
|
11
|
+
params.each_pair do |k,v|
|
12
|
+
instance_variable_set("@#{k}", v)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
# Creates a new president summary object from a JSON API presidential response.
|
17
|
+
def self.create_summary(params={})
|
18
|
+
self.new :name => params['name'],
|
19
|
+
:id => params['candidate_id'],
|
20
|
+
:party => params['party'],
|
21
|
+
:committee_id => params['committee_id'],
|
22
|
+
:total_receipts => params['total_receipts'],
|
23
|
+
:total_disbursements => params['total_disbursements'],
|
24
|
+
:end_cash => params['cash_on_hand'],
|
25
|
+
:date_coverage_from => params['date_coverage_from'],
|
26
|
+
:date_coverage_to => params['date_coverage_to']
|
27
|
+
end
|
28
|
+
|
29
|
+
# Creates a detailed president object
|
30
|
+
def self.create_detail(params={})
|
31
|
+
self.new :name => params['candidate_name'],
|
32
|
+
:id => params['candidate_id'],
|
33
|
+
:party => params['party'],
|
34
|
+
:committee_id => params['committee_id'],
|
35
|
+
:total_receipts => params['total_receipts'],
|
36
|
+
:total_contributions => params['total_contributions'],
|
37
|
+
:total_disbursements => params['total_disbursements'],
|
38
|
+
:end_cash => params['cash_on_hand'],
|
39
|
+
:date_coverage_from => params['date_coverage_from'],
|
40
|
+
:date_coverage_to => params['date_coverage_to'],
|
41
|
+
:total_refunds => params['total_refunds'],
|
42
|
+
:net_individual_contributions => params['net_individual_contributions'],
|
43
|
+
:net_pac_contributions => params['net_pac_contributions'],
|
44
|
+
:net_party_contributions => params['net_party_contributions'],
|
45
|
+
:net_candidate_contributions => params['net_candidate_contributions'],
|
46
|
+
:net_primary_contributions => params['net_primary_contributions'],
|
47
|
+
:net_general_contributions => params['net_general_contributions'],
|
48
|
+
:federal_funds => params['federal_funds'],
|
49
|
+
:contributions_less_than_200 => params['total_contributions_less_than_200'],
|
50
|
+
:contributions_200_499 => params['contributions_200_499'],
|
51
|
+
:contributions_500_1499 => params['contributions_500_1499'],
|
52
|
+
:contributions_1500_2499 => params['contributions_1500_2499'],
|
53
|
+
:contributions_max => params['total_contributions_max']
|
54
|
+
end
|
55
|
+
|
56
|
+
# Returns an array of presidential candidates for a given cycle, defaults to the current cycle.
|
57
|
+
# Only returns candidates that The New York Times is tracking for financial activity.
|
58
|
+
def self.summary(cycle=CURRENT_CYCLE)
|
59
|
+
reply = invoke("#{cycle}/president/totals", {})
|
60
|
+
results = reply['results']
|
61
|
+
results.map{|c| self.create_summary(c)}
|
62
|
+
end
|
63
|
+
|
64
|
+
# Returns a President object for a given presidential candidate in a given cycle, defaults to the current cycle.
|
65
|
+
# Only returns candidates tracked by The New York Times.
|
66
|
+
def self.detail(id, cycle=CURRENT_CYCLE)
|
67
|
+
reply = invoke("#{cycle}/president/candidates/#{id}", {})
|
68
|
+
results = reply['results']
|
69
|
+
results.map{|c| self.create_detail(c)}
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
@@ -51,7 +51,7 @@ class TestCampaignCash::TestCandidate < Test::Unit::TestCase
|
|
51
51
|
|
52
52
|
context "candidate leaders" do
|
53
53
|
setup do
|
54
|
-
reply = Base.invoke('2010/candidates/leaders/
|
54
|
+
reply = Base.invoke('2010/candidates/leaders/end-cash', {})
|
55
55
|
results = reply['results']
|
56
56
|
@candidates = results.map{|c| Candidate.create(c)}
|
57
57
|
end
|
@@ -53,7 +53,7 @@ class TestCampaignCash::TestCommittee < Test::Unit::TestCase
|
|
53
53
|
setup do
|
54
54
|
reply = Base.invoke('2010/committees/C00312223/filings', {})
|
55
55
|
results = reply['results']
|
56
|
-
@filings = results.map{|f| Filing.
|
56
|
+
@filings = results.map{|f| Filing.create(f)}
|
57
57
|
end
|
58
58
|
|
59
59
|
should "return 11 filings" do
|
@@ -81,7 +81,7 @@ class TestCampaignCash::TestCommittee < Test::Unit::TestCase
|
|
81
81
|
end
|
82
82
|
|
83
83
|
should "return a $5,000 contribution to Renee Ellmers" do
|
84
|
-
assert_equal @contribution.results.detect{|c| c.
|
84
|
+
assert_equal @contribution.results.detect{|c| c.candidate == "H0NC02059"}.amount, 5000
|
85
85
|
end
|
86
86
|
|
87
87
|
end
|
@@ -89,7 +89,7 @@ class TestCampaignCash::TestCommittee < Test::Unit::TestCase
|
|
89
89
|
context "committee contributions to a candidate" do
|
90
90
|
setup do
|
91
91
|
reply = Base.invoke('2010/committees/C00458588/contributions/candidates/H0NC02059', {})
|
92
|
-
@contribution = Contribution.
|
92
|
+
@contribution = Contribution.to_candidate(reply)
|
93
93
|
end
|
94
94
|
|
95
95
|
should "return 2 results totaling $10,000" do
|
@@ -19,7 +19,7 @@ class TestCampaignCash::TestIndependentExpenditure < Test::Unit::TestCase
|
|
19
19
|
end
|
20
20
|
|
21
21
|
should "return at least one independent expenditure against Barack Obama" do
|
22
|
-
assert_equal("P80003338", @independent_expenditures.first.
|
22
|
+
assert_equal("P80003338", @independent_expenditures.first.candidate)
|
23
23
|
end
|
24
24
|
end
|
25
25
|
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class TestCampaignCash::TestPresident < Test::Unit::TestCase
|
4
|
+
include CampaignCash
|
5
|
+
|
6
|
+
context "President.summary" do
|
7
|
+
setup do
|
8
|
+
reply = Base.invoke('2012/president/totals', {})
|
9
|
+
@results = reply['results']
|
10
|
+
@summaries = @results.map{|r| President.create_summary(r)}
|
11
|
+
@summary = @summaries.first
|
12
|
+
end
|
13
|
+
|
14
|
+
should "return an array of objects of the President type" do
|
15
|
+
assert_kind_of(President, @summary)
|
16
|
+
end
|
17
|
+
|
18
|
+
%w(name total_contributions party total_receipts).each do |attr|
|
19
|
+
should "assign the value of the @#{attr} attribute from the '#{attr}' key in the hash" do
|
20
|
+
assert_equal(@results.first[attr], @summary.send(attr))
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
context "President.detail" do
|
26
|
+
setup do
|
27
|
+
reply = Base.invoke('2012/president/candidates/C00496034', {})
|
28
|
+
@results = reply['results']
|
29
|
+
@detail = President.create_detail(@results.first)
|
30
|
+
end
|
31
|
+
|
32
|
+
should "return an array of objects of the President type" do
|
33
|
+
assert_kind_of(President, @detail)
|
34
|
+
end
|
35
|
+
|
36
|
+
%w(net_primary_contributions party total_refunds).each do |attr|
|
37
|
+
should "assign the value of the @#{attr} attribute from the '#{attr}' key in the hash" do
|
38
|
+
assert_equal(@results.first[attr], @detail.send(attr))
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
data/test/test_helper.rb
CHANGED
@@ -4,7 +4,7 @@ require 'shoulda'
|
|
4
4
|
require 'json'
|
5
5
|
require 'ostruct'
|
6
6
|
|
7
|
-
%w(base candidate committee contribution filing form independent_expenditure).each do |f|
|
7
|
+
%w(base candidate committee contribution filing form independent_expenditure president).each do |f|
|
8
8
|
require File.join(File.dirname(__FILE__), '../lib/campaign_cash', f)
|
9
9
|
end
|
10
10
|
|
metadata
CHANGED
@@ -1,12 +1,12 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: campaign_cash
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 3
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
|
-
-
|
8
|
-
-
|
9
|
-
version: "
|
7
|
+
- 2
|
8
|
+
- 0
|
9
|
+
version: "2.0"
|
10
10
|
platform: ruby
|
11
11
|
authors:
|
12
12
|
- Derek Willis
|
@@ -14,7 +14,7 @@ autorequire:
|
|
14
14
|
bindir: bin
|
15
15
|
cert_chain: []
|
16
16
|
|
17
|
-
date:
|
17
|
+
date: 2012-01-10 00:00:00 -05:00
|
18
18
|
default_executable:
|
19
19
|
dependencies:
|
20
20
|
- !ruby/object:Gem::Dependency
|
@@ -61,7 +61,7 @@ dependencies:
|
|
61
61
|
version: "0"
|
62
62
|
type: :development
|
63
63
|
version_requirements: *id003
|
64
|
-
description: A
|
64
|
+
description: A client for The New York Times Campaign Finance API
|
65
65
|
email:
|
66
66
|
- dwillis@nytimes.com
|
67
67
|
executables: []
|
@@ -86,12 +86,14 @@ files:
|
|
86
86
|
- lib/campaign_cash/filing.rb
|
87
87
|
- lib/campaign_cash/form.rb
|
88
88
|
- lib/campaign_cash/independent_expenditure.rb
|
89
|
+
- lib/campaign_cash/president.rb
|
89
90
|
- lib/campaign_cash/version.rb
|
90
91
|
- test/campaign_cash/test_candidate.rb
|
91
92
|
- test/campaign_cash/test_committee.rb
|
92
93
|
- test/campaign_cash/test_filing.rb
|
93
94
|
- test/campaign_cash/test_form.rb
|
94
95
|
- test/campaign_cash/test_independent_expenditure.rb
|
96
|
+
- test/campaign_cash/test_president.rb
|
95
97
|
- test/test_helper.rb
|
96
98
|
has_rdoc: true
|
97
99
|
homepage: http://rubygems.org/gems/campaign_cash
|
@@ -135,4 +137,5 @@ test_files:
|
|
135
137
|
- test/campaign_cash/test_filing.rb
|
136
138
|
- test/campaign_cash/test_form.rb
|
137
139
|
- test/campaign_cash/test_independent_expenditure.rb
|
140
|
+
- test/campaign_cash/test_president.rb
|
138
141
|
- test/test_helper.rb
|