Skip to content

Commit

Permalink
Merge pull request #13 from brentsowers1/businessKeys
Browse files Browse the repository at this point in the history
1.2.0 - finished up business key support with tests, and licensing
  • Loading branch information
brentsowers1 committed Mar 3, 2014
2 parents 21ca4da + 37a3ede commit 0065b1f
Show file tree
Hide file tree
Showing 8 changed files with 126 additions and 90 deletions.
5 changes: 5 additions & 0 deletions History.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
== 1.2.0 / 2014-03-03
* Added support for setting an API key for monitoring, and a client ID/private key for business customers (thanks forrest!)
* Changed to use maps.googleapis.com instead of maps.google.com (thanks nathany!)
* Explicitly added MIT licensing

== 1.1.4 / 2013-07-04
* Properly URL encoding the URLs, caused an issue when using URI.parse on generated URLs (thanks nathany!)

Expand Down
21 changes: 21 additions & 0 deletions LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
The MIT License (MIT)

Copyright (c) 2010-2014 Brent Sowers

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
27 changes: 23 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,10 +57,29 @@ If you're working behind a proxy, create the map object this way:

map = GoogleStaticMap.new(:proxy_address=>'my.proxy.host', :proxy_port=>8080, :width => 640, :height => 480)

If you have a public API key for tracking usage (https://developers.google.com/maps/documentation/staticmaps/#api_key):

Author:: Brent Sowers (mailto:[email protected])
map = GoogleStaticMap.new(:api_key => "my_api_key")

If you are a Maps For Businesses customer with a client ID and private key (https://developers.google.com/maps/documentation/business/webservices/#client_id)
(note that you cannot set an api_key if you want to use client_id and private_key):

map = GoogleStaticMap.new(:client_id => "my_client_id", :private_key => "my_private_key")

## Compatibility

This has been tested and is working with Ruby 1.8.7, 1.9.3, 2.0.0, and 2.1.1, and JRuby 1.7.11.

## Author

Brent Sowers (mailto:[email protected])

## Feedback

To post comments about this gem, go to my blog posting at http://www.brentsowers.com/2010/08/gem-for-getting-google-static-maps.html. Contributions are also welcome! Fork the repo and issue a pull request, and I'll review it.

## License

googlestaticmap is released under the [MIT License](http://www.opensource.org/licenses/MIT). You're free to do whatever you want with this.

License:: You're free to do whatever you want with this

To post comments about this gem, go to my blog posting at
http://www.brentsowers.com/2010/08/gem-for-getting-google-static-maps.html
4 changes: 2 additions & 2 deletions example.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
print "\n"
map = GoogleStaticMap.new(:zoom => 11, :center => MapLocation.new(:address => "Washington, DC"))
image = map.get_map
print "Got a map of size #{image.length}, should be rougly 100K\n"
print "Got a map of size #{image.length}, should be roughly 100K\n"
image_url = map.url(:auto)
print "The URL for this map is '#{image_url}'\n"

Expand All @@ -23,7 +23,7 @@
map.markers << MapMarker.new(:color => "blue", :location => MapLocation.new(:address => "1 1st Street Northeast, Washington, DC"))
image = map.get_map

print "Got a map of size #{image.length}, should be rougly 50K\n"
print "Got a map of size #{image.length}, should be roughly 50K\n"
image_url = map.url(:auto)
print "The URL for this map is '#{image_url}'\n"

Expand Down
Binary file added googlestaticmap-1.2.0.gem
Binary file not shown.
7 changes: 4 additions & 3 deletions googlestaticmap.gemspec
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
Gem::Specification.new do |spec|
spec.name = 'googlestaticmap'
spec.version = '1.1.4'
spec.files = Dir['lib/**/*', 'test/**/*', 'README', 'History.txt']
spec.version = '1.2.0'
spec.license = 'MIT'
spec.files = Dir['lib/**/*', 'test/**/*', 'README.md', 'History.txt']
spec.test_files = Dir.glob('test/tc_*.rb')

spec.summary = 'Class for retrieving maps from the Google Maps Static API service'
spec.description = "Easily retrieve single PNG, GIF, or JPG map images from Google with your own custom markers and paths using the Static Maps API service with this gem. Simply set the attributes you want for your map and GoogleStaticMap will take care of getting the map for you, or giving your the URL to retrieve the map."

spec.authors = 'Brent Sowers'
spec.email = '[email protected]'
spec.extra_rdoc_files = ['README','History.txt']
spec.extra_rdoc_files = ['README.md','History.txt']
spec.homepage = 'http://www.coordinatecommons.com/googlestaticmap/'
end
100 changes: 26 additions & 74 deletions lib/googlestaticmap.rb
Original file line number Diff line number Diff line change
@@ -1,61 +1,9 @@
# = googlestaticmap gem
#
# This gem is on Rubygems, simply type "gem install googlestaticmap" to install it.
#
# Available on github at http://github.com/brentsowers1/googlestaticmap
#
# Class for generating URLs for and downloading static maps from the Google Maps
# Static API service. GoogleStaticMap is the main class to use, instantiate it,
# set the attributes to what you want, and call full_url on the instance to get
# the URL to download the map from. You can also call get_map to actually
# download the map from Google, return the bytes, and optionally write the
# image to a file.
#
# Examples:
#
# Get a simple static map centered at Washington, DC, with the default size
# (500 x 350), zoomed to level 11
# map = GoogleStaticMap.new(:zoom => 11, :center => MapLocation.new(:address => "Washington, DC"))
# image = map.get_map
#
# Get the URL of the image described in the previous example, so you can insert
# this URL as the src of an img element on an HTML page
# require 'googlestaticmap'
# map = GoogleStaticMap.new(:zoom => 11, :center => MapLocation.new(:address => "Washington, DC"))
# image_url = map.url(:auto)
#
# Get a map with blue markers at the White House and the Supreme Court, zoomed
# the closest that the map can be with both markers visible, at the default
# size.
# map = GoogleStaticMap.new
# map.markers << MapMarker.new(:color => "blue", :location => MapLocation.new(:address => "1600 Pennsylvania Ave., Washington, DC"))
# map.markers << MapMarker.new(:color => "blue", :location => MapLocation.new(:address => "1 1st Street Northeast, Washington, DC"))
# image = map.get_map
#
# Get a GIF satellite map, with a size of 640 x 480, with a
# semi transparent green box drawn around a set of 4 coordinates, with the box
# outline solid, centered at the middle of the box, written out to the file
# map.gif:
# map = GoogleStaticMap.new(:maptype => "satellite", :format => "gif", :width => 640, :height => 480)
# poly = MapPolygon.new(:color => "0x00FF00FF", :fillcolor => "0x00FF0060")
# poly.points << MapLocation.new(:latitude => 38.8, :longitude => -77.5)
# poly.points << MapLocation.new(:latitude => 38.8, :longitude => -76.9)
# poly.points << MapLocation.new(:latitude => 39.2, :longitude => -76.9)
# poly.points << MapLocation.new(:latitude => 39.2, :longitude => -77.5)
# poly.points << MapLocation.new(:latitude => 38.8, :longitude => -77.5)
# map.paths << poly
# map.get_map("map.gif")
#
# If you're working behind a proxy, create the map object this way:
# map = GoogleStaticMap.new(:proxy_address=>'my.proxy.host', :proxy_port=>8080, :width => 640, :height => 480)
#
# Author:: Brent Sowers (mailto:[email protected])
# License:: You're free to do whatever you want with this
#
# To post comments about this gem, go to my blog posting at
# http://www.brentsowers.com/2010/08/gem-for-getting-google-static-maps.html
# Main file for the googlestaticmap gem. See README.md for a full desciption with examples, licensing, contact
# info, etc.

require 'cgi'
require 'base64'
require 'openssl'
require 'net/http'
require 'net/https' if RUBY_VERSION < "1.9"
require File.dirname(__FILE__) + '/googlestaticmap_helper'
Expand Down Expand Up @@ -118,18 +66,22 @@ class GoogleStaticMap
# If proxy_address is set, set this to the port of the proxy server
attr_accessor :proxy_port

# Key - see https://developers.google.com/maps/documentation/staticmaps/#api_key for details
attr_accessor :key
# API Key - see https://developers.google.com/maps/documentation/staticmaps/#api_key for details
# Note that if this is set, the client ID and private key will be ignored if set
attr_accessor :api_key

# ClientId/PrivateKey - see https://developers.google.com/maps/documentation/business/webservices/auth#generating_valid_signatures for details
attr_accessor :client
# ClientId/PrivateKey for business customers -
# see https://developers.google.com/maps/documentation/business/webservices/auth#generating_valid_signatures for details
# These will be ignored if api_key is set
attr_accessor :client_id
attr_accessor :private_key

# Takes an optional hash of attributes
def initialize(attrs={})
defaults = {:width => 500, :height => 350, :markers => [],
:sensor => false, :maptype => "roadmap", :paths => [],
:proxy_port => nil, :proxy_address => nil}
:proxy_port => nil, :proxy_address => nil, :api_key => nil,
:client_id => nil, :private_key => nil}

attributes = defaults.merge(attrs)
attributes.each {|k,v| self.send("#{k}=".to_sym,v)}
Expand All @@ -149,30 +101,30 @@ def url(protocol='http')
protocol = 'http' unless protocol == 'http' || protocol == 'https' ||
protocol == :auto
protocol = protocol == :auto ? '' : protocol + ":"
u = "#{protocol}//maps.googleapis.com"
base = "#{protocol}//maps.googleapis.com"
path = "/maps/api/staticmap?"
attrs = GoogleStaticMapHelpers.safe_instance_variables(self,
["markers", "paths", "width", "height", "center",
"proxy_address", "proxy_port", "key", "private_key"],
"proxy_address", "proxy_port", "api_key", "client_id",
"private_key"],
:cgi_escape_values => true).to_a
attrs << ["size", "#{@width}x#{@height}"] if @width && @height
markers.each {|m| attrs << ["markers",m.to_s] }
paths.each {|p| attrs << ["path",p.to_s] }
attrs << ["center", center.to_s] if !center.nil?
@markers.each {|m| attrs << ["markers",m.to_s] }
@paths.each {|p| attrs << ["path",p.to_s] }
attrs << ["center", @center.to_s] if !@center.nil?
attrs << ["key", @api_key] if !@api_key.nil?
attrs << ["client", @client_id] if @api_key.nil? && !@client_id.nil? && !@private_key.nil?
path << attrs.collect {|attr| "#{attr[0]}=#{attr[1]}"}.join("&")
if key
u << path << "&key=" << key
elsif client && private_key
u << path << "&signature=" << sign(path)
else
u << path
if @api_key.nil? && !@client_id.nil? && !@private_key.nil?
path << "&signature=" << sign(path)
end
base + path
end

# Returns the URL to retrieve the map, relative to http://maps.googleapis.com
# Example - "/maps/api/staticmap?params..."
def relative_url(protocol='http')
url(protocol).gsub(/[^\/]*\/\/maps\.google\.com/, "")
url(protocol).gsub(/[^\/]*\/\/maps\.googleapis\.com/, "")
end


Expand Down Expand Up @@ -209,7 +161,7 @@ def get_map(output_file=nil, protocol='http')

# signing code is grabbed from https://github.com/alexreisner/geocoder
def sign(path)
raw_private_key = url_safe_base64_decode(private_key)
raw_private_key = url_safe_base64_decode(@private_key)
digest = OpenSSL::Digest.new('sha1')
raw_signature = OpenSSL::HMAC.digest(digest, raw_private_key, path)
url_safe_base64_encode(raw_signature)
Expand Down
52 changes: 45 additions & 7 deletions test/tc_google_static_map.rb
Original file line number Diff line number Diff line change
Expand Up @@ -67,35 +67,73 @@ def test_url
assert u.include?("maptype=hybrid")
assert u.include?("scale=2")
assert u.include?("asdf")
assert u.include?("http://maps.google.com")
assert u.include?("color:0x00FF00FF#{MAP_SEPARATOR}fillcolor:0x00FF0060#{MAP_SEPARATOR}38.8,-77.5#{MAP_SEPARATOR}38.8,-76.9#{MAP_SEPARATOR}39.2,-76.9#{MAP_SEPARATOR}39.2,-77.5#{MAP_SEPARATOR}38.8,-77.5"), "Polygon not in URL"
assert u.include?("http://maps.googleapis.com")
assert u.include?("color:0x00FF00FF")
assert u.include?("fillcolor:0x00FF0060")
assert u.include?("38.8,-77.5#{MAP_SEPARATOR}38.8,-76.9#{MAP_SEPARATOR}39.2,-76.9#{MAP_SEPARATOR}39.2,-77.5#{MAP_SEPARATOR}38.8,-77.5"), "Polygon not in URL - #{u}"
assert u.include?("Washington%2C+DC")
assert !u.include?("key"), "API included when it shouldn't be"
assert !u.include?("client"), "Client included when it shouldn't be"

f = nil
assert_nothing_raised {f = g.relative_url}
assert !f.include?("http://maps.google.com")
assert !f.include?("http://maps.googleapis.com")
end

def test_url_auto
g = default_map
u = nil
assert_nothing_raised { u = g.url(:auto) }
assert_equal 7, u.split("&").length, u
assert u =~ /^\/\/maps.google.com/, u
assert u =~ /^\/\/maps.googleapis.com/, u
f = nil
assert_nothing_raised {f = g.relative_url}
assert_no_match /^\/\/maps.google.com/, f
assert_no_match /^\/\/maps.googleapis.com/, f
end

def test_url_https
g = default_map
u = nil
assert_nothing_raised { u = g.url('https') }
assert_equal 7, u.split("&").length, u
assert u =~ /^https:\/\/maps.google.com/
assert u =~ /^https:\/\/maps.googleapis.com/
f = nil
assert_nothing_raised {f = g.relative_url}
assert_no_match /^https:\/\/maps.google.com/, f
assert_no_match /^https:\/\/maps.googleapis.com/, f
end

def test_url_api_key
g = default_map
g.api_key = "asdfapikey"
u = nil
assert_nothing_raised { u = g.url }
assert_equal 8, u.split("&").length, u
assert u.include?("key=asdfapikey"), u
assert !u.include?("client"), u
assert !u.include?("signature"), u
end

def test_url_for_business
g = default_map
g.client_id = "asdfclientid"
g.private_key = "asdfprivatekey"
u = nil
assert_nothing_raised { u = g.url }
assert_equal 9, u.split("&").length, u
assert u.include?("signature="), u
assert u.include?("client=asdfclientid"), u
assert !u.include?("key="), u
end

def test_url_for_business_no_key
g = default_map
g.client_id = "asdfclientid"
u = nil
assert_nothing_raised { u = g.url }
assert_equal 7, u.split("&").length, u
assert !u.include?("signature=")
assert !u.include?("client=asdfclientid")
assert !u.include?("key=")
end

def test_get_map_success_no_file_http
Expand Down

0 comments on commit 0065b1f

Please sign in to comment.