Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/algonauti/google_maps_juice
Drink Google Maps Services with ease! :tropical_drink: :earth_americas:
https://github.com/algonauti/google_maps_juice
geocoding google google-maps-api ruby rubygem timezone
Last synced: about 1 month ago
JSON representation
Drink Google Maps Services with ease! :tropical_drink: :earth_americas:
- Host: GitHub
- URL: https://github.com/algonauti/google_maps_juice
- Owner: algonauti
- License: mit
- Created: 2018-08-07T18:44:31.000Z (over 6 years ago)
- Default Branch: master
- Last Pushed: 2020-07-17T14:27:04.000Z (over 4 years ago)
- Last Synced: 2024-04-29T17:20:48.649Z (8 months ago)
- Topics: geocoding, google, google-maps-api, ruby, rubygem, timezone
- Language: Ruby
- Homepage:
- Size: 113 KB
- Stars: 2
- Watchers: 5
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE.txt
Awesome Lists containing this project
README
# GoogleMapsJuice
**Drink Google Maps Services with ease!** :tropical_drink: :earth_americas:
[![Build Status](https://travis-ci.org/algonauti/google_maps_juice.svg?branch=master)](https://travis-ci.org/algonauti/google_maps_juice)
[![Coverage Status](https://coveralls.io/repos/github/algonauti/google_maps_juice/badge.svg?branch=master)](https://coveralls.io/github/algonauti/google_maps_juice?branch=master)This gem aims at progressively covering a fair amount of those widely-used services that are part of the Google Maps Platform, such as: [Geocoding](https://developers.google.com/maps/documentation/geocoding/intro), [Time Zone](https://developers.google.com/maps/documentation/timezone/intro), [Directions](https://developers.google.com/maps/documentation/directions/intro), etc. with some key ideas:
1. Allowing "standard" requests, meaning: sending the same params documented by Google.
2. Allowing "smart" requests, meaning: with more "developer-friendly" params, and/or improved error handling.
3. Return full Google responses, but also provide methods to easily inspect the most relevant info.
4. Provide error handling.`GoogleMapsJuice` currently covers:
* Geocoding
* Time Zone
* DirectionsContributors are welcome!
## Installation
Add this line to your application's Gemfile:
```ruby
gem 'google_maps_juice'
```And then execute:
$ bundle
Or install it yourself as:
$ gem install google_maps_juice
## Google API Key
You can set your Google API key with the following one-liner:
```ruby
GoogleMapsJuice.configure { |c| c.api_key = 'my-api-key' }`
```In a Rails application, that would typically go in an initializer.
### Multiple API keys
If you need to use multiple API keys, you have two options:
* a) pass an `api_key` named param to the endpoint class method, e.g.
```ruby
GoogleMapsJuice::Geocoding.geocode(params, api_key: 'my-api-key')
```* b) create your own `GoogleMapsJuice::Client` instance(s) and use it to create your endpoint object(s), e.g.
```ruby
client = GoogleMapsJuice::Client.new(api_key: 'my-api-key')
geocoding = GoogleMapsJuice::Geocoding.new(client)
response = geocoding.geocode(params)
```This is especially useful in some "hybrid" scenario, where an API key is shared by a group of requests, but another group uses a different key: a `client` object would then be instantiated and reused for each group.
## Error Handling
If Google servers respond with a non-successful HTTP status code, i.e. `4xx` or `5xx`, a `GoogleMapsJuice::ResponseError` is raised with a message of the form `'HTTP 503 - Error details as returned by the server'`.
API errors are also handled, based on the `status` attribute of Google's JSON response, and the optional `error_message` attribute.
* `GoogleMapsJuice::ZeroResults` is raised when `status` is `'ZERO_RESULTS'`
* `GoogleMapsJuice::ApiLimitError` is raised when `status` is `'OVER_DAILY_LIMIT'` or `'OVER_QUERY_LIMIT'`
* `GoogleMapsJuice::ResponseError` is raised when `status` is not `OK` with a message of the form `API - `## Geocoding
### Standard Geocoding
The simplest geocoding requests accept an address:
```ruby
response = GoogleMapsJuice::Geocoding.geocode(address: '8955 Lantana Rd, Lake Worth, FL 33467, USA')
```Supported params are the ones accepted by Google's endpoint: `address`, `components`, `bounds`, `language`, `region`; at least one between `address` and `components` is required. Learn more [here](https://developers.google.com/maps/documentation/geocoding/intro#geocoding). `GoogleMapsJuice` will raise an `ArgumentError` if some unsupported param is passed, or when none of the required params are passed.
### Smart Geocoding
**Motivation**
For best geocoding results, the `address` param should be formatted according to the local language. This is often a hard task for an application that needs to geocode addresses stored as separate fields. Luckily, Google offers the `components` param which accepts individual address fields; however, it's annoying to build it and it's not fault tolerant. For example, an error on `postal_code` makes geocoding of a whole address fail.
Purpose of `i_geocode` method is twofold:
1. Providing a simpler method interface for leveraging Google's `components` param
2. Providing an approximate geocoding result when some address component is wrongHere an example call with all supported params:
```ruby
response = GoogleMapsJuice::Geocoding.i_geocode(
{
address: '8955 Lantana Rd',
locality: 'Lake Worth',
administrative_area: 'FL',
postal_code: '33467',
country: 'US'
}, sleep_before_retry: 0.15
)
```**Accepted params:**
* At least one between `address` and `country` is required
* `locality`, `administrative_area`, `postal_code` and `country` expect the same content as described in [Component Filtering](https://developers.google.com/maps/documentation/geocoding/intro#ComponentFiltering)
* `address` can also include more info than street number and name, as long as they do not contrast with other params passed
* An optional `sleep_before_retry` param sets seconds between geocoding attempts (see below); defaults to zero.
* `GoogleMapsJuice` will raise an `ArgumentError` if some unsupported param is passed, or when none of the required params are passed.**How it works**
On its 1st attempt, `i_geocode` sends all received params to Google's endpoint, properly formatted. If a `GoogleMapsJuice::ZeroResults` is raised, it removes a param and retries until no error is raised. Params are removed in the following order:
* `postal_code`
* `address`
* `locality`
* `administrative_area`As a consequence:
* In the best case, `i_geocode` will send 1 request to Google API
* In the worst case, `i_geocode` will send 4 requests to Google API### Geocoding Response
Both `geocode` and `i_geocode` methods return a `GoogleMapsJuice::Geocoding::Response`. It's a `Hash` representation of Google's JSON response. However, it also provides many useful methods:
* `latitude`, `longitude`: geographic coordinates as `float` numbers
* `street_number`, `route`, `locality`, `postal_code`, `administrative_area_level_1`, `country`: all of these methods return a `Hash` with 2 keys: `'short_name'` and `'long_name'`
* `partial_match?`: boolean, `true` if some param (of the last geocoding attempt) partially matched
* `precision`: can be one of: `'street_number'`, `'route'`, `'locality'`, `'postal_code'`, `'administrative_area_level_1'`, `'country'` and represents the most-specific matching component
## Time Zone
[Google's Time Zone API](https://developers.google.com/maps/documentation/timezone/intro#Requests) returns the time zone of a given geographic location; it also accepts a timestamp, in order to determine whether DST should be applied or not.
GoogleMapsJuice provides the `GoogleMapsJuice::Timezone.by_location` method. Compared to Google's raw API request, it provides simpler params and some validations, in order to avoid sending requests when they would fail for sure (and then save money!) - to learn more see `spec/unit/timezone_spec.rb`.
**Accepted params:**
* Both `latitude` and `longitude` are mandatory
* `timestamp` is optional and defaults to `Time.now`
* `language` is optional### Time Zone Response
The `by_location` method returns a `GoogleMapsJuice::Timezone::Response`. It's a `Hash` representation of Google's JSON response. However, it also provides a few useful methods:
* `timezone_id`: unique name as defined in [IANA Time Zone Database](https://www.iana.org/time-zones)
* `timezone_name`: the long form name of the time zone
* `raw_offset`: the offset from UTC in seconds
* `dst_offset`: the offset for daylight-savings time in seconds
## Directions
[Google's Directions API](https://developers.google.com/maps/documentation/directions/intro#DirectionsRequests) returns the possible routes of given origin and destination geographic locations; Google's API accepts address, textual latitude/longitude value, or place ID of which you wish to calculate directions. Currently this gem implements only latitude/longitude mode.
`GoogleMapsJuice` will raise an `ArgumentError` if some unsupported param is passed, or when none of the required params are passed.```ruby
response = GoogleMapsJuice::Directions.find(origin: '41.8892732,12.4921921', destination: '41.9016488,12.4583003')
```Compared to Google's raw API request, it provides validation of both origin and destination, in order to avoid sending requests when they would fail for sure - to learn more see `spec/unit/directions_spec.rb`.
**Accepted params:**
* Both `origin` and `destination` are mandatory
* `origin` is composed by `latitude` and `longitude`, comma separated float values
* `destination` same format as `origin`### Directions Response
The `find` method returns a `GoogleMapsJuice::Directions::Response`. It's a `Hash` representation of Google's JSON response. However, it also provides a few useful methods:
* `results`: the `Hash` raw result
* `routes`: an `Array` of `GoogleMapsJuice::Directions::Response::Route` objects
* `first`: the first `Route` of the `routes` `List`
As described in [Google's Directions API](https://developers.google.com/maps/documentation/directions/intro#Routes), the response contains all possible routes. Each route has some attributes and one or more *legs*, wich in turn have one or more *steps*.
If no waypoints are passed, the route response will contain a single leg. Since `GoogleMapsJuice::Directions` doesn't handles waypoints yet, only the first leg is considered for each route.
The `GoogleMapsJuice::Directions::Response::Route` is a representation of a response route and provides methods to access all route's attributes:* `summary`: a brief description of the route
* `legs`: all legs of the route, generally a single one
* `steps`: all steps of the first route's leg
* `duration`: time duration of the first route's leg
* `distance`: distance between origin and destination of first route's leg
* `start_location`: `latitude`/`longitude` of the origin first route's leg
* `end_location`: `latitude`/`longitude` of the destination first route's leg
* `start_address`: address of the origin first route's leg
* `end_address`: address of the destination first route's leg
## Development
After checking out the repo, run `bin/setup` to install dependencies. Create a `.env` file and save your Google API key there; if you want to use a different key for testing, put it in `.env.test` and it will override the one in `.env`.
Run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags and push the `.gem` file to [rubygems.org](https://rubygems.org).
### Implementing a new endpoint
All endpoints must be subclasses of `GoogleMapsJuice::Endpoint`; methods that implement "standard" Google API calls have a common structure, described by the `invoke` method in the `SomeEndpoint` test class in `spec/unit/endpoint_spec.rb`.
All new endpoints' methods must return subclasses of `GoogleMapsJuice::Endpoint::Response` as their response objects, since it contains methods needed for error handling.
## Contributing
Bug reports and pull requests are welcome on GitHub at https://github.com/algonauti/google_maps_juice.
## License
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).