get_your_rep 0.1.9 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+ module GetYourRep
3
+ # Office information. Belongs to Representative.
4
+ class OfficeLocation
5
+ include GetYourRep::Errors
6
+
7
+ # Each instance belongs to a Represenative, which has many OfficeLocations.
8
+ attr_accessor :rep
9
+ # Defines the type of office ('district' or 'capitol')
10
+ attr_accessor :type
11
+ # Line 1 of address.
12
+ attr_accessor :line_1
13
+ # Line 2 of address.
14
+ attr_accessor :line_2
15
+ # City, state and zip.
16
+ attr_accessor :city, :state, :zip
17
+
18
+ # Construct a new instance, setting attributes from an options hash.
19
+ def initialize(office_hash = {})
20
+ office_hash.each do |key, val|
21
+ send("#{key}=", val)
22
+ end
23
+ end
24
+
25
+ # Set the rep attribute to an instance of a Representative, and make two-way association.
26
+ def rep=(other)
27
+ if other.is_a?(Representative)
28
+ @rep = other
29
+ other.add_office_location(self) unless other.office_locations.include?(self)
30
+ else
31
+ not_a_rep_error
32
+ end
33
+ end
34
+
35
+ # Display self attributes for CLI.
36
+ def cli_display
37
+ puts " #{type.capitalize} Office".bold.blue
38
+ office_lines = [line_1, line_2, "#{city}, #{state} #{zip}"]
39
+ office_lines.each { |line| puts " #{line}".red if line }
40
+ end
41
+ end
42
+ end
@@ -1,114 +1,56 @@
1
+ # frozen_string_literal: true
1
2
  module GetYourRep
2
-
3
3
  # Retrieve your elected state representatives from the Open States API, parse it from
4
4
  # JSON, and assemble it into a usable Ruby Hash-like object called a Representative.
5
5
  # Representatives are then wrapped in an Array-like object called a Delegation.
6
- class OpenStates
7
-
8
- # Initiates a chain of class method calls that will instantiate a
9
- # Delegation object and return it.
10
- def self.now(address)
11
- @coordinates = if address.is_a?(Array)
12
- address
13
- else
14
- get_coordinates(address)
15
- end
16
- @response = get_rep
17
- if @response.empty? || @response.is_a?(String) || @response.first['error']
18
- puts 'Error message received. Confirm and re-enter your address and check your parameters.'
19
- puts @response
20
- return GetYourRep::Delegation.new
21
- end
22
-
23
- parse_rep
24
- @delegation
25
- end
26
-
27
- # Geocodes an address and returns the coordinates.
28
- def self.get_coordinates(address)
29
- return address if address.is_a?(Array)
30
- address = '0%o' % address if address.is_a?(Integer)
31
- raise "Entry must be coordinates or of types String or Integer" if !address.is_a?(String)
32
- Geocoder.coordinates(address)
33
- end
34
-
35
- # Sets parameters for and executes Open States API request.
36
- def self.get_rep
37
- if @coordinates
38
- lat = @coordinates.first
39
- long = @coordinates.last
40
- url = "http://openstates.org/api/v1/legislators/geo/?lat=#{lat}&long=#{long}"
41
- HTTParty.get(url).parsed_response
42
- else
43
- []
44
- end
45
- end
46
-
47
- # Parses the JSON response and assembles it into a Delegation object.
48
- def self.parse_rep
49
-
50
- @delegation = GetYourRep::Delegation.new
51
-
52
- @response.each do |rep|
53
- @delegation << GetYourRep::Representative[
54
- :name, rep['full_name'].split(', ').reverse.join(' '),
55
- :office, "#{rep['state'].upcase} #{rep['chamber'].capitalize} Chamber, #{rep['district']}",
56
- :party, rep['party'],
57
- :phone, phone(rep),
58
- :office_locations, offices(rep),
59
- :email, email(rep),
60
- :url, rep['url'],
61
- :photo, rep['photo_url'],
62
- :twitter, nil,
63
- :facebook, nil,
64
- :youtube, nil,
65
- :googleplus, nil,
66
- :committees, committees(rep)
67
- ]
68
- end
69
- end
70
-
71
- def self.offices(rep)
72
- rep['offices'].map do |office|
73
-
74
- # TODO change office parsing to RegEx
75
- office_hash = {}
76
- office_hash[:type] = office['type']
77
- address = office['address'].split("\n")
78
-
79
- if address.size == 1
80
- address = office['address'].split(', ')
6
+ module OpenStates
7
+ class << self
8
+ include GetYourRep
9
+
10
+ # Holds the coordinates geocoded from the address. Used in the HTTP request to the API.
11
+ attr_accessor :coordinates
12
+ # Holds the Delegation object which will be returned by the all_reps class method.
13
+ attr_accessor :delegation
14
+ # Holds the raw JSON data response from the API.
15
+ attr_accessor :response
16
+
17
+ # Initiates a chain of class method calls that will instantiate a
18
+ # Delegation object and return it.
19
+ def all_reps(address)
20
+ self.coordinates = address.is_a?(Array) ? address : get_coordinates(address)
21
+ self.response = find_rep
22
+ if response.empty? || response.is_a?(String) || response.first['error']
23
+ handle_reps_not_found_error
24
+ else
25
+ parse_reps
26
+ delegation
81
27
  end
