Skip to content

Commit

Permalink
Add 'details' command (#4)
Browse files Browse the repository at this point in the history
* Add 'details' command
Includes:
- Refactoring Google Maps API piece into separate file and class
- Updating Sorbet
- Updating README
- Adding tests and related VCR cassettes

* Replace triple equals with more suitable options

* Fix rescue statement

* Refactor possible responses as private methods
  • Loading branch information
l33loo authored Mar 7, 2020
1 parent fe55296 commit 22e820f
Show file tree
Hide file tree
Showing 12 changed files with 1,235 additions and 361 deletions.
46 changes: 45 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ Light Phone team works on adding things like directions.
* [Setup](#setup)
* [Cost](#cost)
* [Supported Commands](#supported-commands)
* [details](#details) returns Google Maps place details
* [directions](#directions) texts you Google Maps directions
* [h](#h) (help) shows available commands
* [ping](#ping) tiny command for testing your gateway
Expand Down Expand Up @@ -73,6 +74,49 @@ this service!

Here are the currently supported commands. If you want to add more commands, see [Contributing a new command](#contributing-a-new-command).

### details

This command will text you the available info about a specific place listed on Google Maps.
If there are more than one match, the command returns a list of the top 10 results instead.

*NOTE:* this command does *not* factor in the location of your phone.

*Syntax*: `details <place>`
*Extra cost:* consult Google Maps API fees

*Params:*
* `place` - a description of the place, as precise as possible

*Setup*:
* [Get an API key for Google Maps](https://developers.google.com/maps/gmp-get-started)
* `heroku config:set GOOGLE_MAPS_API_KEY=...`

*Examples:*

-> details korean restaurant victoria bc

(1) NARU Korean Restaurant, Wharf Street, Victoria, BC, Canada
(2) Cera Korean Restaurant, Pandora Avenue, Victoria, BC, Canada
(3) Han Korean Restaurant, Johnson Street, Victoria, BC, Canada
(4) Sura Korean Restaurant, Douglas Street, Victoria, BC, Canada
(5) Sumi Korean Restaurant, Victoria Drive, Vancouver, BC, Canada

-> details naru victoria bc

NARU Korean Restaurant
1218 Wharf St, Victoria, BC V8W 1T8, Canada
Phone: (250) 590-5298
Rating: 4.5
Closed now
Hours:
* Monday: 11:30 AM - 4:00 PM, 5:00 - 9:30 PM
* Tuesday: 11:30 AM - 4:00 PM, 5:00 - 9:30 PM
* Wednesday: 11:30 AM - 4:00 PM, 5:00 - 9:30 PM
* Thursday: 11:30 AM - 4:00 PM, 5:00 - 9:30 PM
* Friday: 11:30 AM - 4:00 PM, 5:00 - 9:30 PM
* Saturday: 11:30 AM - 4:00 PM, 5:00 - 9:30 PM
* Sunday: Closed

### directions

This command will give you Google Maps directions from `start` to `destination`.
Expand Down Expand Up @@ -315,4 +359,4 @@ Once the tunnel is up:

Thanks to these folks for contributing:

* @l33loo - added `tip` command and phone whitelisting!
* @l33loo - added `details` and `tip` commands, and phone whitelisting!
2 changes: 2 additions & 0 deletions lib/commands.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
# frozen_string_literal: true

require_relative './commands/base'
require_relative './commands/details'
require_relative './commands/directions'
require_relative './commands/help'
require_relative './commands/ping'
Expand All @@ -13,6 +14,7 @@ module Commands
sig { returns(T::Array[T.class_of(Commands::Base)]) }
def self.all
[
Commands::Details,
Commands::Directions,
Commands::Help,
Commands::Ping,
Expand Down
74 changes: 74 additions & 0 deletions lib/commands/details.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
# typed: ignore
# frozen_string_literal: true

require_relative './google_maps_api'

module Commands
class Details < GoogleMapsAPI
extend T::Sig

sig { override.returns(String) }
def self.name
'details'
end

sig { override.returns(String) }
def self.help
<<~HELP
details <place>: returns available info about a specific place listed on Google Maps.
If there are more than one match, the command returns a list of the top 10 results instead.
Examples:
details living computers museum, seattle wa
details korean restaurant victoria bc
HELP
end

sig { override.returns(String) }
def response_body
return api_key_missing unless api_key_exists?

return help if arg_text.empty?

begin
places = Google::Maps.places(arg_text)
place = Google::Maps.place(places.first.place_id)
rescue Google::Maps::ZeroResultsException
return "NO RESULTS FOR \"#{arg_text}\""
rescue => error
return error.message
end

return list_of_places(places) if places.length > 1

build_response(place)
end

private

sig { params(place: Google::Maps::PlaceDetails).returns(String) }
def build_response(place)
place_name = place.name
place_address = place.address
data = place.data
data_phone = data.formatted_phone_number ? "\nPhone: #{data.formatted_phone_number}" : ''
data_rating = data.rating ? "\nRating: #{data.rating}" : ''
data_price_level = data.price_level ? "\nPrice level (0\{free\}-4): #{data.price_level}" : ''
data_permanently_closed = data.permanently_closed ? 'PERMAMENTLY CLOSED' : ''
data_hours = data.opening_hours
open_now = defined?(data_hours.open_now) ? (data_hours.open_now ? "\nOpen now" : "\nClosed now") : ''
weekday_hours = defined?(data_hours.weekday_text) ?
"\nHours:\n* #{data.opening_hours.weekday_text.join(%Q{\n* })}"
:
''

"#{place_name}\n#{place_address}#{data_phone}#{data_rating}"\
"#{data_price_level}#{data_permanently_closed}#{open_now}#{weekday_hours}"
end

sig { params(places: T::Array[Google::Maps::Place]).returns(String) }
def list_of_places(places)
places.slice(0, 10).map.with_index { |place, index| "(#{index + 1}) #{place}" }.join(%Q{\n})
end
end
end
27 changes: 3 additions & 24 deletions lib/commands/directions.rb
Original file line number Diff line number Diff line change
@@ -1,16 +1,10 @@
# typed: false
# typed: ignore
# frozen_string_literal: true

require_relative './base'
require 'google-maps'

Google::Maps.configure do |config|
config.authentication_mode = Google::Maps::Configuration::API_KEY
config.api_key = ENV['GOOGLE_MAPS_API_KEY']
end
require_relative './google_maps_api'

module Commands
class Directions < Base
class Directions < GoogleMapsAPI
extend T::Sig

class Mode < T::Enum
Expand Down Expand Up @@ -66,21 +60,6 @@ def response_body
RoutePresenter.new(route, mode: query.mode).to_text
end

private

def api_key_missing
<<~MSG
Your Google Maps API key is missing.
Create a new key at: https://developers.google.com/maps/gmp-get-started
Once you get a key, set it to ENV['GOOGLE_MAPS_API_KEY'] on your server.
MSG
end

def api_key_exists?
ENV.key?('GOOGLE_MAPS_API_KEY')
end

class Query < T::Struct
extend T::Sig

Expand Down
29 changes: 29 additions & 0 deletions lib/commands/google_maps_api.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# typed: ignore
# frozen_string_literal: true

require_relative './base'
require 'google-maps'

Google::Maps.configure do |config|
config.authentication_mode = Google::Maps::Configuration::API_KEY
config.api_key = ENV['GOOGLE_MAPS_API_KEY']
end

module Commands
class GoogleMapsAPI < Base
private

def api_key_missing
<<~MSG
Your Google Maps API key is missing.
Create a new key at: https://developers.google.com/maps/gmp-get-started
Once you get a key, set it to ENV['GOOGLE_MAPS_API_KEY'] on your server.
MSG
end

def api_key_exists?
ENV.key?('GOOGLE_MAPS_API_KEY')
end
end
end
88 changes: 2 additions & 86 deletions sorbet/rbi/hidden-definitions/errors.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2320,6 +2320,7 @@
# wrong constant name name
# wrong constant name inherited
# wrong constant name <static-init>
# wrong constant name <static-init>
# wrong constant name polar
# wrong constant name rect
# wrong constant name rectangular
Expand Down Expand Up @@ -2805,97 +2806,12 @@
# wrong constant name stress=
# wrong constant name verify_internal_consistency
# wrong constant name verify_transient_heap_internal_consistency
# wrong constant name <Class:S3URISigner>
# wrong constant name <Class:UriParser>
# wrong constant name <Class:UriParsing>
# wrong constant name _deprecated_default_specifications_dir
# undefined method `deprecate_option<defaultArg>1' for class `Gem::Command'
# Did you mean? deprecate_constant
# undefined method `deprecate_option<defaultArg>2' for class `Gem::Command'
# Did you mean? deprecate_constant
# undefined method `show_lookup_failure<defaultArg>2' for class `Gem::Command'
# wrong constant name check_deprecated_options
# wrong constant name deprecate_option<defaultArg>1
# wrong constant name deprecate_option<defaultArg>2
# wrong constant name deprecate_option
# wrong constant name show_lookup_failure<defaultArg>2
# wrong constant name <=>
# wrong constant name identity
# undefined method `_deprecated_find_gems_with_sources<defaultArg>1' for class `Gem::DependencyInstaller'
# undefined method `_deprecated_find_spec_by_name_and_version<defaultArg>1' for class `Gem::DependencyInstaller'
# undefined method `_deprecated_find_spec_by_name_and_version<defaultArg>2' for class `Gem::DependencyInstaller'
# wrong constant name _deprecated_available_set_for
# wrong constant name _deprecated_find_gems_with_sources<defaultArg>1
# wrong constant name _deprecated_find_gems_with_sources
# wrong constant name _deprecated_find_spec_by_name_and_version<defaultArg>1
# wrong constant name _deprecated_find_spec_by_name_and_version<defaultArg>2
# wrong constant name _deprecated_find_spec_by_name_and_version
# wrong constant name _deprecated_unpack
# wrong constant name package
# wrong constant name gem
# wrong constant name oct_or_256based
# undefined singleton method `raw_spec<defaultArg>1' for `Gem::Package'
# wrong constant name raw_spec<defaultArg>1
# wrong constant name raw_spec
# wrong constant name <Class:FetchError>
# wrong constant name <Class:UnknownHostError>
# wrong constant name _deprecated_fetch_size
# wrong constant name s3_uri_signer
# wrong constant name initialize
# wrong constant name uri
# wrong constant name uri=
# wrong constant name <static-init>
# wrong constant name <static-init>
# wrong constant name default_prerelease
# wrong constant name platform
# uninitialized constant Gem::Resolver::Molinillo::DependencyGraph::Log::Elem
# undefined method `sign<defaultArg>1' for class `Gem::S3URISigner'
# wrong constant name <Class:ConfigurationError>
# wrong constant name <Class:InstanceProfileError>
# wrong constant name <Class:S3Config>
# wrong constant name initialize
# wrong constant name sign<defaultArg>1
# wrong constant name sign
# wrong constant name uri
# wrong constant name uri=
# wrong constant name initialize
# wrong constant name <static-init>
# wrong constant name initialize
# wrong constant name <static-init>
# uninitialized constant Gem::S3URISigner::S3Config::Elem
# wrong constant name access_key_id
# wrong constant name access_key_id=
# wrong constant name region
# wrong constant name region=
# wrong constant name secret_access_key
# wrong constant name secret_access_key=
# wrong constant name security_token
# wrong constant name security_token=
# wrong constant name <static-init>
# wrong constant name []
# wrong constant name members
# wrong constant name <static-init>
# undefined method `typo_squatting?<defaultArg>1' for class `Gem::Source'
# wrong constant name <=>
# wrong constant name typo_squatting?<defaultArg>1
# wrong constant name typo_squatting?
# wrong constant name <=>
# uninitialized constant Gem::Specification::GENERICS
# uninitialized constant Gem::Specification::GENERIC_CACHE
# wrong constant name _deprecated_rubyforge_project=
# undefined singleton method `default_stubs<defaultArg>1' for `Gem::Specification'
# wrong constant name default_stubs<defaultArg>1
# wrong constant name default_stubs
# wrong constant name parse
# wrong constant name parse!
# wrong constant name <static-init>
# wrong constant name <static-init>
# wrong constant name correct_for_windows_path
# wrong constant name add_to_load_path
# wrong constant name default_specifications_dir
# wrong constant name java_platform?
# wrong constant name source_date_epoch
# wrong constant name suffix_regexp
# uninitialized constant HTTP::Message::AddressableEnabled
# uninitialized constant HTTPClient::AddressableEnabled
# uninitialized constant HTTPClient::SSLConfig::AddressableEnabled
Expand Down Expand Up @@ -5336,7 +5252,7 @@
# wrong constant name <static-init>
# wrong constant name worse_than?
# wrong constant name +
# uninitialized constant #<Class:0x00007fbfabb8ed78>::Elem
# uninitialized constant #<Class:0x00007fb8e79395c0>::Elem
# wrong constant name candidate?
# wrong constant name ideal?
# wrong constant name indeterminate_actual_indexes
Expand Down
Loading

0 comments on commit 22e820f

Please sign in to comment.