pyr 0.1.0 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
[![Code Climate](https://codeclimate.com/github/msimonborg/pyr/badges/gpa.svg)](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
|