28
+ end
82
29
 
83
- if office['name'].downcase != "capitol office" &&
84
- office['name'].downcase != "district office"
85
-
86
- address.unshift(office['name'])
30
+ private
31
+
32
+ # Sets parameters for and executes Open States API request.
33
+ def find_rep
34
+ if coordinates
35
+ lat = coordinates.first
36
+ long = coordinates.last
37
+ url = "http://openstates.org/api/v1/legislators/geo/?lat=#{lat}&long=#{long}"
38
+ HTTParty.get(url).parsed_response
39
+ else
40
+ Delegation.new
87
41
  end
42
+ end
88
43
 
89
- i = 1
90
- address.each do |line|
91
- office_hash["line_#{i}".to_sym] = line
92
- i += 1
44
+ # Parses the JSON response and assembles it into a Delegation object.
45
+ def parse_reps
46
+ self.delegation = Delegation.new
47
+ response.each do |rep|
48
+ external_rep = OpenStatesRep.new(rep)
49
+ rep_hash = external_rep.build_hash
50
+ new_rep = Representative.new(rep_hash)
51
+ delegation.add_rep(new_rep)
93
52
  end
94
-
95
- office_hash
96
53
  end
97
54
  end
98
-
99
- # Parses the phone, giving preference to district office..
100
- def self.phone(rep)
101
- rep['offices'].map { |office| office['phone']} - [nil]
102
- end
103
-
104
- # Parses the email address.
105
- def self.email(rep)
106
- rep['offices'].map { |office| office['email'] } - [nil]
107
- end
108
-
109
- # Parses committee involvement.
110
- def self.committees(rep)
111
- rep['roles'].map { |role| role['committee'] } - [nil]
112
- end
113
55
  end
114
56
  end
