module GetYourRep # Retrieve your elected representatives from the Google Civic Information API, parse it from # JSON, and assemble it into a usable Ruby Hash-like object called a Representative. # Representatives are then wrapped in an Array-like object called a Delegation. # # You must configure your own Google API key as an environment variable using the constant name # 'GOOGLE_API_KEY' in order for this gem to work. class Google # The Google API key is used to access data from the Google Civic Information API. You must # obtain your own and configure it as an environment variable on your system. API_KEY = ENV['GOOGLE_API_KEY'] # Initiates a chain of class method calls that will instantiate a # Delegation object and return it. # Supported options for :level are "national"(default) and "state". # Supported options for :role are "representative"(default), "senator", "executive" and "vice executive". def self.now(address, level: 'national', role: 'representative') address = convert_zip_to_address(address) if address_is_a_zip?(address) @address = parse_address(address) @level = level @role = role get_rep end #Returns reps in Congress and State Legislature, plus Governor and Lieutenant Governor. def self.all(address) top_level_reps(address) @role = 'representative' state_rep = get_rep @role = 'senator' state_sen = get_rep #Check the Open States API if Google can't find state reps. if state_rep.empty? && state_sen.empty? @reps << GetYourRep::OpenStates.now(@coordinates) else @reps << state_rep @reps << state_sen end end def self.top_level_reps(address) @reps = now(address) @role = 'senator' @reps << get_rep @level = 'state' @role = 'executive' @reps << get_rep @role = 'vice executive' @reps << get_rep end # Parses a String address and prepares for an HTTP request. Accepts Strings and Integers as args. def self.parse_address(address) address = '0%o' % address if address.is_a?(Integer) raise "Entry must be of types String or Integer" if !address.is_a?(String) address = address.tr(',', '').split.join('%20') end # Unparses a parsed address # def self.unparsed_address(address) # address.split('%20').join(' ') # end # Check if an address value is a zip code or a full address. def self.address_is_a_zip?(address) address = '0%o' % address if address.is_a?(Integer) raise "Entry must be of types String or Integer" if !address.is_a?(String) !(address =~ /^\d{5}(-\d{4})?$/).nil? end # Convert a zip code to a street address using Geocoder to convert zip to coordinates # and coordinates to an address. def self.convert_zip_to_address(address) @coordinates = Geocoder.coordinates(address) address = Geocoder.address(@coordinates) trim_street_number(address) end # If a street number is a range reduce it to one number. def self.trim_street_number(address) address = address.split(' ') address[0] = address[0].split('-').shift address.join(' ') end # Sets parameters for and executes Google API request. def self.get_rep level = case @level when 'national' 'country' when 'state' 'administrativeArea1' else @level end role = case @role when 'representative' 'legislatorLowerBody' when 'senator' 'legislatorUpperBody' when 'executive' 'headOfGovernment' when 'vice executive' 'deputyHeadOfGovernment' else @role end url = "https://www.googleapis.com/civicinfo/v2/representatives?address=#{@address}%20&includeOffices=true&levels=#{level}&roles=#{role}&fields=offices%2Cofficials&key=#{API_KEY}" @response = HTTParty.get(url).parsed_response deliver_response end def self.deliver_response if @response.empty? puts "'Google can't find a rep with that address. Checking the Open States API." return GetYourRep::Delegation.new elsif @response['error'] puts 'Error message received. Confirm and re-enter your address and check your parameters.' puts @response return GetYourRep::Delegation.new end parse_rep @delegation end # Parses the JSON response and assembles it into a Delegation object, # except for social media attributes, which are handles by .parse_channels. def self.parse_rep @delegation = GetYourRep::Delegation.new @officials = @response['officials'] @officials.each do |official| @delegation << GetYourRep::Representative[ :name, official['name'], :office, @response['offices'].first['name'], :party, official['party'], :phone, official['phones'], :office_locations, offices(official), :email, official['emails'] || [], :url, (official['urls'].first if official['urls']), :photo, official['photoUrl'], ] parse_channels(official) if official['channels'] end end def self.offices(official) offices = [] official['address'].each do |office| office_hash = {} if office['line1'].downcase.match(/(state|house|senate|assembly|capitol|dirksen|reyburn|rayburn|legislative|legislature|government)+/) office_hash[:type] = 'capitol' else office_hash[:type] = 'district' end office_hash[:line_1] = office['line1'] office_hash[:line_2] = office['line_2'] office_hash[:line_3] = "#{office['city'].capitalize}, #{office['state']} #{office['zip']}" offices << office_hash end offices end # Parses social media handles and adds them to the Delegation object. def self.parse_channels(official) official['channels'].each do |channel| @delegation.last[channel['type'].downcase.to_sym] = channel['id'] end end end end