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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: e9e59c224c843ca67e681e5f25ccc13da61ec142
4
- data.tar.gz: 564cf7a0cc20981bb4b49df434b50ecca8ef19f1
3
+ metadata.gz: 6333e6354f970dcd24da80da145b5a14b17eb53d
4
+ data.tar.gz: 4e4e70ab8ab3f72c411ed6966ae80df19d43038c
5
5
  SHA512:
6
- metadata.gz: 0a19050c771961098b9af8875f09f2aa6b54b375fa15e26cf7577cd2e90a915cd09af1d5f63397f8ebd179137c330ca042e95091aa8641de60b8830357aaeed6
7
- data.tar.gz: f562c9bce4f3315679278482753268fe4f7ea0b63eb141d007e7fe45bc8fbdb8e45ae52df9e91d107f74b56d180e1bb4a027318ff4908b52d9c8a08915369aea
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.57784149999999
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) do { |r| r.address = 'Vermont' }
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?lat=44.5588028&long=-72.57784149999999&"
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.city
60
- => "St. Johnsbury"
62
+ reps.first.office_locations.first.phone
63
+ => "802-748-9269"
61
64
  ```
62
65
 
63
- ### Query the full index and narrowing with scopes
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: 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>]>
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['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>
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['self']
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
- API_BASE_URL = 'https://phone-your-rep.herokuapp.com/api/beta/'
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? API_BASE_URL
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: API_BASE_URL, resource: resource }
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
- # Handles string conversion for request params.
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 = id == true ? true : false
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
- attr_reader :id, :controller
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
- "#{id}?"
37
+ @params ||= []
25
38
  end
26
39
  end
27
40
  end
@@ -2,28 +2,73 @@
2
2
 
3
3
  module PYR
4
4
  class Resource
5
- # Request object for sending requests to the /reps resource of the API
5
+ # Resource object for sending requests to the /reps resource of the API
6
6
  class Reps < Resource
7
- attr_reader :lat, :long, :address, :generate
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
- def params
10
- "#{id}?#{lat}#{long}#{address}#{generate}"
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
- def lat=(value)
14
- @lat = Param.new(:lat, value)
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
- def long=(value)
18
- @long = Param.new(:long, value)
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
- def address=(value)
22
- @address = Param.new(:address, value)
23
- end
24
-
25
- def generate=(value)
26
- @generate = Param.new(:generate, value)
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
@@ -2,16 +2,15 @@
2
2
 
3
3
  module PYR
4
4
  class Resource
5
- # Request object for sending requests to the /zctas resource of the API
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
- def params
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(API_BASE_URL, '').split('/').first
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
@@ -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
- def initialize(opts = {})
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] = if PYR_RESOURCES.include?(key.to_sym)
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
- def controller
25
- @controller ||= self.class.to_s.split('::').last.tableize
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
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- module PYR
4
- VERSION = '0.1.0'
3
+ module PYR # :nodoc:
4
+ VERSION = '0.2.0'
5
5
  end
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.1.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-10 00:00:00.000000000 Z
11
+ date: 2017-04-13 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: httparty