@@ -0,0 +1,82 @@
1
+ # frozen_string_literal: true
2
+ module GetYourRep
3
+ # Red, white and blue decorations for CLI.
4
+ module Patriotic
5
+ # Stars banner.
6
+ def self.banner
7
+ puts ' ' + '_' * 23 + ' '.bold.red
8
+ puts "\u23B9".bold.red + ' * * * * * * * * * * * '.white.on_blue + "\u23B8".bold.red
9
+ puts ' ' + "\u203E".bold.red * 23 + ' '
10
+ end
11
+
12
+ # Stars and Bars
13
+ def self.stars_and_bars
14
+ 4.times { puts stars_and_red_bar, stars_and_white_bar }
15
+ puts stars_and_red_bar
16
+ 3.times { puts white_bar, red_bar }
17
+ end
18
+
19
+ # Stars and red bar.
20
+ def self.stars_and_red_bar
21
+ ' * * * * * * '.white.on_blue + ' '.on_red
22
+ end
23
+
24
+ # Stars and white bar.
25
+ def self.stars_and_white_bar
26
+ ' * * * * * '.white.on_blue + ' '.on_white
27
+ end
28
+
29
+ # Red bar.
30
+ def self.red_bar
31
+ ' '.on_red
32
+ end
33
+
34
+ # White bar.
35
+ def self.white_bar
36
+ ' '.on_white
37
+ end
38
+
39
+ # Fireworks welcome message.
40
+ def self.welcome
41
+ puts ''
42
+ 2.times do
43
+ print "\r" + '- '.red + '- '.white + '- '.blue + 'g e '.red + 'y o u r '.white + 'r e p '.blue +
44
+ '- '.red + '- '.white + '- '.blue
45
+ sleep(0.05)
46
+ print "\r" + '- '.red + '- '.white + '- '.blue + 'g e t '.red + 'y o r '.white + 'r e p '.blue +
47
+ '- '.red + '- '.white + '- '.blue
48
+ sleep(0.05)
49
+ print "\r" + '- '.red + '- '.white + '- '.blue + 'g e t '.red + 'y o u r '.white + 'r p '.blue +
50
+ '- '.red + '- '.white + '- '.blue
51
+ sleep(0.05)
52
+ print "\r" + '- '.red + '- '.white + '- '.blue + 'g e t '.red + 'y o u '.white + 'r e p '.blue +
53
+ '- '.red + '- '.white + '- '.blue
54
+ sleep(0.05)
55
+ print "\r" + '- '.red + '- '.white + '- '.blue + 'g e t '.red + ' o u r '.white + 'r e p '.blue +
56
+ '- '.red + '- '.white + '- '.blue
57
+ sleep(0.05)
58
+ print "\r" + '- '.red + '- '.white + '- '.blue + ' e t '.red + 'y o u r '.white + 'r e p '.blue +
59
+ '- '.red + '- '.white + '- '.blue
60
+ sleep(0.05)
61
+ print "\r" + '- '.red + '- '.white + '- '.blue + 'g e t '.red + 'y o u r '.white + 'r e '.blue +
62
+ '- '.red + '- '.white + '- '.blue
63
+ sleep(0.05)
64
+ print "\r" + '- '.red + '- '.white + '- '.blue + 'g e t '.red + 'y o u r '.white + 'r e p '.blue +
65
+ '- '.red + '- '.white + '- '.blue
66
+ sleep(0.05)
67
+ print "\r" + '- '.red + '- '.white + '- '.blue + 'g e t '.red + 'y u r '.white + 'r e p '.blue +
68
+ '- '.red + '- '.white + '- '.blue
69
+ sleep(0.05)
70
+ print "\r" + '- '.red + '- '.white + '- '.blue + 'g t '.red + 'y o u r '.white + 'r e p '.blue +
71
+ '- '.red + '- '.white + '- '.blue
72
+ sleep(0.05)
73
+ print "\r" + '- '.red + '- '.white + '- '.blue + 'g e t '.red + 'y o u r '.white + ' e p '.blue +
74
+ '- '.red + '- '.white + '- '.blue
75
+ sleep(0.05)
76
+ print "\r" + '- '.red + '- '.white + '- '.blue + 'g e t '.red + 'y o u r '.white + 'r e p '.blue +
77
+ '- '.red + '- '.white + '- '.blue
78
+ end
79
+ puts ''
80
+ end
81
+ end
82
+ end
@@ -1,294 +1,128 @@
1
+ # frozen_string_literal: true
1
2
  module GetYourRep
2
-
3
3
  # Stores rep info in key/value pairs, and makes values accessible by instance method.
4
- class Representative < Hash
5
-
6
- # Maps attributes to a simple array for easy printing, iteration, and display. It uses #each rather than #map so it can skip over nil values without mapping them.
7
- def business_card
8
-
9
- card = []
10
-
11
- self.each do |key, value|
12
- next if value.nil?
13
- if key == :facebook || key == :twitter || key == :youtube || key == :googleplus
14
- card << "#{key.to_s.capitalize}: #{value}"
15
- else
16
- card << "#{value}"
17
- end
4
+ class Representative
5
+ include GetYourRep::Errors
6
+
7
+ # The Delegation object that the instance belongs to.
8
+ attr_reader :delegation
9
+ # Rep personal attributes.
10
+ attr_accessor :name, :middle_name, :office, :phones, :party, :email, :committees, :url,
11
+ :photo, :twitter, :facebook, :youtube, :googleplus
12
+
13
+ # Set office_locations, phones, and email as empty arrays. Set the rest of the attributes
14
+ # from the options hash.
15
+ def initialize(rep_hash = {})
16
+ @office_locations = []
17
+ @phones = []
18
+ @email = []
19
+ rep_hash.each do |key, val|
20
+ send("#{key}=", val)
18
21
  end
19
-
20
- card
21
- end
22
-
23
- # Get the :name value.
24
- def name
25
- @name = self[:name]
26
- end
27
-
28
- # Set the :name value.
29
- def name=(value)
30
- @name = value
31
- self[:name] = @name
32
22
  end
33
23
 
34
- # Strips the first name out of the full name if there's no :first_name.
35
- def first_name
36
-
37
- return self[:first_name] if self[:first_name]
38
-
39
- if name.split.count == 1
40
- nil
41
- elsif (name.split.count > 3) || (name.split[-2].downcase == name.split[-2])
42
- name.split[0..-3].join(' ')
24
+ # Sets the Delegation object that the instance belongs to. Will add self to the Delegation's
25
+ # reps if not done so already.
26
+ def delegation=(other)
27
+ if other.is_a?(Delegation)
28
+ @delegation = other
29
+ other.add_rep(self) unless other.reps.include?(self)
43
30
  else
