pyr 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +12 -0
- data/.rspec +2 -0
- data/.rubocop.yml +8 -0
- data/Gemfile +13 -0
- data/LICENSE.txt +21 -0
- data/README.md +130 -0
- data/Rakefile +4 -0
- data/bin/console +15 -0
- data/bin/setup +8 -0
- data/lib/pyr.rb +50 -0
- data/lib/pyr/param.rb +25 -0
- data/lib/pyr/parser.rb +32 -0
- data/lib/pyr/request.rb +16 -0
- data/lib/pyr/resource.rb +27 -0
- data/lib/pyr/resources/districts.rb +9 -0
- data/lib/pyr/resources/office_locations.rb +9 -0
- data/lib/pyr/resources/reps.rb +30 -0
- data/lib/pyr/resources/states.rb +9 -0
- data/lib/pyr/resources/zctas.rb +18 -0
- data/lib/pyr/response.rb +41 -0
- data/lib/pyr/response_object.rb +28 -0
- data/lib/pyr/response_objects/district.rb +9 -0
- data/lib/pyr/response_objects/office_location.rb +35 -0
- data/lib/pyr/response_objects/rep.rb +42 -0
- data/lib/pyr/response_objects/state.rb +9 -0
- data/lib/pyr/response_objects/zcta.rb +11 -0
- data/lib/pyr/version.rb +5 -0
- data/pyr.gemspec +44 -0
- metadata +118 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: e9e59c224c843ca67e681e5f25ccc13da61ec142
|
4
|
+
data.tar.gz: 564cf7a0cc20981bb4b49df434b50ecca8ef19f1
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 0a19050c771961098b9af8875f09f2aa6b54b375fa15e26cf7577cd2e90a915cd09af1d5f63397f8ebd179137c330ca042e95091aa8641de60b8830357aaeed6
|
7
|
+
data.tar.gz: f562c9bce4f3315679278482753268fe4f7ea0b63eb141d007e7fe45bc8fbdb8e45ae52df9e91d107f74b56d180e1bb4a027318ff4908b52d9c8a08915369aea
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.rubocop.yml
ADDED
data/Gemfile
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
source 'https://rubygems.org'
|
4
|
+
|
5
|
+
# Specify your gem's dependencies in pyr.gemspec
|
6
|
+
gemspec
|
7
|
+
|
8
|
+
group :test, :development do
|
9
|
+
gem 'pry', '~> 0.10.0'
|
10
|
+
gem 'rake', '~> 10.0'
|
11
|
+
gem 'rspec', '~> 3.5.0'
|
12
|
+
gem 'rubocop', '~> 0.48.0'
|
13
|
+
end
|
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2017 M. Simon Borg
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,130 @@
|
|
1
|
+
# PYR
|
2
|
+
[![Code Climate](https://codeclimate.com/github/msimonborg/pyr/badges/gpa.svg)](https://codeclimate.com/github/msimonborg/pyr)
|
3
|
+
|
4
|
+
PYR makes integrating data from the Phone Your Rep API into your Ruby project as easy as pie.
|
5
|
+
|
6
|
+
## Installation
|
7
|
+
|
8
|
+
Add this line to your application's Gemfile:
|
9
|
+
|
10
|
+
```ruby
|
11
|
+
gem 'pyr'
|
12
|
+
```
|
13
|
+
|
14
|
+
And then execute:
|
15
|
+
|
16
|
+
$ bundle
|
17
|
+
|
18
|
+
Or install it yourself as:
|
19
|
+
|
20
|
+
$ gem install pyr
|
21
|
+
|
22
|
+
## Usage
|
23
|
+
|
24
|
+
### Querying by location
|
25
|
+
```ruby
|
26
|
+
response = PYR.call :reps do |r|
|
27
|
+
r.lat = 44.5588028
|
28
|
+
r.long = -72.57784149999999
|
29
|
+
end
|
30
|
+
|
31
|
+
## or ##
|
32
|
+
|
33
|
+
response = PYR.call(:reps) do { |r| r.address = 'Vermont' }
|
34
|
+
|
35
|
+
response.uri
|
36
|
+
=> "https://phone-your-rep.herokuapp.com/api/beta/reps?lat=44.5588028&long=-72.57784149999999&"
|
37
|
+
|
38
|
+
response.code
|
39
|
+
=> 200
|
40
|
+
|
41
|
+
response.message
|
42
|
+
=> "OK"
|
43
|
+
|
44
|
+
response.headers
|
45
|
+
=> { ... }
|
46
|
+
|
47
|
+
response.body
|
48
|
+
=> { ... }
|
49
|
+
|
50
|
+
reps = response.objects
|
51
|
+
=> #<PYR::RepRelation [#<PYR::Rep id: 1, ...>]>
|
52
|
+
|
53
|
+
reps.first.official_full
|
54
|
+
=> "Bernard Sanders"
|
55
|
+
|
56
|
+
reps.first.office_locations_count
|
57
|
+
=> 3
|
58
|
+
|
59
|
+
reps.first.office_locations.first.city
|
60
|
+
=> "St. Johnsbury"
|
61
|
+
```
|
62
|
+
|
63
|
+
### Query the full index and narrowing with scopes
|
64
|
+
```ruby
|
65
|
+
response = PYR.call :reps
|
66
|
+
|
67
|
+
reps = response.objects
|
68
|
+
|
69
|
+
reps.count
|
70
|
+
=> 536
|
71
|
+
|
72
|
+
reps.democratic.count
|
73
|
+
=> 243
|
74
|
+
|
75
|
+
reps.senators.count
|
76
|
+
=> 100
|
77
|
+
|
78
|
+
reps.democratic.senators.count
|
79
|
+
=> 46
|
80
|
+
|
81
|
+
reps.where official_full: 'Bernard Sanders'
|
82
|
+
=> #<PYR::RepRelation [#<PYR::Rep id: 435, self: "https://phone-your-rep.herokuapp.com/api/beta/reps/S000033", state: {"self"=>"https://phone-your-rep.herokuapp.com/states/50", "state_code"=>"50", "name"=>"Vermont", "abbr"=>"VT"}, district: nil, active: true, bioguide_id: "S000033", official_full: "Bernard Sanders", role: "United States Senator", party: "Independent", senate_class: "01", last: "Sanders", first: "Bernard", middle: nil, nickname: "Bernie", suffix: nil, contact_form: "http://www.sanders.senate.gov/contact/", url: "https://www.sanders.senate.gov", photo: "https://phoneyourrep.github.io/images/congress/450x550/S000033.jpg", twitter: "SenSanders", facebook: "senatorsanders", youtube: "senatorsanders", instagram: nil, googleplus: nil, twitter_id: "29442313", facebook_id: nil, youtube_id: "UCD_DaKNac0Ta-2PeHuoQ1uA", instagram_id: nil, office_locations_count: 3>]>
|
83
|
+
|
84
|
+
reps.independent.where { |r| r.state['name'] == 'Vermont' }.first
|
85
|
+
=> #<PYR::Rep id: 435, self: "https://phone-your-rep.herokuapp.com/api/beta/reps/S000033", state: {"self"=>"https://phone-your-rep.herokuapp.com/states/50", "state_code"=>"50", "name"=>"Vermont", "abbr"=>"VT"}, district: nil, active: true, bioguide_id: "S000033", official_full: "Bernard Sanders", role: "United States Senator", party: "Independent", senate_class: "01", last: "Sanders", first: "Bernard", middle: nil, nickname: "Bernie", suffix: nil, contact_form: "http://www.sanders.senate.gov/contact/", url: "https://www.sanders.senate.gov", photo: "https://phoneyourrep.github.io/images/congress/450x550/S000033.jpg", twitter: "SenSanders", facebook: "senatorsanders", youtube: "senatorsanders", instagram: nil, googleplus: nil, twitter_id: "29442313", facebook_id: nil, youtube_id: "UCD_DaKNac0Ta-2PeHuoQ1uA", instagram_id: nil, office_locations_count: 3>
|
86
|
+
```
|
87
|
+
|
88
|
+
### Querying by ID
|
89
|
+
```ruby
|
90
|
+
bernie = PYR.call(:reps, 'S000033').objects.first
|
91
|
+
=> #<PYR::Rep ... >
|
92
|
+
```
|
93
|
+
|
94
|
+
### Querying by Object
|
95
|
+
```ruby
|
96
|
+
office = PYR.call(:reps, 'S000033').objects.first.office_locations.district.first
|
97
|
+
=> #<PYR::OfficeLocation id: 1, city: "Burlington", rep: "https://phone-your-rep.herokuapp.com/api/beta/reps/S000033", active: true, office_id: "S000033-burlington", bioguide_id: "S000033", office_type: "district", distance: nil, building: "", address: "1 Church St.", suite: "3rd Floor", city: "Burlington", state: "VT", zip: "05401", phone: "802-862-0697", fax: "802-860-6370", hours: "", latitude: 44.4802081, longitude: -73.2130702, v_card_link: "https://phone-your-rep.herokuapp.com/v_cards/S000033-burlington", downloads: 14, qr_code_link: "https://s3.amazonaws.com/phone-your-rep-images/S000033_burlington.png">
|
98
|
+
|
99
|
+
# Pass in the object itself as the param to PYR.call
|
100
|
+
office.office_id == PYR.call(office).objects.first.office_id
|
101
|
+
=> true
|
102
|
+
```
|
103
|
+
|
104
|
+
### Querying by Phone Your Rep URI
|
105
|
+
```ruby
|
106
|
+
rep = PYR.call(:reps) { |r| r.address = 'vermont' }.objects.representatives.first
|
107
|
+
|
108
|
+
uri = rep.district['self']
|
109
|
+
=> "https://phone-your-rep.herokuapp.com/api/beta/districts/5000"
|
110
|
+
|
111
|
+
district = PYR.call(uri).objects.first
|
112
|
+
|
113
|
+
=> #<PYR::District id: 2, self: "https://phone-your-rep.herokuapp.com/api/beta/districts/5000", full_code: "5000", code: "00", state_code: "50">
|
114
|
+
```
|
115
|
+
|
116
|
+
## Development
|
117
|
+
|
118
|
+
After checking out the repo, run `bin/setup` to install dependencies. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
|
119
|
+
|
120
|
+
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and 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).
|
121
|
+
|
122
|
+
## Contributing
|
123
|
+
|
124
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/msimonborg/pyr.
|
125
|
+
|
126
|
+
|
127
|
+
## License
|
128
|
+
|
129
|
+
The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
|
130
|
+
|
data/Rakefile
ADDED
data/bin/console
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require 'bundler/setup'
|
5
|
+
require 'pyr'
|
6
|
+
|
7
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
8
|
+
# with your gem easier. You can also use a different console, if you like.
|
9
|
+
|
10
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
11
|
+
require 'pry'
|
12
|
+
Pry.start
|
13
|
+
|
14
|
+
# require 'irb'
|
15
|
+
# IRB.start(__FILE__)
|
data/bin/setup
ADDED
data/lib/pyr.rb
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'pyr/param'
|
4
|
+
require 'pyr/parser'
|
5
|
+
require 'pyr/resource'
|
6
|
+
require 'pyr/resources/districts'
|
7
|
+
require 'pyr/resources/office_locations'
|
8
|
+
require 'pyr/resources/reps'
|
9
|
+
require 'pyr/resources/states'
|
10
|
+
require 'pyr/resources/zctas'
|
11
|
+
require 'pyr/response'
|
12
|
+
require 'pyr/response_object'
|
13
|
+
require 'pyr/response_objects/district'
|
14
|
+
require 'pyr/response_objects/office_location'
|
15
|
+
require 'pyr/response_objects/rep'
|
16
|
+
require 'pyr/response_objects/state'
|
17
|
+
require 'pyr/response_objects/zcta'
|
18
|
+
require 'pyr/request'
|
19
|
+
require 'pyr/version'
|
20
|
+
|
21
|
+
# PYR provides an easy interface to the Phone Your Rep API,
|
22
|
+
# converting the data payloads into Plain Old Ruby Objects.
|
23
|
+
module PYR
|
24
|
+
API_BASE_URL = 'https://phone-your-rep.herokuapp.com/api/beta/'
|
25
|
+
|
26
|
+
PYR_RESOURCES = %i[
|
27
|
+
reps
|
28
|
+
office_locations
|
29
|
+
states
|
30
|
+
districts
|
31
|
+
zctas
|
32
|
+
].freeze
|
33
|
+
|
34
|
+
ActiveSupport::Inflector.inflections do |inflect|
|
35
|
+
inflect.irregular 'zcta', 'zctas'
|
36
|
+
end
|
37
|
+
|
38
|
+
def self.call(resource, id = nil)
|
39
|
+
if resource.is_a?(ResponseObject)
|
40
|
+
request_object = { response_object: resource }
|
41
|
+
elsif resource.to_s.include? API_BASE_URL
|
42
|
+
request_object = { base_url: resource }
|
43
|
+
else
|
44
|
+
resource = Request.build(resource, id)
|
45
|
+
yield resource if block_given?
|
46
|
+
request_object = { base_url: API_BASE_URL, resource: resource }
|
47
|
+
end
|
48
|
+
Response.new request_object
|
49
|
+
end
|
50
|
+
end
|
data/lib/pyr/param.rb
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module PYR
|
4
|
+
# Handles string conversion for request params.
|
5
|
+
# Will handle the conversion differently depending on if
|
6
|
+
# it is an ID param e.g. controller/:id
|
7
|
+
class Param
|
8
|
+
attr_reader :name, :value
|
9
|
+
|
10
|
+
def initialize(name, value, id: nil)
|
11
|
+
@id = id == true ? true : false
|
12
|
+
@name = name
|
13
|
+
@value = value
|
14
|
+
end
|
15
|
+
|
16
|
+
def id?
|
17
|
+
@id
|
18
|
+
end
|
19
|
+
|
20
|
+
def to_s
|
21
|
+
url_value = value.to_s.tr('#;\'""', '').gsub(' ', '%20')
|
22
|
+
id? ? "/#{value}" : "#{name}=#{url_value}&"
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
data/lib/pyr/parser.rb
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
module PYR
|
5
|
+
# Parses the response body and returns an array of response_objects.
|
6
|
+
module Parser
|
7
|
+
def self.parse(body, controller)
|
8
|
+
if body.keys.first == 'self'
|
9
|
+
klass = "PYR::#{controller.to_s.classify}".constantize
|
10
|
+
LazyRecord::Relation.new model: klass, array: [klass.new(body)]
|
11
|
+
else
|
12
|
+
reduce_body(body)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.reduce_body(body)
|
17
|
+
body.reduce([]) do |memo, (key, value)|
|
18
|
+
if PYR_RESOURCES.include?(key.to_sym)
|
19
|
+
convert_to_relation(key, memo, value)
|
20
|
+
else
|
21
|
+
memo
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.convert_to_relation(resource, memo, value)
|
27
|
+
klass = "PYR::#{resource.classify}".constantize
|
28
|
+
LazyRecord::Relation.new model: klass,
|
29
|
+
array: memo + value.map { |val| klass.new(val) }
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
data/lib/pyr/request.rb
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module PYR
|
4
|
+
# The Request module determines based on the :resource parameter which
|
5
|
+
# Resource subclass to call for constructing the query to the API, and
|
6
|
+
# returns an instance of that class.
|
7
|
+
module Request
|
8
|
+
def self.build(resource, id = nil)
|
9
|
+
new_resource(resource, id) if PYR_RESOURCES.include?(resource.to_sym)
|
10
|
+
end
|
11
|
+
|
12
|
+
def self.new_resource(resource, id)
|
13
|
+
"PYR::Resource::#{resource.to_s.camelize}".constantize.new(resource, id)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
data/lib/pyr/resource.rb
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module PYR
|
4
|
+
# Resource and its subclasses accept attribute params and,
|
5
|
+
# in conjunction with the Param class,
|
6
|
+
# convert them to a URI friendly string
|
7
|
+
class Resource
|
8
|
+
attr_reader :id, :controller
|
9
|
+
|
10
|
+
def initialize(controller, id)
|
11
|
+
@controller = controller
|
12
|
+
self.id = id
|
13
|
+
end
|
14
|
+
|
15
|
+
def id=(value)
|
16
|
+
@id = Param.new(:id, value, id: true) if value
|
17
|
+
end
|
18
|
+
|
19
|
+
def to_s
|
20
|
+
"#{controller}#{params}"
|
21
|
+
end
|
22
|
+
|
23
|
+
def params
|
24
|
+
"#{id}?"
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module PYR
|
4
|
+
class Resource
|
5
|
+
# Request object for sending requests to the /reps resource of the API
|
6
|
+
class Reps < Resource
|
7
|
+
attr_reader :lat, :long, :address, :generate
|
8
|
+
|
9
|
+
def params
|
10
|
+
"#{id}?#{lat}#{long}#{address}#{generate}"
|
11
|
+
end
|
12
|
+
|
13
|
+
def lat=(value)
|
14
|
+
@lat = Param.new(:lat, value)
|
15
|
+
end
|
16
|
+
|
17
|
+
def long=(value)
|
18
|
+
@long = Param.new(:long, value)
|
19
|
+
end
|
20
|
+
|
21
|
+
def address=(value)
|
22
|
+
@address = Param.new(:address, value)
|
23
|
+
end
|
24
|
+
|
25
|
+
def generate=(value)
|
26
|
+
@generate = Param.new(:generate, value)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module PYR
|
4
|
+
class Resource
|
5
|
+
# Request object for sending requests to the /zctas resource of the API
|
6
|
+
class Zctas < Resource
|
7
|
+
attr_reader :reps
|
8
|
+
|
9
|
+
def params
|
10
|
+
"#{id}?#{reps}"
|
11
|
+
end
|
12
|
+
|
13
|
+
def reps=(value)
|
14
|
+
@reps = Param.new(:reps, value)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
data/lib/pyr/response.rb
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'httparty'
|
4
|
+
|
5
|
+
module PYR
|
6
|
+
# The object returned by a request call to the API.
|
7
|
+
class Response
|
8
|
+
attr_reader :body, :uri, :code, :message, :headers, :objects, :controller
|
9
|
+
|
10
|
+
def initialize(base_url: nil, resource: nil, response_object: nil)
|
11
|
+
assign_url_and_controller(base_url, resource, response_object)
|
12
|
+
fetch_and_parse_payload
|
13
|
+
parse_objects
|
14
|
+
end
|
15
|
+
|
16
|
+
def assign_url_and_controller(base_url, resource, response_object)
|
17
|
+
if base_url && resource
|
18
|
+
@controller = resource.controller
|
19
|
+
@uri = "#{base_url}#{resource}"
|
20
|
+
elsif base_url
|
21
|
+
@controller = base_url.sub(API_BASE_URL, '').split('/').first
|
22
|
+
@uri = base_url
|
23
|
+
elsif response_object
|
24
|
+
@controller = response_object.controller
|
25
|
+
@uri = response_object.self
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def fetch_and_parse_payload
|
30
|
+
payload = HTTParty.get uri
|
31
|
+
@body = payload.parsed_response
|
32
|
+
@code = payload.code
|
33
|
+
@message = payload.message
|
34
|
+
@headers = payload.headers
|
35
|
+
end
|
36
|
+
|
37
|
+
def parse_objects
|
38
|
+
@objects = Parser.parse(body, controller)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'lazy_record'
|
4
|
+
|
5
|
+
module PYR
|
6
|
+
# The ResponseObject is the parent class of all objects instantiated
|
7
|
+
# from the response body.
|
8
|
+
class ResponseObject < LazyRecord::Base
|
9
|
+
def initialize(opts = {})
|
10
|
+
new_opts = opts.each_with_object({}) do |(key, val), memo|
|
11
|
+
memo[key] = if PYR_RESOURCES.include?(key.to_sym)
|
12
|
+
objectify(key, val)
|
13
|
+
else
|
14
|
+
val
|
15
|
+
end
|
16
|
+
end
|
17
|
+
super(new_opts)
|
18
|
+
end
|
19
|
+
|
20
|
+
def objectify(name, array)
|
21
|
+
array.map { |obj| "PYR::#{name.classify}".constantize.new(obj) }
|
22
|
+
end
|
23
|
+
|
24
|
+
def controller
|
25
|
+
@controller ||= self.class.to_s.split('::').last.tableize
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
module PYR
|
5
|
+
# The OfficeLocation is the response object that carries the data
|
6
|
+
# for a single office location, which in turn is associated to a
|
7
|
+
# rep in a `:rep has_many :office_locations` relationship.
|
8
|
+
class OfficeLocation < ResponseObject
|
9
|
+
lr_attr_accessor :self,
|
10
|
+
:city,
|
11
|
+
:rep,
|
12
|
+
:active,
|
13
|
+
:office_id,
|
14
|
+
:bioguide_id,
|
15
|
+
:office_type,
|
16
|
+
:distance,
|
17
|
+
:building,
|
18
|
+
:address,
|
19
|
+
:suite,
|
20
|
+
:city,
|
21
|
+
:state,
|
22
|
+
:zip,
|
23
|
+
:phone,
|
24
|
+
:fax,
|
25
|
+
:hours,
|
26
|
+
:latitude,
|
27
|
+
:longitude,
|
28
|
+
:v_card_link,
|
29
|
+
:downloads,
|
30
|
+
:qr_code_link
|
31
|
+
|
32
|
+
lr_scope :capitol, -> { where office_type: 'capitol' }
|
33
|
+
lr_scope :district, -> { where office_type: 'district' }
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module PYR
|
4
|
+
# The Rep is the response object that carries the data for
|
5
|
+
# a single elected representative.
|
6
|
+
class Rep < ResponseObject
|
7
|
+
lr_has_many :office_locations
|
8
|
+
|
9
|
+
lr_scope :republican, -> { where party: 'Republican' }
|
10
|
+
lr_scope :democratic, -> { where party: 'Democrat' }
|
11
|
+
lr_scope :independent, -> { where party: 'Independent' }
|
12
|
+
lr_scope :senators, -> { where role: 'United States Senator' }
|
13
|
+
lr_scope :representatives, -> { where role: 'United States Representative' }
|
14
|
+
|
15
|
+
lr_attr_accessor :self,
|
16
|
+
:state,
|
17
|
+
:district,
|
18
|
+
:active,
|
19
|
+
:bioguide_id,
|
20
|
+
:official_full,
|
21
|
+
:role,
|
22
|
+
:party,
|
23
|
+
:senate_class,
|
24
|
+
:last,
|
25
|
+
:first,
|
26
|
+
:middle,
|
27
|
+
:nickname,
|
28
|
+
:suffix,
|
29
|
+
:contact_form,
|
30
|
+
:url,
|
31
|
+
:photo,
|
32
|
+
:twitter,
|
33
|
+
:facebook,
|
34
|
+
:youtube,
|
35
|
+
:instagram,
|
36
|
+
:googleplus,
|
37
|
+
:twitter_id,
|
38
|
+
:facebook_id,
|
39
|
+
:youtube_id,
|
40
|
+
:instagram_id
|
41
|
+
end
|
42
|
+
end
|
data/lib/pyr/version.rb
ADDED
data/pyr.gemspec
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
lib = File.expand_path('../lib', __FILE__)
|
5
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
6
|
+
require 'pyr/version'
|
7
|
+
|
8
|
+
Gem::Specification.new do |spec|
|
9
|
+
spec.name = 'pyr'
|
10
|
+
spec.version = PYR::VERSION
|
11
|
+
spec.authors = ['M. Simon Borg']
|
12
|
+
spec.email = ['msimonborg@gmail.com']
|
13
|
+
|
14
|
+
spec.summary = 'Make requests to the Phone Your Rep API and get '\
|
15
|
+
'Ruby objects in return'
|
16
|
+
spec.description = 'Wraps the Phone Your Rep API up with an idiomatic Ruby'\
|
17
|
+
' bow. Easily construct requests with block syntax and receive a response '\
|
18
|
+
'with http status, headers, raw body, and ActiveRecord-esque objects that '\
|
19
|
+
'make data-querying easy (using the lazy_record gem).'
|
20
|
+
spec.homepage = 'https://www.github.com/msimonborg/pyr'
|
21
|
+
spec.license = 'MIT'
|
22
|
+
|
23
|
+
# Prevent pushing this gem to RubyGems.org.
|
24
|
+
# To allow pushes either set the 'allowed_push_host'
|
25
|
+
# to allow pushing to a single host or delete this
|
26
|
+
# section to allow pushing to any host.
|
27
|
+
if spec.respond_to?(:metadata)
|
28
|
+
spec.metadata['allowed_push_host'] = 'https://rubygems.org'
|
29
|
+
else
|
30
|
+
raise 'RubyGems 2.0 or newer is required to protect against ' \
|
31
|
+
'public gem pushes.'
|
32
|
+
end
|
33
|
+
|
34
|
+
spec.files = `git ls-files -z`.split("\x0").reject do |f|
|
35
|
+
f.match(%r{^(test|spec|features|doc)/})
|
36
|
+
end
|
37
|
+
spec.bindir = 'exe'
|
38
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
39
|
+
spec.require_paths = ['lib']
|
40
|
+
|
41
|
+
spec.add_dependency 'httparty', '~> 0.14.0'
|
42
|
+
spec.add_dependency 'lazy_record', '~> 0.3.0'
|
43
|
+
spec.add_development_dependency 'bundler', '~> 1.14'
|
44
|
+
end
|
metadata
ADDED
@@ -0,0 +1,118 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: pyr
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- M. Simon Borg
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2017-04-10 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: httparty
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 0.14.0
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 0.14.0
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: lazy_record
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 0.3.0
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: 0.3.0
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: bundler
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '1.14'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '1.14'
|
55
|
+
description: Wraps the Phone Your Rep API up with an idiomatic Ruby bow. Easily construct
|
56
|
+
requests with block syntax and receive a response with http status, headers, raw
|
57
|
+
body, and ActiveRecord-esque objects that make data-querying easy (using the lazy_record
|
58
|
+
gem).
|
59
|
+
email:
|
60
|
+
- msimonborg@gmail.com
|
61
|
+
executables: []
|
62
|
+
extensions: []
|
63
|
+
extra_rdoc_files: []
|
64
|
+
files:
|
65
|
+
- ".gitignore"
|
66
|
+
- ".rspec"
|
67
|
+
- ".rubocop.yml"
|
68
|
+
- Gemfile
|
69
|
+
- LICENSE.txt
|
70
|
+
- README.md
|
71
|
+
- Rakefile
|
72
|
+
- bin/console
|
73
|
+
- bin/setup
|
74
|
+
- lib/pyr.rb
|
75
|
+
- lib/pyr/param.rb
|
76
|
+
- lib/pyr/parser.rb
|
77
|
+
- lib/pyr/request.rb
|
78
|
+
- lib/pyr/resource.rb
|
79
|
+
- lib/pyr/resources/districts.rb
|
80
|
+
- lib/pyr/resources/office_locations.rb
|
81
|
+
- lib/pyr/resources/reps.rb
|
82
|
+
- lib/pyr/resources/states.rb
|
83
|
+
- lib/pyr/resources/zctas.rb
|
84
|
+
- lib/pyr/response.rb
|
85
|
+
- lib/pyr/response_object.rb
|
86
|
+
- lib/pyr/response_objects/district.rb
|
87
|
+
- lib/pyr/response_objects/office_location.rb
|
88
|
+
- lib/pyr/response_objects/rep.rb
|
89
|
+
- lib/pyr/response_objects/state.rb
|
90
|
+
- lib/pyr/response_objects/zcta.rb
|
91
|
+
- lib/pyr/version.rb
|
92
|
+
- pyr.gemspec
|
93
|
+
homepage: https://www.github.com/msimonborg/pyr
|
94
|
+
licenses:
|
95
|
+
- MIT
|
96
|
+
metadata:
|
97
|
+
allowed_push_host: https://rubygems.org
|
98
|
+
post_install_message:
|
99
|
+
rdoc_options: []
|
100
|
+
require_paths:
|
101
|
+
- lib
|
102
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
103
|
+
requirements:
|
104
|
+
- - ">="
|
105
|
+
- !ruby/object:Gem::Version
|
106
|
+
version: '0'
|
107
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
108
|
+
requirements:
|
109
|
+
- - ">="
|
110
|
+
- !ruby/object:Gem::Version
|
111
|
+
version: '0'
|
112
|
+
requirements: []
|
113
|
+
rubyforge_project:
|
114
|
+
rubygems_version: 2.6.11
|
115
|
+
signing_key:
|
116
|
+
specification_version: 4
|
117
|
+
summary: Make requests to the Phone Your Rep API and get Ruby objects in return
|
118
|
+
test_files: []
|