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 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