pyr 0.1.0 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +14 -11
- data/lib/pyr.rb +109 -3
- data/lib/pyr/param.rb +7 -3
- data/lib/pyr/resource.rb +18 -5
- data/lib/pyr/resources/reps.rb +59 -14
- data/lib/pyr/resources/zctas.rb +4 -5
- data/lib/pyr/response.rb +1 -1
- data/lib/pyr/response_object.rb +48 -10
- data/lib/pyr/response_objects/district.rb +15 -0
- data/lib/pyr/response_objects/office_location.rb +3 -3
- data/lib/pyr/version.rb +2 -2
- data/pyr.gemspec +0 -4
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6333e6354f970dcd24da80da145b5a14b17eb53d
|
4
|
+
data.tar.gz: 4e4e70ab8ab3f72c411ed6966ae80df19d43038c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a1f47d4383710c005cd1bc62d5312d6212c42f77d8f98818512044795296d5d87bb46c7711b6fe8603f4863b72a4df8edf09f8892260cf26bc0c78dc8243b0e4
|
7
|
+
data.tar.gz: 91364f48240d406420d6b0fa8fc7ed39d2db5521db23854ee12e90000cfa601ed29836549c99fdbc9e87b1afa1a2465f1bb3de15f0310a233680c518c2242187
|
data/README.md
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
# PYR
|
2
2
|
[](https://codeclimate.com/github/msimonborg/pyr)
|
3
3
|
|
4
|
-
PYR makes integrating data from the Phone Your Rep API into your Ruby project as easy as pie.
|
4
|
+
PYR makes integrating data from the [Phone Your Rep API](https://www.github.com/phoneyourrep/phone-your-rep-api) into your Ruby project as easy as pie.
|
5
5
|
|
6
6
|
## Installation
|
7
7
|
|
@@ -25,15 +25,18 @@ Or install it yourself as:
|
|
25
25
|
```ruby
|
26
26
|
response = PYR.call :reps do |r|
|
27
27
|
r.lat = 44.5588028
|
28
|
-
r.long = -72.
|
28
|
+
r.long = -72.5778415
|
29
29
|
end
|
30
30
|
|
31
|
+
response.uri
|
32
|
+
=> "https://phone-your-rep.herokuapp.com/api/beta/reps?lat=44.5588028&long=-72.5778415&"
|
33
|
+
|
31
34
|
## or ##
|
32
35
|
|
33
|
-
response = PYR.call(:reps)
|
36
|
+
response = PYR.call(:reps) { |r| r.address = 'Vermont' }
|
34
37
|
|
35
38
|
response.uri
|
36
|
-
=> "https://phone-your-rep.herokuapp.com/api/beta/reps?
|
39
|
+
=> "https://phone-your-rep.herokuapp.com/api/beta/reps?address=Vermont&"
|
37
40
|
|
38
41
|
response.code
|
39
42
|
=> 200
|
@@ -56,11 +59,11 @@ reps.first.official_full
|
|
56
59
|
reps.first.office_locations_count
|
57
60
|
=> 3
|
58
61
|
|
59
|
-
reps.first.office_locations.first.
|
60
|
-
=> "
|
62
|
+
reps.first.office_locations.first.phone
|
63
|
+
=> "802-748-9269"
|
61
64
|
```
|
62
65
|
|
63
|
-
###
|
66
|
+
### Querying the full index and narrowing with scopes
|
64
67
|
```ruby
|
65
68
|
response = PYR.call :reps
|
66
69
|
|
@@ -79,10 +82,10 @@ reps.democratic.senators.count
|
|
79
82
|
=> 46
|
80
83
|
|
81
84
|
reps.where official_full: 'Bernard Sanders'
|
82
|
-
=> #<PYR::RepRelation [#<PYR::Rep id:
|
85
|
+
=> #<PYR::RepRelation [#<PYR::Rep id: 428, self: "https://phone-your-rep.herokuapp.com/api/beta/reps/S000033", state: #<PYR::State:0x007fdb11d42580>, 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
86
|
|
84
|
-
reps.independent.where { |r| r.state
|
85
|
-
=> #<PYR::Rep id:
|
87
|
+
reps.independent.where { |r| r.state.name == 'Vermont' }.first
|
88
|
+
=> #<PYR::Rep id: 428, self: "https://phone-your-rep.herokuapp.com/api/beta/reps/S000033", state: #<PYR::State:0x007fdb11d42580>, 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
89
|
```
|
87
90
|
|
88
91
|
### Querying by ID
|
@@ -105,7 +108,7 @@ office.office_id == PYR.call(office).objects.first.office_id
|
|
105
108
|
```ruby
|
106
109
|
rep = PYR.call(:reps) { |r| r.address = 'vermont' }.objects.representatives.first
|
107
110
|
|
108
|
-
uri = rep.district
|
111
|
+
uri = rep.district.self
|
109
112
|
=> "https://phone-your-rep.herokuapp.com/api/beta/districts/5000"
|
110
113
|
|
111
114
|
district = PYR.call(uri).objects.first
|
data/lib/pyr.rb
CHANGED
@@ -1,5 +1,25 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
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.
|
22
|
+
|
3
23
|
require 'pyr/param'
|
4
24
|
require 'pyr/parser'
|
5
25
|
require 'pyr/resource'
|
@@ -20,9 +40,79 @@ require 'pyr/version'
|
|
20
40
|
|
21
41
|
# PYR provides an easy interface to the Phone Your Rep API,
|
22
42
|
# converting the data payloads into Plain Old Ruby Objects.
|
43
|
+
# There is one class method on the PYR module, ::call.
|
44
|
+
#
|
45
|
+
# The method takes two arguments: :resource and :id. The resource
|
46
|
+
# is the API resource, or controller name, that you want to
|
47
|
+
# query. The name must be in plural form. The options are 'reps',
|
48
|
+
# 'office_locations', 'states', 'districts', and 'zctas' (Zip Code
|
49
|
+
# Tabulation Areas).
|
50
|
+
#
|
51
|
+
# The :id is the primary key id of a particular object. Each
|
52
|
+
# resource has its own data attribute as ID.
|
53
|
+
#
|
54
|
+
# ids = {
|
55
|
+
# reps: :bioguide_id,
|
56
|
+
# office_locations: :office_id,
|
57
|
+
# states: :state_code,
|
58
|
+
# districts: :full_code,
|
59
|
+
# zctas: :zcta
|
60
|
+
# }
|
61
|
+
#
|
62
|
+
# The ::call method takes a block, to which it yields an object
|
63
|
+
# inherited from the PYR::Resource class. You can then pass params to
|
64
|
+
# the PYR::Resource object. The particular descendant of PYR::Resource,
|
65
|
+
# and therefore the available params, depends on the resource/controller
|
66
|
+
# that you are querying.
|
67
|
+
#
|
68
|
+
# The return value of ::call is an instance of the PYR::Response class.
|
69
|
+
# You can call these methods on the object:
|
70
|
+
|
71
|
+
# #objects => A collection, similar to an ActiveRecord Relation, of
|
72
|
+
# objects descended from the PYR::ResponseObject superclass,
|
73
|
+
# which have getter methods for each data attribute.
|
74
|
+
# The objects may be nested inside other PYR::ResponseObjects,
|
75
|
+
# e.g. a :rep has_one :state and has_many :office_locations.
|
76
|
+
# The collection can be iterated over, and can be queried
|
77
|
+
# similarly to how you would query in ActiveRecord, using the
|
78
|
+
# #where method, which can take hash syntax for checking equality
|
79
|
+
# of discreet attributes, or block syntax if you need to do
|
80
|
+
# more complex comparisons. Some scopes are also available
|
81
|
+
# depending on the resource, e.g. `reps.democratic.senators`
|
82
|
+
#
|
83
|
+
# #uri => The URI that the request was sent to.
|
84
|
+
#
|
85
|
+
# #body => The raw JSON data response
|
86
|
+
#
|
87
|
+
# #code => The HTTP status code e.g. 200
|
88
|
+
#
|
89
|
+
# #message => The HTTP status message e.g. 'OK'
|
90
|
+
#
|
91
|
+
# #controller => The API controller that was hit e.g. :reps, :zctas etc...
|
92
|
+
#
|
93
|
+
# #headers => A hash containing the HTTP response headers
|
94
|
+
#
|
95
|
+
# ==== Examples
|
96
|
+
#
|
97
|
+
# response = PYR.call(:reps) { |r| r.address = 'vermont' }
|
98
|
+
#
|
99
|
+
# response.body # => { ... }
|
100
|
+
# response.uri # => 'https://phone-your-rep.herokuapp.com/api/beta/reps?address=vermont'
|
101
|
+
# reps = response.objects
|
102
|
+
# reps.count # => 3
|
103
|
+
# reps.independent.senators.first.official_full # => "Bernard Sanders"
|
104
|
+
#
|
105
|
+
# response = PYR.call :reps
|
106
|
+
#
|
107
|
+
# response.objects.count # => 536
|
108
|
+
# independent_senators = response.objects.independent.senators
|
109
|
+
# vt_fav_son = independent_senators.where { |r| r.state.abbr == 'VT' }.first
|
110
|
+
# vt_fav_son.official_full # => "Bernard Sanders"
|
23
111
|
module PYR
|
24
|
-
|
112
|
+
# The base URI for all requests
|
113
|
+
API_BASE_URI = 'https://phone-your-rep.herokuapp.com/api/beta/'
|
25
114
|
|
115
|
+
# The API resources available to query
|
26
116
|
PYR_RESOURCES = %i[
|
27
117
|
reps
|
28
118
|
office_locations
|
@@ -31,19 +121,35 @@ module PYR
|
|
31
121
|
zctas
|
32
122
|
].freeze
|
33
123
|
|
124
|
+
# ActiveSupport::Inflector is used to identify possible PYR
|
125
|
+
# objects nested in the JSON data response.
|
126
|
+
#
|
127
|
+
# The inflector thinks the plural of 'zcta' is 'zcta', so we
|
128
|
+
# register the correct inflection.
|
34
129
|
ActiveSupport::Inflector.inflections do |inflect|
|
35
130
|
inflect.irregular 'zcta', 'zctas'
|
36
131
|
end
|
37
132
|
|
133
|
+
# The main API interface. All the objects you will need to work
|
134
|
+
# with are returned by this method.
|
135
|
+
#
|
136
|
+
# Arguments can be:
|
137
|
+
#
|
138
|
+
# a particular PYR::ResponseObject itself to query that object's 'self' url;
|
139
|
+
#
|
140
|
+
# a valid Phone Your Rep URI beginning with the API_BASE_URI string value;
|
141
|
+
#
|
142
|
+
# or, perhaps most commonly, a resource name (String or Symbol) with
|
143
|
+
# optional ID(String).
|
38
144
|
def self.call(resource, id = nil)
|
39
145
|
if resource.is_a?(ResponseObject)
|
40
146
|
request_object = { response_object: resource }
|
41
|
-
elsif resource.to_s.include?
|
147
|
+
elsif resource.to_s.include? API_BASE_URI
|
42
148
|
request_object = { base_url: resource }
|
43
149
|
else
|
44
150
|
resource = Request.build(resource, id)
|
45
151
|
yield resource if block_given?
|
46
|
-
request_object = { base_url:
|
152
|
+
request_object = { base_url: API_BASE_URI, resource: resource }
|
47
153
|
end
|
48
154
|
Response.new request_object
|
49
155
|
end
|
data/lib/pyr/param.rb
CHANGED
@@ -1,25 +1,29 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module PYR
|
4
|
-
#
|
4
|
+
# Defines the #to_s method for request params.
|
5
5
|
# Will handle the conversion differently depending on if
|
6
6
|
# it is an ID param e.g. controller/:id
|
7
7
|
class Param
|
8
|
+
# www.example.com/path?name=value
|
8
9
|
attr_reader :name, :value
|
9
10
|
|
11
|
+
# Set the param `name` and `value`, and whether it's an ID
|
10
12
|
def initialize(name, value, id: nil)
|
11
|
-
@id
|
13
|
+
@id = !id.nil?
|
12
14
|
@name = name
|
13
15
|
@value = value
|
14
16
|
end
|
15
17
|
|
18
|
+
# Is the param an ID param?
|
16
19
|
def id?
|
17
20
|
@id
|
18
21
|
end
|
19
22
|
|
23
|
+
# Format the param for the URI
|
20
24
|
def to_s
|
21
25
|
url_value = value.to_s.tr('#;\'""', '').gsub(' ', '%20')
|
22
|
-
id? ? "/#{value}" : "#{name}=#{url_value}
|
26
|
+
id? ? "/#{value}" : "#{name}=#{url_value}"
|
23
27
|
end
|
24
28
|
end
|
25
29
|
end
|
data/lib/pyr/resource.rb
CHANGED
@@ -2,10 +2,23 @@
|
|
2
2
|
|
3
3
|
module PYR
|
4
4
|
# Resource and its subclasses accept attribute params and,
|
5
|
-
# in conjunction with the Param class,
|
6
|
-
# convert them to a URI friendly string
|
5
|
+
# in conjunction with instances of the Param class,
|
6
|
+
# convert them to a URI friendly string.
|
7
|
+
# When a block is passed to `PYR.call(name)`, it yields
|
8
|
+
# a Resource object, on which param setter methods can be
|
9
|
+
# called. The exact type of Resource that is yielded depends
|
10
|
+
# on the name that is passed to the method.
|
11
|
+
#
|
12
|
+
# === Example
|
13
|
+
#
|
14
|
+
# PYR.call(:reps) do |r| # yielding an instance of PYR::Resource::Reps
|
15
|
+
# r.address = 'Somewhere in the USA' # The `address` param is available
|
16
|
+
# end
|
7
17
|
class Resource
|
8
|
-
|
18
|
+
# Read the `id`
|
19
|
+
attr_reader :id
|
20
|
+
# Read the `controller`
|
21
|
+
attr_reader :controller
|
9
22
|
|
10
23
|
def initialize(controller, id)
|
11
24
|
@controller = controller
|
@@ -17,11 +30,11 @@ module PYR
|
|
17
30
|
end
|
18
31
|
|
19
32
|
def to_s
|
20
|
-
"#{controller}#{params}"
|
33
|
+
"#{controller}#{id}?#{params.map(&:to_s).join('&')}"
|
21
34
|
end
|
22
35
|
|
23
36
|
def params
|
24
|
-
|
37
|
+
@params ||= []
|
25
38
|
end
|
26
39
|
end
|
27
40
|
end
|
data/lib/pyr/resources/reps.rb
CHANGED
@@ -2,28 +2,73 @@
|
|
2
2
|
|
3
3
|
module PYR
|
4
4
|
class Resource
|
5
|
-
#
|
5
|
+
# Resource object for sending requests to the /reps resource of the API
|
6
6
|
class Reps < Resource
|
7
|
-
|
7
|
+
# Read the lat param
|
8
|
+
attr_reader :lat
|
9
|
+
# Read the long param
|
10
|
+
attr_reader :long
|
11
|
+
# Read the address param
|
12
|
+
attr_reader :address
|
13
|
+
# Read the generate param
|
14
|
+
attr_reader :generate
|
8
15
|
|
9
|
-
|
10
|
-
|
16
|
+
# Set the lat param : float
|
17
|
+
# Needs to be accompanied by :long.
|
18
|
+
#
|
19
|
+
# Usage:
|
20
|
+
# PYR.call :reps do |r|
|
21
|
+
# r.lat = 45.0
|
22
|
+
# r.long = -70.0
|
23
|
+
# end
|
24
|
+
def lat=(float)
|
25
|
+
@lat = Param.new(:lat, float)
|
26
|
+
params << @lat
|
11
27
|
end
|
12
28
|
|
13
|
-
|
14
|
-
|
29
|
+
# Set the long param : float
|
30
|
+
# Needs to be accompanied by :lat.
|
31
|
+
#
|
32
|
+
# Usage:
|
33
|
+
# PYR.call :reps do |r|
|
34
|
+
# r.lat = 45.0
|
35
|
+
# r.long = -70.0
|
36
|
+
# end
|
37
|
+
#
|
38
|
+
# Resulting URI: 'https://phone-your-rep.herokuapp.com/api/beta/reps?lat=45.0&long=-45.0'
|
39
|
+
def long=(float)
|
40
|
+
@long = Param.new(:long, float)
|
41
|
+
params << @long
|
15
42
|
end
|
16
43
|
|
17
|
-
|
18
|
-
|
44
|
+
# Set the address param : string
|
45
|
+
# :lat and :long take precedence
|
46
|
+
#
|
47
|
+
# Usage:
|
48
|
+
# PYR.call(:reps) { |r| r.address = '123 Main St., USA'}
|
49
|
+
#
|
50
|
+
# Resulting URI: 'https://phone-your-rep.herokuapp.com/api/beta/reps?lat=45.0&long=-45.0'
|
51
|
+
def address=(string)
|
52
|
+
@address = Param.new(:address, string)
|
53
|
+
params << @address
|
19
54
|
end
|
20
55
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
56
|
+
# Set the generate param : boolean
|
57
|
+
#
|
58
|
+
# By default making a call to the full :reps index will return a cached
|
59
|
+
# JSON file. The cached file is updated regularly (usually every day).
|
60
|
+
# However, if you want to generate a fresh response directly from the
|
61
|
+
# database, you can set :generate to true. The response will be much
|
62
|
+
# slower, and in most cases will never be necessary. Has no effect
|
63
|
+
# when used with either :address or :lat/:long
|
64
|
+
#
|
65
|
+
# Usage:
|
66
|
+
# PYR.call(:reps) { |r| r.generate = true }
|
67
|
+
#
|
68
|
+
# Resulting URI: 'https://phone-your-rep.herokuapp.com/api/beta/reps?generate=true'
|
69
|
+
def generate=(boolean)
|
70
|
+
@generate = Param.new(:generate, boolean)
|
71
|
+
params << @generate
|
27
72
|
end
|
28
73
|
end
|
29
74
|
end
|
data/lib/pyr/resources/zctas.rb
CHANGED
@@ -2,16 +2,15 @@
|
|
2
2
|
|
3
3
|
module PYR
|
4
4
|
class Resource
|
5
|
-
#
|
5
|
+
# Resource object for sending requests to the /zctas resource of the API
|
6
6
|
class Zctas < Resource
|
7
|
+
# Read the reps param value
|
7
8
|
attr_reader :reps
|
8
9
|
|
9
|
-
|
10
|
-
"#{id}?#{reps}"
|
11
|
-
end
|
12
|
-
|
10
|
+
# Set the 'reps' param value
|
13
11
|
def reps=(value)
|
14
12
|
@reps = Param.new(:reps, value)
|
13
|
+
params << @reps
|
15
14
|
end
|
16
15
|
end
|
17
16
|
end
|
data/lib/pyr/response.rb
CHANGED
@@ -18,7 +18,7 @@ module PYR
|
|
18
18
|
@controller = resource.controller
|
19
19
|
@uri = "#{base_url}#{resource}"
|
20
20
|
elsif base_url
|
21
|
-
@controller = base_url.sub(
|
21
|
+
@controller = base_url.sub(API_BASE_URI, '').split('/').first
|
22
22
|
@uri = base_url
|
23
23
|
elsif response_object
|
24
24
|
@controller = response_object.controller
|
data/lib/pyr/response_object.rb
CHANGED
@@ -1,28 +1,66 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
# The LazyRecord gem provides hash and block constructor syntax,
|
4
|
+
# attribute, association, and scope definition macros, and object
|
5
|
+
# collections. It gives objects an API similar to ActiveRecord,
|
6
|
+
# turning the raw JSON response into a collection of associated
|
7
|
+
# Ruby objects.
|
3
8
|
require 'lazy_record'
|
4
9
|
|
5
10
|
module PYR
|
6
11
|
# The ResponseObject is the parent class of all objects instantiated
|
7
12
|
# from the response body.
|
8
13
|
class ResponseObject < LazyRecord::Base
|
9
|
-
|
14
|
+
# Pass in an options hash to instantiate the object and set the data
|
15
|
+
# attributes. First iterates through the hash converting nested hashes
|
16
|
+
# and arrays of hashes into other PYR::ResponseObjects if possible.
|
17
|
+
# Hash keys that are not defined as attributes with `lr_attr_accessor`
|
18
|
+
# or `lr_has_many` will not be accessible in the parent object.
|
19
|
+
def initialize(opts = {}, &block)
|
10
20
|
new_opts = opts.each_with_object({}) do |(key, val), memo|
|
11
|
-
memo[key] =
|
12
|
-
objectify(key, val)
|
13
|
-
else
|
14
|
-
val
|
15
|
-
end
|
21
|
+
memo[key] = convert_json_object_to_pyr_resource(key, val) || val
|
16
22
|
end
|
17
|
-
super(new_opts)
|
23
|
+
super(new_opts, &block)
|
18
24
|
end
|
19
25
|
|
26
|
+
# The controller name, based on the object's class name.
|
27
|
+
def controller
|
28
|
+
@controller ||= self.class.to_s.split('::').last.tableize
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
# If the attribute key is a valid plural or singular resource,
|
34
|
+
# e.g. `"reps"` or `"rep"`, use the values as options hashes to
|
35
|
+
# instantiate PYR::ResponseObjects.
|
36
|
+
def convert_json_object_to_pyr_resource(key, val)
|
37
|
+
if resources_include?(key) && val.is_a?(Array)
|
38
|
+
objectify(key, val)
|
39
|
+
elsif resources_include_singular?(key) && val.is_a?(Hash)
|
40
|
+
new_response_object(key, val)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
# Check the `PYR_RESOURCES` constant for the plural version of `name`
|
45
|
+
def resources_include_singular?(name)
|
46
|
+
resources_include?(name.to_s.pluralize)
|
47
|
+
end
|
48
|
+
|
49
|
+
# Check the `PYR_RESOURCES` constant for `name`
|
50
|
+
def resources_include?(name)
|
51
|
+
PYR_RESOURCES.include?(name.to_sym)
|
52
|
+
end
|
53
|
+
|
54
|
+
# Iterate over an array and instantiate a PYR::ResponseObject from
|
55
|
+
# each item in the collection.
|
20
56
|
def objectify(name, array)
|
21
|
-
array.map { |obj| "PYR::#{name.classify}".constantize.new(obj) }
|
57
|
+
array.map { |obj| "PYR::#{name.to_s.classify}".constantize.new(obj) }
|
22
58
|
end
|
23
59
|
|
24
|
-
|
25
|
-
|
60
|
+
# Instantiate a single PYR::ResponseObject from an options hash.
|
61
|
+
def new_response_object(name, opts)
|
62
|
+
"PYR::#{name.to_s.classify}".constantize.new(opts)
|
26
63
|
end
|
64
|
+
# end private
|
27
65
|
end
|
28
66
|
end
|
@@ -3,6 +3,21 @@
|
|
3
3
|
module PYR
|
4
4
|
# The District is the response object that carries the data for
|
5
5
|
# a single congressional district.
|
6
|
+
#
|
7
|
+
# Responds to the following attribute methods:
|
8
|
+
#
|
9
|
+
# #self => The object's direct URI path
|
10
|
+
#
|
11
|
+
# #full_code => Concatenation of the `state_code` and `district_code`.
|
12
|
+
# A unique 4 digit identifier for each Congressional District,
|
13
|
+
# and the primary key ID of the object.
|
14
|
+
#
|
15
|
+
# #code => 2 digit district identifier. Not unique. The state must
|
16
|
+
# provide context to indicate the exact district.
|
17
|
+
# e.g. Minnesota's 4th district
|
18
|
+
#
|
19
|
+
# #state_code => Unique 2 digit code for the State that contains
|
20
|
+
# the district.
|
6
21
|
class District < ResponseObject
|
7
22
|
lr_attr_accessor :self, :full_code, :code, :state_code
|
8
23
|
end
|
@@ -6,6 +6,9 @@ module PYR
|
|
6
6
|
# for a single office location, which in turn is associated to a
|
7
7
|
# rep in a `:rep has_many :office_locations` relationship.
|
8
8
|
class OfficeLocation < ResponseObject
|
9
|
+
lr_scope :capitol, -> { where office_type: 'capitol' }
|
10
|
+
lr_scope :district, -> { where office_type: 'district' }
|
11
|
+
|
9
12
|
lr_attr_accessor :self,
|
10
13
|
:city,
|
11
14
|
:rep,
|
@@ -28,8 +31,5 @@ module PYR
|
|
28
31
|
:v_card_link,
|
29
32
|
:downloads,
|
30
33
|
:qr_code_link
|
31
|
-
|
32
|
-
lr_scope :capitol, -> { where office_type: 'capitol' }
|
33
|
-
lr_scope :district, -> { where office_type: 'district' }
|
34
34
|
end
|
35
35
|
end
|
data/lib/pyr/version.rb
CHANGED
data/pyr.gemspec
CHANGED
@@ -20,10 +20,6 @@ Gem::Specification.new do |spec|
|
|
20
20
|
spec.homepage = 'https://www.github.com/msimonborg/pyr'
|
21
21
|
spec.license = 'MIT'
|
22
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
23
|
if spec.respond_to?(:metadata)
|
28
24
|
spec.metadata['allowed_push_host'] = 'https://rubygems.org'
|
29
25
|
else
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: pyr
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- M. Simon Borg
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-04-
|
11
|
+
date: 2017-04-13 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: httparty
|