44
- name.split[0..-2].join(' ')
31
+ not_a_del_error
45
32
  end
46
-
47
- end
48
-
49
- # Get the :middle_name value.
50
- def middle_name
51
- @middle_name = self[:middle_name]
52
- end
53
-
54
- # Strips the surname out of the full name if there's no :last_name.
55
- def last_name
56
-
57
- return self[:last_name] if self[:last_name]
58
-
59
- if name.split.count == 1
60
- name
61
- elsif (name.split.count > 3) || (name.split[-2].downcase == name.split[-2])
62
- name.split[-2..-1].join(' ')
63
- else
64
- name.split.last
65
- end
66
-
67
- end
68
-
69
- # Get the :office value.
70
- def office
71
- @office = self[:office]
72
- end
73
-
74
- # Set the :office value.
75
- def office=(value)
76
- @office = value
77
- self[:office] = @office
78
- end
79
-
80
- # Get the :party value.
81
- def party
82
- @party = self[:party]
83
- end
84
-
85
- # Set the :party value.
86
- def party=(value)
87
- @party = value
88
- self[:party] = @party
89
- end
90
-
91
- # Get the :phone value.
92
- def phone
93
- @phone = self[:phone]
94
33
  end
95
34
 
96
- # Set the :phone value.
97
- def phone=(value)
98
- @phone = value
99
- self[:phone] = @phone
100
- end
101
-
102
- # Get the :alt_phone value.
103
- # def alt_phone
104
- # @alt_phone = self[:alt_phone]
105
- # end
106
-
107
- # Set the :alt_phone value.
108
- # def alt_phone=(value)
109
- # @alt_phone = value
110
- # self[:alt_phone] = @alt_phone
111
- # end
112
-
113
- # Get the :alt_address_1 value.
114
- # def alt_address_1
115
- # @alt_address_1 = self[:alt_address_1]
116
- # end
117
-
118
- # Set the :alt_address_1 value.
119
- # def alt_address_1=(value)
120
- # @alt_address_1 = value
121
- # self[:alt_address_1] = @alt_address_1
122
- # end
123
-
124
- # Get the :alt_address_2 value.
125
- # def alt_address_2
126
- # @alt_address_2 = self[:alt_address_2]
127
- # end
128
-
129
- # Set the :alt_address_2 value.
130
- # def alt_address_2=(value)
131
- # @alt_address_2 = value
132
- # self[:alt_address_2] = @alt_address_2
133
- # end
134
-
135
- # Get the :alt_address_3 value.
136
- # def alt_address_3
137
- # @alt_address_3 = self[:alt_address_3]
138
- # end
139
-
140
- # Set the :alt_address_3 value.
141
- # def alt_address_3=(value)
142
- # @alt_address_3 = value
143
- # self[:alt_address_3] = @alt_address_3
144
- # end
145
-
146
- # Get the :address_1 value.
147
- # def address_1
148
- # @address_1 = self[:address_1]
149
- # end
150
-
151
- # Set the :address_1 value.
152
- # def address_1=(value)
153
- # @address_1 = value
154
- # self[:address_1] = @address_1
155
- # end
156
-
157
- # Get the :address_2 value.
158
- # def address_2
159
- # @address_2 = self[:address_2]
160
- # end
161
-
162
- # Set the :address_2 value.
163
- # def address_2=(value)
164
- # @address_2 = value
165
- # self[:address_2] = @address_2
166
- # end
167
-
168
- # Get the :address_3 value.
169
- # def address_3
170
- # @address_3 = self[:address_3]
171
- # end
172
-
173
- # Set the :address_3 value.
174
- # def address_3=(value)
175
- # @address_3 = value
176
- # self[:address_3] = @address_3
177
- # end
178
-
35
+ # Returns a frozen duplicate of the office_locations array.
179
36
  def office_locations
180
- @office_locations = self[:office_locations]
37
+ @office_locations.dup.freeze
181
38
  end
182
39
 
183
- def office_locations=(value)
184
- @office_locations = value
185
- self[:office_locations] = @office_locations
40
+ # Empties the office_locations array.
41
+ def clear_office_locations
42
+ @office_locations.clear
186
43
  end
187
44
 
188
- def district_office
189
- @district_office = self.office_locations.select { |loc| loc[:type] == 'district' }.first
190
- if @district_office.nil?
191
- {}
45
+ # Creates a new OfficeLocation association. Sets self as the other's rep if not done so already.
46
+ def add_office_location(other)
47
+ if other.is_a?(OfficeLocation)
48
+ @office_locations << other
49
+ other.rep = self unless other.rep == self
192
50
  else
