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 CHANGED
@@ -1,6 +1,10 @@
1
- = campaign_cash
2
1
 
3
- * Source[http://github.com/nytimes/campaign_cash]
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
- == USAGE:
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. Some examples (provided you've done include CampaignCash):
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
- Candidate.find("H4NY07011", 2012) # find Gary Ackerman's details for the 2012 cycle
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
- Check out the tests for further examples.
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
 
@@ -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 thin client for The New York Times Campaign Finance API"
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
@@ -1,3 +1,3 @@
1
- %w(base candidate committee contribution filing form independent_expenditure).each do |f|
1
+ %w(base candidate committee contribution filing form independent_expenditure president).each do |f|
2
2
  require File.join(File.dirname(__FILE__), '../lib/campaign_cash', f)
3
3
  end
@@ -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 => parse_committee_id(params['committee']),
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
- :committee_id => parse_committee_id(params['committee'])
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
- :super_pac => params['super_pac'],
55
- :sponsor_name => params['sponsor_name']
56
-
102
+ :leadership => params['leadership'],
103
+ :super_pac => params['super_pac']
57
104
  end
58
105
 
59
- def self.parse_candidate(candidate)
60
- return nil if candidate.nil?
61
- candidate.split('/').last.split('.').first
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.new_committees(cycle=CURRENT_CYCLE)
142
+ def self.latest(cycle=CURRENT_CYCLE)
77
143
  reply = invoke("#{cycle}/committees/new",{})
78
144
  results = reply['results']
79
- results.map{|c| create(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
- def self.create(params={})
13
- self.new :committee_uri => params['committee'],
14
- :total_results => params['total_results'],
15
- :cycle => params['cycle'],
16
- :total_amount => params['total_amount'],
17
- :results => params['results'].map{|c| OpenStruct.new({
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
- :candidate_uri => c['candidate_uri'],
20
- :primary_general => c['primary_general'],
21
- :amount => c['amount'],
22
- :state => c['state'],
23
- :name => c['name'],
24
- :image_uri => c['image_uri'],
25
- :party => c['party'],
26
- :district => c['district']})}
27
-
28
- end
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
- else
34
- reply = invoke("#{cycle}/committees/#{fecid}/contributions")
35
- end
36
- create(reply)
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
@@ -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
- @filings = results.map{|c| Filing.create(c)}
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
- @filings = results.map{|c| Filing.create(c)}
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
- @filings = results.map{|c| Filing.create(c)}
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 :fec_committee_id, :district, :state, :fec_committee_name, :purpose, :fec_candidate_id, :support_or_oppose, :date, :amount, :office, :amendment, :date_received, :payee, :fec_uri
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 :fec_committee_id => params['fec_committee'].split('/').last.split('.').first,
14
- :fec_committee_name => params['fec_committee_name'],
15
- :fec_candidate_id => params['fec_candidate'].split('/').last.split('.').first,
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
- @independent_expenditures = results.map{|c| IndependentExpenditure.create(c)}
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
- @independent_expenditures = results.map{|c| IndependentExpenditure.create(c)}
39
+ results.map{|c| IndependentExpenditure.create(c)}
40
40
  end
41
41
 
42
42
  def self.committee(id, cycle, offset=0)
43
- @independent_expenditures = []
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
- @independent_expenditures << IndependentExpenditure.create(result)
49
+ independent_expenditures << IndependentExpenditure.create(result)
50
50
  end
51
- @independent_expenditures
51
+ independent_expenditures
52
52
  end
53
53
 
54
54
  def self.candidate(id, cycle, offset=0)
55
- @independent_expenditures = []
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
- @independent_expenditures << IndependentExpenditure.create(result)
61
+ independent_expenditures << IndependentExpenditure.create(result)
62
62
  end
63
- @independent_expenditures
63
+ independent_expenditures
64
64
  end
65
65
 
66
- def self.president(cycle=Base::CURRENT_CYCLE,offset=0)
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
- @independent_expenditures = results.map{|c| IndependentExpenditure.create(c)}
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
@@ -1,3 +1,3 @@
1
1
  module CampaignCash
2
- VERSION = "1.8"
2
+ VERSION = "2.0"
3
3
  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/end_cash', {})
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.create_from_filings(f)}
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.candidate_uri == "/candidates/H0NC02059.json"}.amount, 5000
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.create(reply)
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.fec_candidate_id)
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: 31
4
+ hash: 3
5
5
  prerelease:
6
6
  segments:
7
- - 1
8
- - 8
9
- version: "1.8"
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: 2011-12-29 00:00:00 -05:00
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 thin client for The New York Times Campaign Finance API
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