open_fec_api 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 818b705a49bd80cf98215fef54f4b5eda20769da
4
+ data.tar.gz: 4ab0d6b6a6075df42cdc644ebb577244531d98a8
5
+ SHA512:
6
+ metadata.gz: 1e2b362f084c2dcef094944a678e411b337bf2815c1b4ba833b437561f444278163c98c99430ec7e36d82a4c203e32276b5613203dee2618747f9ae3ea26e373
7
+ data.tar.gz: 8aad09cc00374547cbd3621f462eaaf77ee26efda67b4c82e34f8d7c7cd8fc9864f64c19b3460e3ab7d570f960adafc5b4304593595c8efc3d1af077d9b1f1df
data/.gitignore ADDED
@@ -0,0 +1,14 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ *.bundle
11
+ *.so
12
+ *.o
13
+ *.a
14
+ mkmf.log
data/.rspec ADDED
@@ -0,0 +1,2 @@
1
+ --format documentation
2
+ --color
data/CREDITS.md ADDED
@@ -0,0 +1,14 @@
1
+ # Credits, Notes, and Reference
2
+ + http://sunlightfoundation.com/blog/2015/07/08/openfec-makes-campaign-finance-data-more-accessible-with-new-api-heres-how-to-get-started/
3
+ + http://brandonhilkert.com/blog/ruby-gem-configuration-patterns/
4
+ + https://robots.thoughtbot.com/mygem-configure-block
5
+ + http://stackoverflow.com/questions/10584638/setting-up-configuration-settings-when-writing-a-gem
6
+ + http://sunlightfoundation.com/blog/2015/07/08/openfec-makes-campaign-finance-data-more-accessible-with-new-api-heres-how-to-get-started/
7
+ + http://betterspecs.org/
8
+ + https://github.com/jnunemaker/httparty
9
+ + https://github.com/jnunemaker/httparty/tree/master/examples
10
+ + http://s2t2.info/process-documentation/2015/07/03/how-to-make-a-ruby-gem.html
11
+ + https://gorails.com/episodes/consuming-an-api-using-httparty-and-creating-a-gem
12
+ + https://api.open.fec.gov/
13
+ + http://plumbing.pipelinedeals.com/wrapping-rest-apis-with-ruby/
14
+ + http://stackoverflow.com/questions/2680523/dry-ruby-initialization-with-hash-argument
data/ENDPOINTS.md ADDED
@@ -0,0 +1,36 @@
1
+ ## Endpoints
2
+
3
+ Endpoint | Operation | Wrapper Method
4
+ --- | --- | ---
5
+ Candidates | `GET /candidate/{candidate_id}` | `Candidate#find`
6
+ Candidates | `GET /candidate/{candidate_id}/history` | N/A
7
+ Candidates | `GET /candidate/{candidate_id}/history/{cycle}` | N/A
8
+ Candidates | `GET /candidates` | `Candidate#all`
9
+ Candidates | `GET /candidates/search` | N/A
10
+ Candidates | `GET /candidate/{candidate_id}/committees` | N/A
11
+ Candidates | `GET /candidate/{candidate_id}/committees/history` | N/A
12
+ Candidates | `GET /candidate/{candidate_id}/committees/history/{cycle}` | N/A
13
+ Committees | `GET /committee/{committee_id}/candidates` | N/A
14
+ Committees | `GET /committee/{committee_id}/candidates/history` | N/A
15
+ Committees | `GET /committee/{committee_id}/candidates/history/{cycle}` | N/A
16
+ Committees | `GET /committee/{committee_id}` | N/A
17
+ Committees | `GET /committee/{committee_id}/history` | N/A
18
+ Committees | `GET /committee/{committee_id}/history/{cycle}` | N/A
19
+ Committees | `GET /committees` | N/A
20
+ Filings | `GET /committee/{committee_id}/filings` | N/A
21
+ Filings | `GET /filings` | N/A
22
+ Financial | `GET /committee/{committee_id}/reports` | N/A
23
+ Financial | `GET /committee/{committee_id}/totals` | N/A
24
+ Financial | `GET /reports/{committee_type}` | N/A
25
+ Schedules | `GET /committee/{committee_id}/schedules/schedule_a/by_contributor` | N/A
26
+ Schedules | `GET /committee/{committee_id}/schedules/schedule_a/by_size` | N/A
27
+ Schedules | `GET /committee/{committee_id}/schedules/schedule_a/by_state` | N/A
28
+ Schedules | `GET /committee/{committee_id}/schedules/schedule_a/by_zip` | N/A
29
+ Schedules | `GET /schedules/schedule_a` | N/A
30
+ Schedules | `GET /schedules/schedule_a/by_contributor` | N/A
31
+ Schedules | `GET /schedules/schedule_a/by_size` | N/A
32
+ Schedules | `GET /schedules/schedule_a/by_state` | N/A
33
+ Schedules | `GET /schedules/schedule_a/by_zip` | N/A
34
+ Schedules | `GET /schedules/schedule_b` | N/A
35
+ Search | `GET /names/candidates` | `Candidate#where`
36
+ Search | `GET /names/committees` | N/A
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in open_fec_api.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2015 MJ Rossetti (@s2t2)
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,67 @@
1
+ # OpenFecApi
2
+
3
+ A ruby wrapper for 18F's [Open FEC (Federal Elections Commission) API](https://api.open.fec.gov/).
4
+
5
+ ## Installation
6
+
7
+ Add `gem 'open_fec_api'` to your application's *Gemfile* and run `bundle install`, or install manually with `gem install open_fec_api`.
8
+
9
+ ## Configuration
10
+
11
+ Configure a client with your [API key](https://api.data.gov/signup/) before making requests.
12
+
13
+ ```` rb
14
+ client = OpenFecApi::Client.new("api_key_123")
15
+ ````
16
+
17
+ ## Usage
18
+
19
+ Make a request.
20
+
21
+ ```` rb
22
+ response = client.candidates
23
+ ````
24
+
25
+ Request different pages by setting the `:page` request parameter. Avoid rate-limits by increasing the `:per_page` request parameter to 100.
26
+
27
+ ```` rb
28
+ options = {:page => 1, :per_page => 100}
29
+ response = client.candidates(options)
30
+ while response.page < response.pages do
31
+ options.merge!({:page => response.page + 1})
32
+ response = client.candidates(options)
33
+ end
34
+ ````
35
+
36
+ Make requests using endpoint-specific parameters.
37
+
38
+ ```` rb
39
+ options = {:party => "DEM"}
40
+ response = client.candidates(options)
41
+ ````
42
+
43
+ ## Contributing
44
+
45
+ Help wrap all the [endpoints](ENDPOINTS.md)!
46
+
47
+ Browse existing issues or create a new issue to communicate bugs, desired features, etc.
48
+
49
+ After forking the repo and pushing your changes, create a pull request referencing the applicable issue(s).
50
+
51
+ ### Installation
52
+
53
+ Check out the repo with `git clone git@github.com:debate-watch/open-fec-api-ruby.git`, and `cd open-fec-api-ruby`.
54
+
55
+ After checking out the repo, run `bin/setup` to install dependencies.
56
+
57
+ ### Testing
58
+
59
+ Run `bundle exec rake` or `bundle exec rspec spec/` to run the tests.
60
+
61
+ You can also run `bin/console` for an interactive prompt that will allow you to experiment.
62
+
63
+ To install this gem onto your local machine, run `bundle exec rake install`.
64
+
65
+ ### Releasing
66
+
67
+ Update the version number in `version.rb`, then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
data/Rakefile ADDED
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task :default => :spec
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "open_fec_api"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ require "pry"
11
+ Pry.start
12
+
13
+ # require "irb"
14
+ # IRB.start
data/bin/setup ADDED
@@ -0,0 +1,7 @@
1
+ #!/bin/bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+
5
+ bundle install
6
+
7
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,81 @@
1
+ require "open_fec_api/version"
2
+ require "open_fec_api/client"
3
+ require "open_fec_api/response"
4
+
5
+ module OpenFecApi
6
+ =begin
7
+
8
+ #
9
+ # CANDIDATE
10
+ #
11
+
12
+ GET /candidate/{candidate_id}
13
+ GET /candidate/{candidate_id}/history
14
+ GET /candidate/{candidate_id}/history/{cycle}
15
+
16
+ #
17
+ # CANDIDATES
18
+ #
19
+
20
+ GET /candidates
21
+ GET /candidates/search
22
+
23
+ GET /committee/{committee_id}/candidates
24
+ GET /committee/{committee_id}/candidates/history
25
+ GET /committee/{committee_id}/candidates/history/{cycle}
26
+
27
+ #
28
+ # COMMITTEE
29
+ #
30
+
31
+ GET /committee/{committee_id}
32
+ GET /committee/{committee_id}/filings
33
+ GET /committee/{committee_id}/reports
34
+ GET /committee/{committee_id}/totals
35
+ GET /committee/{committee_id}/history
36
+ GET /committee/{committee_id}/history/{cycle}
37
+
38
+ #
39
+ # COMMITTEES
40
+ #
41
+
42
+ GET /committees
43
+
44
+ GET /candidate/{candidate_id}/committees
45
+ GET /candidate/{candidate_id}/committees/history
46
+ GET /candidate/{candidate_id}/committees/history/{cycle}
47
+
48
+ #
49
+ # SCHEDULES
50
+ #
51
+
52
+ GET /schedules/schedule_a
53
+ GET /schedules/schedule_a/by_contributor
54
+ GET /schedules/schedule_a/by_size
55
+ GET /schedules/schedule_a/by_state
56
+ GET /schedules/schedule_a/by_zip
57
+ GET /schedules/schedule_b
58
+
59
+ GET /committee/{committee_id}/schedules/schedule_a/by_contributor
60
+ GET /committee/{committee_id}/schedules/schedule_a/by_size
61
+ GET /committee/{committee_id}/schedules/schedule_a/by_state
62
+ GET /committee/{committee_id}/schedules/schedule_a/by_zip
63
+
64
+ # NAMES
65
+
66
+ GET /names/candidates
67
+ GET /names/committees
68
+
69
+ HTTParty.get("http://api.open.fec.gov/v1/names/candidates?api_key=#{@api_key}")
70
+ HTTParty.get("http://api.open.fec.gov/v1/names/committees?api_key=#{@api_key}")
71
+
72
+ # FILINGS
73
+
74
+ GET /filings
75
+
76
+ # REPORTS
77
+
78
+ GET /reports/{committee_type}
79
+
80
+ =end
81
+ end
@@ -0,0 +1,51 @@
1
+ require 'httparty'
2
+
3
+ module OpenFecApi
4
+ class Client
5
+ attr_reader :api_key
6
+ include HTTParty
7
+ base_uri 'https://api.open.fec.gov/v1'
8
+
9
+ def initialize(api_key)
10
+ @api_key = api_key
11
+ end
12
+
13
+ def configured?
14
+ !self.api_key.nil?
15
+ end
16
+
17
+ # Candidates Endpoint
18
+ #
19
+ # https://api.open.fec.gov/developers#!/candidate/get_candidates
20
+ #
21
+ # @param [Hash] options
22
+ # option options Array[string] :sort Provide a field to sort by. Use - for descending order.
23
+ # option options Boolean :sort_hide_null Hide null values on sorted column(s).
24
+ # option options String :year See records pertaining to a particular year.
25
+ # option options Array[string] :office Governmental office candidate runs for: House (H), Senate (S) or President (P).
26
+ # option options Array[string] :candidate_status One letter code explaining if the candidate is: present (C), future (F), not yet (N), or prior (P).
27
+ # option options Array[string] :party Three letter code for the party under which a candidate ran for office.
28
+ # option options Array[string] :state U.S. State candidate or territory where a candidate runs for office.
29
+ # option options Array[integer] :cycle Two-year election cycle in which a candidate runs for office. Calculated from FEC form 2.
30
+ # option options Array[string] :district Two digit district number.
31
+ # option options Array[string] :incumbent_challenge One letter code explaining if the candidate is an incumbent (I), a challenger (C), or if the seat is open (O).
32
+ # option options String :q Text to search all fields for.
33
+ # option options String :name Candidate's name (full or partial).
34
+ # option options Array[string] :candidate_id A unique identifier assigned to each candidate registered with the FEC. If a person runs for several offices, that person will have separate candidate IDs for each office.
35
+ # option options Integer :page For paginating through results, starting at page 1.
36
+ # option options Integer :per_page The number of results returned per page. Defaults to 20.
37
+ #
38
+ # @example
39
+ # OpenFecApi::Client.new(:api_key => API_KEY).candidates(:page => 1, :per_page => 100)
40
+ def candidates(options = {})
41
+ query = {'api_key' => @api_key}
42
+ request_params = ["sort", "sort_hide_null", "year", "office", "candidate_status", "party", "state", "cycle", "district", "incumbent_challenge", "name", "candidate_id", "page", "per_page"]
43
+ request_options = options.select{|k,v| request_params.include?(k.to_s)}
44
+ request_options.each do |k,v|
45
+ query.merge!({k.to_s => v})
46
+ end
47
+ response = self.class.get("/candidates", query: query)
48
+ return Response.new(response)
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,49 @@
1
+ module OpenFecApi
2
+ class Response
3
+ attr_reader :request, :headers, :api_version, :pagination, :results
4
+
5
+ def initialize(response)
6
+ @request = response.request
7
+ @headers = response.headers
8
+ @api_version = response["api_version"]
9
+ @pagination = response["pagination"]
10
+ @results = response["results"]
11
+ end
12
+
13
+ def request_query
14
+ request.options[:query]
15
+ end
16
+
17
+ def limit
18
+ headers["x-ratelimit-limit"].to_i
19
+ end
20
+
21
+ def remaining
22
+ headers["x-ratelimit-remaining"].to_i
23
+ end
24
+
25
+ def page
26
+ pagination["page"].to_i
27
+ end
28
+
29
+ def pages
30
+ pagination["pages"].to_i
31
+ end
32
+
33
+ def results_count
34
+ results.count
35
+ end
36
+
37
+ def first_result_name
38
+ results.first["name"]
39
+ end
40
+
41
+ def last_result_name
42
+ results.last["name"]
43
+ end
44
+
45
+ def summary
46
+ "PAGE #{page}/#{pages} -- RATE #{remaining}/#{limit} -- #{first_result_name} ... #{last_result_name}"
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,3 @@
1
+ module OpenFecApi
2
+ VERSION = "0.0.1"
3
+ end
@@ -0,0 +1,26 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'open_fec_api/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "open_fec_api"
8
+ spec.version = OpenFecApi::VERSION
9
+ spec.authors = ["MJ Rossetti (@s2t2)"]
10
+ spec.email = ["s2t2mail@gmail.com"]
11
+ spec.summary = %q{A ruby wrapper for 18F's [Open FEC (Federal Elections Commission) API](https://api.open.fec.gov/).}
12
+ spec.description = %q{A ruby wrapper for 18F's [Open FEC (Federal Elections Commission) API](https://api.open.fec.gov/).}
13
+ spec.homepage = "https://github.com/debate-watch/open_fec_api/"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_development_dependency "bundler", "~> 1.7"
22
+ spec.add_development_dependency "rake", "~> 10.0"
23
+ spec.add_development_dependency "rspec", "~> 3.1"
24
+ spec.add_development_dependency "pry", "~> 0.10"
25
+ spec.add_dependency "httparty", "~> 0.13"
26
+ end
@@ -0,0 +1,303 @@
1
+ {"pagination"=>{"pages"=>1020, "count"=>20393, "per_page"=>20, "page"=>1},
2
+ "api_version"=>"1.0",
3
+ "results"=>
4
+ [{"candidate_status"=>"N",
5
+ "active_through"=>2004,
6
+ "incumbent_challenge_full"=>"Unknown",
7
+ "district"=>nil,
8
+ "election_years"=>[2004],
9
+ "party"=>"IND",
10
+ "office"=>"P",
11
+ "candidate_status_full"=>"Not yet a statutory candidate",
12
+ "state"=>"US",
13
+ "incumbent_challenge"=>nil,
14
+ "party_full"=>"Independent",
15
+ "office_full"=>"President",
16
+ "candidate_id"=>"P40002172",
17
+ "name"=>"AABBATTE, MICHAEL THOMAS WITORT",
18
+ "cycles"=>[2004]},
19
+ {"candidate_status"=>"C",
20
+ "active_through"=>2012,
21
+ "incumbent_challenge_full"=>"Challenger",
22
+ "district"=>nil,
23
+ "election_years"=>[2012],
24
+ "party"=>"REP",
25
+ "office"=>"S",
26
+ "candidate_status_full"=>"Statutory candidate",
27
+ "state"=>"UT",
28
+ "incumbent_challenge"=>"C",
29
+ "party_full"=>"Republican Party",
30
+ "office_full"=>"Senate",
31
+ "candidate_id"=>"S2UT00229",
32
+ "name"=>"AALDERS, TIMOTHY NOEL",
33
+ "cycles"=>[2012]},
34
+ {"candidate_status"=>"C",
35
+ "active_through"=>2012,
36
+ "incumbent_challenge_full"=>"Challenger",
37
+ "district"=>"01",
38
+ "election_years"=>[2012],
39
+ "party"=>"REP",
40
+ "office"=>"H",
41
+ "candidate_status_full"=>"Statutory candidate",
42
+ "state"=>"CA",
43
+ "incumbent_challenge"=>"C",
44
+ "party_full"=>"Republican Party",
45
+ "office_full"=>"House",
46
+ "candidate_id"=>"H2CA01110",
47
+ "name"=>"AANESTAD, SAMUEL",
48
+ "cycles"=>[2012]},
49
+ {"candidate_status"=>"N",
50
+ "active_through"=>2008,
51
+ "incumbent_challenge_full"=>"Open seat",
52
+ "district"=>nil,
53
+ "election_years"=>[2008],
54
+ "party"=>"DEM",
55
+ "office"=>"P",
56
+ "candidate_status_full"=>"Not yet a statutory candidate",
57
+ "state"=>"US",
58
+ "incumbent_challenge"=>"O",
59
+ "party_full"=>"Democratic Party",
60
+ "office_full"=>"President",
61
+ "candidate_id"=>"P80002926",
62
+ "name"=>"AARON, LAURA DAVIS",
63
+ "cycles"=>[2008]},
64
+ {"candidate_status"=>"P",
65
+ "active_through"=>2000,
66
+ "incumbent_challenge_full"=>"Unknown",
67
+ "district"=>"01",
68
+ "election_years"=>[2000],
69
+ "party"=>"REP",
70
+ "office"=>"H",
71
+ "candidate_status_full"=>"Statutory candidate in a prior cycle",
72
+ "state"=>"MA",
73
+ "incumbent_challenge"=>nil,
74
+ "party_full"=>"Republican Party",
75
+ "office_full"=>"House",
76
+ "candidate_id"=>"H0MA01024",
77
+ "name"=>"ABAIR, PETER JON",
78
+ "cycles"=>[2000]},
79
+ {"candidate_status"=>"N",
80
+ "active_through"=>2012,
81
+ "incumbent_challenge_full"=>"Open seat",
82
+ "district"=>"00",
83
+ "election_years"=>[2012],
84
+ "party"=>"DEM",
85
+ "office"=>"H",
86
+ "candidate_status_full"=>"Not yet a statutory candidate",
87
+ "state"=>"MT",
88
+ "incumbent_challenge"=>"O",
89
+ "party_full"=>"Democratic Party",
90
+ "office_full"=>"House",
91
+ "candidate_id"=>"H2MT00039",
92
+ "name"=>"ABARR, JOHN ALLEN",
93
+ "cycles"=>[2012]},
94
+ {"candidate_status"=>"C",
95
+ "active_through"=>2008,
96
+ "incumbent_challenge_full"=>"Unknown",
97
+ "district"=>"05",
98
+ "election_years"=>[2006, 2008],
99
+ "party"=>"DEM",
100
+ "office"=>"H",
101
+ "candidate_status_full"=>"Statutory candidate",
102
+ "state"=>"NJ",
103
+ "incumbent_challenge"=>nil,
104
+ "party_full"=>"Democratic Party",
105
+ "office_full"=>"House",
106
+ "candidate_id"=>"H6NJ05155",
107
+ "name"=>"ABATE, CAMILLE M",
108
+ "cycles"=>[2006, 2008]},
109
+ {"candidate_status"=>"P",
110
+ "active_through"=>1992,
111
+ "incumbent_challenge_full"=>"Unknown",
112
+ "district"=>"12",
113
+ "election_years"=>[1992],
114
+ "party"=>"DEM",
115
+ "office"=>"H",
116
+ "candidate_status_full"=>"Statutory candidate in a prior cycle",
117
+ "state"=>"NJ",
118
+ "incumbent_challenge"=>nil,
119
+ "party_full"=>"Democratic Party",
120
+ "office_full"=>"House",
121
+ "candidate_id"=>"H2NJ12036",
122
+ "name"=>"ABATE, FRANK G",
123
+ "cycles"=>[1992]},
124
+ {"candidate_status"=>"C",
125
+ "active_through"=>1990,
126
+ "incumbent_challenge_full"=>"Unknown",
127
+ "district"=>"03",
128
+ "election_years"=>[1990],
129
+ "party"=>"REP",
130
+ "office"=>"H",
131
+ "candidate_status_full"=>"Statutory candidate",
132
+ "state"=>"IA",
133
+ "incumbent_challenge"=>nil,
134
+ "party_full"=>"Republican Party",
135
+ "office_full"=>"House",
136
+ "candidate_id"=>"H0IA03071",
137
+ "name"=>"ABBAS, JEFFREY LYN",
138
+ "cycles"=>[1990]},
139
+ {"candidate_status"=>"C",
140
+ "active_through"=>1994,
141
+ "incumbent_challenge_full"=>"Unknown",
142
+ "district"=>"15",
143
+ "election_years"=>[1994],
144
+ "party"=>"REP",
145
+ "office"=>"H",
146
+ "candidate_status_full"=>"Statutory candidate",
147
+ "state"=>"TX",
148
+ "incumbent_challenge"=>nil,
149
+ "party_full"=>"Republican Party",
150
+ "office_full"=>"House",
151
+ "candidate_id"=>"H4TX15043",
152
+ "name"=>"ABBOTT, BONNIE",
153
+ "cycles"=>[1994]},
154
+ {"candidate_status"=>"N",
155
+ "active_through"=>2016,
156
+ "incumbent_challenge_full"=>"Open seat",
157
+ "district"=>nil,
158
+ "election_years"=>[2016],
159
+ "party"=>"IND",
160
+ "office"=>"P",
161
+ "candidate_status_full"=>"Not yet a statutory candidate",
162
+ "state"=>"US",
163
+ "incumbent_challenge"=>"O",
164
+ "party_full"=>"Independent",
165
+ "office_full"=>"President",
166
+ "candidate_id"=>"P60005840",
167
+ "name"=>"ABBOTT, GIFFORD WHEELER JR",
168
+ "cycles"=>[2016]},
169
+ {"candidate_status"=>"P",
170
+ "active_through"=>1996,
171
+ "incumbent_challenge_full"=>"Challenger",
172
+ "district"=>"00",
173
+ "election_years"=>[1996],
174
+ "party"=>"DEM",
175
+ "office"=>"H",
176
+ "candidate_status_full"=>"Statutory candidate in a prior cycle",
177
+ "state"=>"SD",
178
+ "incumbent_challenge"=>"C",
179
+ "party_full"=>"Democratic Party",
180
+ "office_full"=>"House",
181
+ "candidate_id"=>"H6SD00077",
182
+ "name"=>"ABBOTT, JAMES W",
183
+ "cycles"=>[1996]},
184
+ {"candidate_status"=>"P",
185
+ "active_through"=>1992,
186
+ "incumbent_challenge_full"=>"Unknown",
187
+ "district"=>nil,
188
+ "election_years"=>[1988, 1992],
189
+ "party"=>"DEM",
190
+ "office"=>"P",
191
+ "candidate_status_full"=>"Statutory candidate in a prior cycle",
192
+ "state"=>"US",
193
+ "incumbent_challenge"=>nil,
194
+ "party_full"=>"Democratic Party",
195
+ "office_full"=>"President",
196
+ "candidate_id"=>"P80002579",
197
+ "name"=>"ABBOTT, JOHN HANCOCK",
198
+ "cycles"=>[1992]},
199
+ {"candidate_status"=>"N",
200
+ "active_through"=>1988,
201
+ "incumbent_challenge_full"=>"Unknown",
202
+ "district"=>nil,
203
+ "election_years"=>[1986, 1988],
204
+ "party"=>"DEM",
205
+ "office"=>"S",
206
+ "candidate_status_full"=>"Not yet a statutory candidate",
207
+ "state"=>"CA",
208
+ "incumbent_challenge"=>nil,
209
+ "party_full"=>"Democratic Party",
210
+ "office_full"=>"Senate",
211
+ "candidate_id"=>"S6CA00345",
212
+ "name"=>"ABBOTT, JOHN HANCOCK",
213
+ "cycles"=>[1986]},
214
+ {"candidate_status"=>"T",
215
+ "active_through"=>2004,
216
+ "incumbent_challenge_full"=>"Unknown",
217
+ "district"=>"18",
218
+ "election_years"=>[2002, 2004],
219
+ "party"=>"REP",
220
+ "office"=>"H",
221
+ "candidate_status_full"=>"Obsolete",
222
+ "state"=>"TX",
223
+ "incumbent_challenge"=>nil,
224
+ "party_full"=>"Republican Party",
225
+ "office_full"=>"House",
226
+ "candidate_id"=>"H2TX18082",
227
+ "name"=>"ABBOTT, PHILLIP J.",
228
+ "cycles"=>[2002, 2004]},
229
+ {"candidate_status"=>"P",
230
+ "active_through"=>2000,
231
+ "incumbent_challenge_full"=>"Unknown",
232
+ "district"=>"03",
233
+ "election_years"=>[1994, 1996, 2000],
234
+ "party"=>"DEM",
235
+ "office"=>"H",
236
+ "candidate_status_full"=>"Statutory candidate in a prior cycle",
237
+ "state"=>"KY",
238
+ "incumbent_challenge"=>nil,
239
+ "party_full"=>"Democratic Party",
240
+ "office_full"=>"House",
241
+ "candidate_id"=>"H4KY03095",
242
+ "name"=>"ABBOTT, RAYMOND H",
243
+ "cycles"=>[1994, 1996, 1998, 2000]},
244
+ {"candidate_status"=>"N",
245
+ "active_through"=>2014,
246
+ "incumbent_challenge_full"=>"Challenger",
247
+ "district"=>"03",
248
+ "election_years"=>[2014],
249
+ "party"=>"DEM",
250
+ "office"=>"H",
251
+ "candidate_status_full"=>"Not yet a statutory candidate",
252
+ "state"=>"MI",
253
+ "incumbent_challenge"=>"C",
254
+ "party_full"=>"Democratic Party",
255
+ "office_full"=>"House",
256
+ "candidate_id"=>"H4MI03201",
257
+ "name"=>"ABBOTT, RICHARD ALLEN IV",
258
+ "cycles"=>[2014]},
259
+ {"candidate_status"=>"P",
260
+ "active_through"=>2004,
261
+ "incumbent_challenge_full"=>"Unknown",
262
+ "district"=>"04",
263
+ "election_years"=>[2002, 2004],
264
+ "party"=>"DEM",
265
+ "office"=>"H",
266
+ "candidate_status_full"=>"Statutory candidate in a prior cycle",
267
+ "state"=>"IN",
268
+ "incumbent_challenge"=>nil,
269
+ "party_full"=>"Democratic Party",
270
+ "office_full"=>"House",
271
+ "candidate_id"=>"H2IN04101",
272
+ "name"=>"ABBOTT, WILLIAM ANTHONY",
273
+ "cycles"=>[2002, 2004]},
274
+ {"candidate_status"=>"P",
275
+ "active_through"=>1988,
276
+ "incumbent_challenge_full"=>"Challenger",
277
+ "district"=>"02",
278
+ "election_years"=>[1988],
279
+ "party"=>"REP",
280
+ "office"=>"H",
281
+ "candidate_status_full"=>"Statutory candidate in a prior cycle",
282
+ "state"=>"NE",
283
+ "incumbent_challenge"=>"C",
284
+ "party_full"=>"Republican Party",
285
+ "office_full"=>"House",
286
+ "candidate_id"=>"H8NE02089",
287
+ "name"=>"ABBOUD, CHRIS",
288
+ "cycles"=>[1988]},
289
+ {"candidate_status"=>"C",
290
+ "active_through"=>2008,
291
+ "incumbent_challenge_full"=>"Challenger",
292
+ "district"=>"16",
293
+ "election_years"=>[2008],
294
+ "party"=>"DEM",
295
+ "office"=>"H",
296
+ "candidate_status_full"=>"Statutory candidate",
297
+ "state"=>"IL",
298
+ "incumbent_challenge"=>"C",
299
+ "party_full"=>"Democratic Party",
300
+ "office_full"=>"House",
301
+ "candidate_id"=>"H8IL16062",
302
+ "name"=>"ABBOUD, ROBERT",
303
+ "cycles"=>[2008]}]}
@@ -0,0 +1,3 @@
1
+ {"error"=>
2
+ {"code"=>"OVER_RATE_LIMIT",
3
+ "message"=>"You have exceeded your rate limit. Try again later or contact us at https://api.open.fec.gov/contact for assistance"}}
@@ -0,0 +1,53 @@
1
+ require 'spec_helper'
2
+
3
+ module OpenFecApi
4
+ RSpec.describe Client do
5
+ describe '#candidates' do
6
+ context 'when configured' do
7
+ before do
8
+ @client = OpenFecApi::Client.new(ENV["OPEN_FEC_API_KEY"])
9
+ end
10
+
11
+ def request_and_print(options)
12
+ response = @client.candidates(options)
13
+ pp response.summary
14
+ return response
15
+ end
16
+
17
+ it "is configured" do
18
+ expect(@client.configured?)
19
+ end
20
+
21
+ it "returns responses" do
22
+ response = @client.candidates
23
+ expect(response).to be_kind_of(OpenFecApi::Response)
24
+ end
25
+
26
+ it "accepts pagination options and avoids rate limits" do
27
+ options = {:page => 1, :per_page => 100}
28
+ response = request_and_print(options)
29
+ expect(response.results_count).to eql(100)
30
+ while response.page < response.pages && response.page < 5 do
31
+ options.merge!({:page => response.page + 1})
32
+ response = request_and_print(options)
33
+ end
34
+ success = true
35
+ expect(success)
36
+ end
37
+
38
+ it "accepts endpoint-specific options" do
39
+ options = {:party => "DEM"}
40
+ response = request_and_print(options)
41
+ expect(response.results.map{|c| c["party"]}.uniq).to eql(["DEM"])
42
+ end
43
+
44
+ it "prevents unrecognized params from being requested" do
45
+ unrecognized_params = {:hair_color => "brown"}
46
+ response = request_and_print(unrecognized_params)
47
+ recognized_params = response.request_query
48
+ expect(!recognized_params.keys.include?("hair_color"))
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,100 @@
1
+ $LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
2
+ require 'open_fec_api'
3
+ require 'pry'
4
+
5
+ # This file was generated by the `rspec --init` command. Conventionally, all
6
+ # specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
7
+ # The generated `.rspec` file contains `--require spec_helper` which will cause
8
+ # this file to always be loaded, without a need to explicitly require it in any
9
+ # files.
10
+ #
11
+ # Given that it is always loaded, you are encouraged to keep this file as
12
+ # light-weight as possible. Requiring heavyweight dependencies from this file
13
+ # will add to the boot time of your test suite on EVERY test run, even for an
14
+ # individual file that may not need all of that loaded. Instead, consider making
15
+ # a separate helper file that requires the additional dependencies and performs
16
+ # the additional setup, and require it from the spec files that actually need
17
+ # it.
18
+ #
19
+ # The `.rspec` file also contains a few flags that are not defaults but that
20
+ # users commonly want.
21
+ #
22
+ # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
23
+ RSpec.configure do |config|
24
+ # rspec-expectations config goes here. You can use an alternate
25
+ # assertion/expectation library such as wrong or the stdlib/minitest
26
+ # assertions if you prefer.
27
+ config.expect_with :rspec do |expectations|
28
+ # This option will default to `true` in RSpec 4. It makes the `description`
29
+ # and `failure_message` of custom matchers include text for helper methods
30
+ # defined using `chain`, e.g.:
31
+ # be_bigger_than(2).and_smaller_than(4).description
32
+ # # => "be bigger than 2 and smaller than 4"
33
+ # ...rather than:
34
+ # # => "be bigger than 2"
35
+ expectations.include_chain_clauses_in_custom_matcher_descriptions = true
36
+ end
37
+
38
+ # rspec-mocks config goes here. You can use an alternate test double
39
+ # library (such as bogus or mocha) by changing the `mock_with` option here.
40
+ config.mock_with :rspec do |mocks|
41
+ # Prevents you from mocking or stubbing a method that does not exist on
42
+ # a real object. This is generally recommended, and will default to
43
+ # `true` in RSpec 4.
44
+ mocks.verify_partial_doubles = true
45
+ end
46
+
47
+ # The settings below are suggested to provide a good initial experience
48
+ # with RSpec, but feel free to customize to your heart's content.
49
+ =begin
50
+ # These two settings work together to allow you to limit a spec run
51
+ # to individual examples or groups you care about by tagging them with
52
+ # `:focus` metadata. When nothing is tagged with `:focus`, all examples
53
+ # get run.
54
+ config.filter_run :focus
55
+ config.run_all_when_everything_filtered = true
56
+
57
+ # Allows RSpec to persist some state between runs in order to support
58
+ # the `--only-failures` and `--next-failure` CLI options. We recommend
59
+ # you configure your source control system to ignore this file.
60
+ config.example_status_persistence_file_path = "spec/examples.txt"
61
+
62
+ # Limits the available syntax to the non-monkey patched syntax that is
63
+ # recommended. For more details, see:
64
+ # - http://myronmars.to/n/dev-blog/2012/06/rspecs-new-expectation-syntax
65
+ # - http://www.teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/
66
+ # - http://myronmars.to/n/dev-blog/2014/05/notable-changes-in-rspec-3#new__config_option_to_disable_rspeccore_monkey_patching
67
+ config.disable_monkey_patching!
68
+
69
+ # This setting enables warnings. It's recommended, but in some cases may
70
+ # be too noisy due to issues in dependencies.
71
+ config.warnings = true
72
+
73
+ # Many RSpec users commonly either run the entire suite or an individual
74
+ # file, and it's useful to allow more verbose output when running an
75
+ # individual spec file.
76
+ if config.files_to_run.one?
77
+ # Use the documentation formatter for detailed output,
78
+ # unless a formatter has already been configured
79
+ # (e.g. via a command-line flag).
80
+ config.default_formatter = 'doc'
81
+ end
82
+
83
+ # Print the 10 slowest examples and example groups at the
84
+ # end of the spec run, to help surface which specs are running
85
+ # particularly slow.
86
+ config.profile_examples = 10
87
+
88
+ # Run specs in random order to surface order dependencies. If you find an
89
+ # order dependency and want to debug it, you can fix the order by providing
90
+ # the seed, which is printed after each run.
91
+ # --seed 1234
92
+ config.order = :random
93
+
94
+ # Seed global randomization in this process using the `--seed` CLI option.
95
+ # Setting this allows you to use `--seed` to deterministically reproduce
96
+ # test failures related to randomization by passing the same `--seed` value
97
+ # as the one that triggered the failure.
98
+ Kernel.srand config.seed
99
+ =end
100
+ end
metadata ADDED
@@ -0,0 +1,137 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: open_fec_api
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - MJ Rossetti (@s2t2)
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-07-25 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.7'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.7'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '3.1'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '3.1'
55
+ - !ruby/object:Gem::Dependency
56
+ name: pry
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '0.10'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '0.10'
69
+ - !ruby/object:Gem::Dependency
70
+ name: httparty
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '0.13'
76
+ type: :runtime
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '0.13'
83
+ description: A ruby wrapper for 18F's [Open FEC (Federal Elections Commission) API](https://api.open.fec.gov/).
84
+ email:
85
+ - s2t2mail@gmail.com
86
+ executables:
87
+ - console
88
+ - setup
89
+ extensions: []
90
+ extra_rdoc_files: []
91
+ files:
92
+ - ".gitignore"
93
+ - ".rspec"
94
+ - CREDITS.md
95
+ - ENDPOINTS.md
96
+ - Gemfile
97
+ - LICENSE.txt
98
+ - README.md
99
+ - Rakefile
100
+ - bin/console
101
+ - bin/setup
102
+ - lib/open_fec_api.rb
103
+ - lib/open_fec_api/client.rb
104
+ - lib/open_fec_api/response.rb
105
+ - lib/open_fec_api/version.rb
106
+ - open_fec_api.gemspec
107
+ - reponse_examples/candidates.rb
108
+ - reponse_examples/over_rate_limit.rb
109
+ - spec/client_spec.rb
110
+ - spec/spec_helper.rb
111
+ homepage: https://github.com/debate-watch/open_fec_api/
112
+ licenses:
113
+ - MIT
114
+ metadata: {}
115
+ post_install_message:
116
+ rdoc_options: []
117
+ require_paths:
118
+ - lib
119
+ required_ruby_version: !ruby/object:Gem::Requirement
120
+ requirements:
121
+ - - ">="
122
+ - !ruby/object:Gem::Version
123
+ version: '0'
124
+ required_rubygems_version: !ruby/object:Gem::Requirement
125
+ requirements:
126
+ - - ">="
127
+ - !ruby/object:Gem::Version
128
+ version: '0'
129
+ requirements: []
130
+ rubyforge_project:
131
+ rubygems_version: 2.4.5
132
+ signing_key:
133
+ specification_version: 4
134
+ summary: A ruby wrapper for 18F's [Open FEC (Federal Elections Commission) API](https://api.open.fec.gov/).
135
+ test_files:
136
+ - spec/client_spec.rb
137
+ - spec/spec_helper.rb