193
- @district_office
51
+ not_an_office_error
194
52
  end
195
53
  end
196
54
 
197
- def capitol_office
198
- @capitol_office = self.office_locations.select { |loc| loc[:type] == 'capitol' }.first
199
- if @capitol_office.nil?
200
- {}
55
+ # Assign an individual OfficeLocation, or an array of them.
56
+ def office_locations=(other)
57
+ if other.is_a?(Array)
58
+ other.each { |val| add_office_location(val) }
201
59
  else
202
- @capitol_office
60
+ add_office_location(other)
203
61
  end
204
62
  end
205
63
 
206
- # Get the :email value.
207
- def email
208
- @email = self[:email]
209
- end
210
-
211
- # Set the :email value.
212
- def email=(value)
213
- @email = value
214
- self[:email] = @email
215
- end
216
-
217
- # Get the :committees value.
218
- def committees
219
- @committees = self[:committees]
220
- end
221
-
222
- # Set the :committees value.
223
- def committees=(value)
224
- @committees = value
225
- self[:committees] = @committees
226
- end
227
-
228
- # Get the :url value.
229
- def url
230
- @url = self[:url]
231
- end
232
-
233
- # Set the :url value.
234
- def url=(value)
235
- @url = value
236
- self[:url] = @url
237
- end
238
-
239
- # Get the :photo value.
240
- def photo
241
- @photo = self[:photo]
242
- end
243
-
244
- # Set the :photo value.
245
- def photo=(value)
246
- @photo = value
247
- self[:photo] = @photo
64
+ # Parse the first name from the :name.
65
+ def first_name
66
+ @first_name ||= if name_count == 1
67
+ nil
68
+ elsif (name_count > 3) || (name_array[-2].downcase == name_array[-2])
69
+ name_array[0..-3].join(' ')
70
+ else
71
+ name_array[0..-2].join(' ')
72
+ end
248
73
  end
249
74
 
250
- # Get the :twitter value.
251
- def twitter
252
- @twitter = self[:twitter]
75
+ # Parse the last name from the :name.
76
+ def last_name
77
+ @last_name ||= if name_count == 1
78
+ name
79
+ elsif (name_count > 3) || (name_array[-2].downcase == name_array[-2])
80
+ name_array[-2..-1].join(' ')
81
+ else
82
+ name_array.last
83
+ end
253
84
  end
254
85
 
255
- # Set the :twitter value.
256
- def twitter=(value)
257
- @twitter = value
258
- self[:twitter] = @twitter
86
+ # Splits the name into an array.
87
+ def name_array
88
+ @name_array ||= name.split
259
89
  end
260
90
 
261
- # Get the :facebook value.
262
- def facebook
263
- @facebook = self[:facebook]
91
+ # Counts the elements in the name array.
92
+ def name_count
93
+ @name_count ||= name_array.size
264
94
  end
265
95
 
266
- # Set the :facebook value.
267
- def facebook=(value)
268
- @facebook = value
269
- self[:facebook] = @facebook
96
+ # Maps the offices with the :type attribute equal to 'district'.
97
+ def district_offices
98
+ @district_offices ||= office_locations.select { |office| office.type == 'district' }
270
99
  end
271
100
 
272
- # Get the :youtube value.
273
- def youtube
274
- @youtube = self[:youtube]
101
+ # Maps the offices with the :type attribute equal to 'capitol'.
102
+ def capitol_offices
103
+ @district_offices ||= office_locations.select { |office| office.type == 'capitol' }
275
104
  end
276
105
 
277
- # Set the :youtube value.
278
- def youtube=(value)
279
- @youtube = value
280
- self[:youtube] = @youtube
106
+ # Displays self for the CLI.
107
+ def cli_display
108
+ cli_basic_info
109
+ office_locations.each(&:cli_display)
110
+ cli_display_committees
281
111
  end
282
112
 
283
- # Get the :googleplus value.
284
- def googleplus
285
- @googleplus = self[:googleplus]
113
+ # Display basic info.
114
+ def cli_basic_info
115
+ puts name.bold.blue
116
+ puts " #{office}".red
117
+ puts " #{party}".red
118
+ phones.each { |phone| puts " #{phone}".red }
286
119
  end
287
120
 
288
- # Set the :googleplus value.
289
- def googleplus=(value)
290
- @googleplus = value
291
- self[:googleplus] = @googleplus
121
+ # Display committee info.
122
+ def cli_display_committees
123
+ return unless committees && !committees.empty?
124
+ puts ' Committees'.bold.blue
125
+ committees.each { |comm| puts " #{comm}".red }
292
126
  end
293
127
  end
294
128
  end