geosack 1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (4) hide show
  1. data/README +44 -0
  2. data/lib/geosack.rb +126 -0
  3. data/test/geosack_test.rb +44 -0
  4. metadata +54 -0
data/README ADDED
@@ -0,0 +1,44 @@
1
+ == Geosack On Rails
2
+
3
+ This plugin enables you to utilize geosack.com unique geocode caching service. Geosack provides a persistent api that caches google-map/geocode lookups - enabling you to re-request the same information any number of times you like without exceeding your quota's or rate-limits from google.
4
+
5
+ To install the plugin, extract the files from the archive to a directory named "geosack" in your vendors/plugin directory.
6
+
7
+ Using the plugin is straightforward:
8
+
9
+ To use the geocoding service you will need a google API key, obtained from here:
10
+
11
+ http://code.google.com/apis/maps/signup.html
12
+
13
+ Once you have this key, you can create your Geosack object:
14
+
15
+ geosack = Geosack::Base.new(:api_key => YOUR_API_KEY)
16
+
17
+ Then you are free to start making geocode requests.
18
+
19
+ result, location = geosack.geo(:q => 'San Jose')
20
+
21
+ The placename to be looked is specified by the :q parameter. The only other parameter is :output which is the response format - KML/XML/JSON. The default response format is XML.
22
+
23
+ You don't need to worry about the 2 second delay that google requires - geosack takes care of that for you.
24
+
25
+ The result object is a reflection of the response returned by google to your request. Anything other than a 200 (G_GEO_SUCCESS) is a failure.
26
+
27
+ You will also need to check for 610 (G_GEO_TOO_MANY_QUERIES) responses which indicate you have reached your limit for the 24 period. Note that this limit only applies to new requests sent to google - if you send a request that has already been cached by geosack, the response will come from geosack, not from google, and your daily limit will be unaffected.
28
+
29
+ Heres an example to get your started:
30
+
31
+ geosack = Geosack::Base.new(:key => API_KEY)
32
+ result, resp = geosack.geo(:q => lookup)
33
+ if result == Geosack::StatusCodes::G_GEO_SUCCESS
34
+ doc = REXML::Document.new(resp)
35
+ doc.root.each_element('//Response') do |response|
36
+ response.each_element('//Placemark') do |place|
37
+ longitude,latitude = place.elements['//coordinates'].text.split(',')
38
+ end
39
+ end
40
+ else
41
+ # failed
42
+ end
43
+
44
+ Have fun, and feel free to contact us at mailto:info@packetnode.com with any questions or suggestions.
data/lib/geosack.rb ADDED
@@ -0,0 +1,126 @@
1
+ # Copyright (c) 2008 Philip Mcmahon
2
+ #
3
+ # Permission is hereby granted, free of charge, to any person obtaining a copy
4
+ # of this software and associated documentation files (the "Software"), to deal
5
+ # in the Software without restriction, including without limitation the rights
6
+ # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7
+ # copies of the Software, and to permit persons to whom the Software is
8
+ # furnished to do so, subject to the following conditions:
9
+ #
10
+ # The above copyright notice and this permission notice shall be included in
11
+ # all copies or substantial portions of the Software.
12
+ #
13
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14
+ # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15
+ # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16
+ # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17
+ # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18
+ # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
+ # THE SOFTWARE.
20
+
21
+ module Geosack #:nodoc:
22
+
23
+ class GeosackError < StandardError; end #:nodoc
24
+
25
+ # Base class
26
+ class Base
27
+
28
+ # Defines the required parameter(s)
29
+ REQUIRED_OPTIONS = {:base => [:key],
30
+ :geo => [:q]}
31
+
32
+ GEOSACK_URL = 'http://www.geosack.com/maps/geo'
33
+ STATUS_RESPONSE = '//kml/Response/Status/code'
34
+
35
+ attr_accessor :key
36
+
37
+ # Initializes the Geosack::Base class
38
+ #
39
+ # geosack = Geosack::Base.new(:api_key => 'MY_API_KEY')
40
+ #
41
+ # === Required options
42
+ # :api_key - Your Google geocoding/maps API key
43
+ def initialize(options = {})
44
+ check_options(:base, options)
45
+ @key = CGI.escape(options[:key])
46
+ end
47
+
48
+ # Geocodes an address from Geosack
49
+ #
50
+ # > geosack = Geosack::Base.new(:api_key => 'MY_API_KEY')
51
+ # > result, location = geosack.geo('San Jose')
52
+ #
53
+ # > result
54
+ # 200
55
+ # > location
56
+ # ... <kml xmlns='http://earth.google.com/kml/2.0'><Response><name>San Jose</name> ...
57
+ #
58
+ # === Required options
59
+ # :q - The query you wish to submit to Geosack, e.g. 'San Jose'
60
+ #
61
+ # === Optional options
62
+ # :output - The output format you are expecting - see Module Outputs
63
+ def geo(options = {})
64
+
65
+ # Check options
66
+ check_options(:geo, options)
67
+ q = CGI.escape(options[:q])
68
+ output = options[:output] ? CGI.escape(options[:output]) : Outputs::XML
69
+
70
+ # first we'll open the url
71
+ resp = open("#{GEOSACK_URL}?q=#{q}&output=#{output}&key=#{@key}").read
72
+
73
+ # then we'll check for the status
74
+ begin
75
+ doc = REXML::Document.new(resp)
76
+ result = doc.elements[STATUS_RESPONSE].text.to_i
77
+ rescue Exception # bad - too generic
78
+ if output == Outputs::JSON
79
+ # :{"code":200,"request":"geocode"}
80
+ result = resp.scan(/\d+/)[0].to_i
81
+ puts result
82
+ else
83
+ result = StatusCodes::G_GEO_SERVER_ERROR
84
+ end
85
+ end
86
+
87
+ [result, resp]
88
+ end
89
+
90
+ private
91
+
92
+ # Checks options
93
+ def check_options(method_name, options = {})
94
+ required_options = REQUIRED_OPTIONS[method_name]
95
+ missing = []
96
+ required_options.each{|option| missing << option if options[option].nil?}
97
+
98
+ unless missing.empty?
99
+ raise GeosackError.new("Missing #{missing.collect{|m| ":#{m}"}.join(', ')}")
100
+ end
101
+ end
102
+
103
+ end # Base
104
+
105
+ # Allowed response formats
106
+ module Outputs
107
+ XML = "xml"
108
+ JSON = "json"
109
+ KML = "kml"
110
+ end
111
+
112
+ # http://code.google.com/apis/maps/documentation/reference.html#GGeoStatusCode
113
+ module StatusCodes
114
+ G_GEO_SUCCESS = 200
115
+ G_GEO_BAD_REQUEST = 400
116
+ G_GEO_SERVER_ERROR = 500
117
+ G_GEO_MISSING_QUERY = 601
118
+ G_GEO_MISSING_ADDRESS = 601
119
+ G_GEO_UNKNOWN_ADDRESS = 602
120
+ G_GEO_UNAVAILABLE_ADDRESS = 603
121
+ G_GEO_UNKNOWN_DIRECTIONS = 604
122
+ G_GEO_BAD_KEY = 610
123
+ G_GEO_TOO_MANY_QUERIES = 620
124
+ end
125
+
126
+ end
@@ -0,0 +1,44 @@
1
+ require 'test/unit'
2
+ require 'geosack'
3
+ require 'cgi'
4
+ require 'open-uri'
5
+ require 'rexml/document'
6
+
7
+ class GeosackTest < Test::Unit::TestCase
8
+
9
+ # sample google key
10
+ API_KEY = "ABQIAAAAEMOKUmwrte1WeNNUKp0ckxTlf0blA_rqbbsuTeo2-FuKFlnNphQEGVnMEOB5H-hLCg_bC_vszRN8Yw"
11
+ INVALID_KEY = "Invalid Key"
12
+
13
+ def test_valid_lookup
14
+ # sample google key
15
+ latitude, longitude = 0.0, 0.0
16
+ lookup = "San Jose"
17
+ geosack = Geosack::Base.new(:key => API_KEY)
18
+ result, resp = geosack.geo(:q => lookup)
19
+ assert_equal(Geosack::StatusCodes::G_GEO_SUCCESS, result)
20
+ doc = REXML::Document.new(resp)
21
+ doc.root.each_element('//Response') do |response|
22
+ response.each_element('//Placemark') do |place|
23
+ longitude,latitude = place.elements['//coordinates'].text.split(',')
24
+ end
25
+ end
26
+ assert_equal(37.316466, latitude.to_f)
27
+ assert_equal(-121.873881, longitude.to_f)
28
+ end
29
+
30
+ def test_invalid_lookup
31
+ lookup = "invalid lookup"
32
+ geosack = Geosack::Base.new(:key => API_KEY)
33
+ result, resp = geosack.geo(:q => lookup)
34
+ assert_equal(Geosack::StatusCodes::G_GEO_UNKNOWN_ADDRESS, result)
35
+ end
36
+
37
+ def test_invalid_key
38
+ geosack = Geosack::Base.new(:key => INVALID_KEY)
39
+ lookup = "San Jose"
40
+ result, resp = geosack.geo(:q => lookup)
41
+ assert_equal(Geosack::StatusCodes::G_GEO_BAD_KEY, result)
42
+ end
43
+
44
+ end
metadata ADDED
@@ -0,0 +1,54 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: geosack
3
+ version: !ruby/object:Gem::Version
4
+ version: "1.0"
5
+ platform: ruby
6
+ authors:
7
+ - Philip Mcmahon
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2008-02-17 00:00:00 -07:00
13
+ default_executable:
14
+ dependencies: []
15
+
16
+ description:
17
+ email: info@packetnode.com
18
+ executables: []
19
+
20
+ extensions: []
21
+
22
+ extra_rdoc_files:
23
+ - README
24
+ files:
25
+ - lib/geosack.rb
26
+ - README
27
+ has_rdoc: true
28
+ homepage: http://geosack.com
29
+ post_install_message:
30
+ rdoc_options: []
31
+
32
+ require_paths:
33
+ - lib
34
+ required_ruby_version: !ruby/object:Gem::Requirement
35
+ requirements:
36
+ - - ">="
37
+ - !ruby/object:Gem::Version
38
+ version: "0"
39
+ version:
40
+ required_rubygems_version: !ruby/object:Gem::Requirement
41
+ requirements:
42
+ - - ">="
43
+ - !ruby/object:Gem::Version
44
+ version: "0"
45
+ version:
46
+ requirements: []
47
+
48
+ rubyforge_project: geosack_plugin
49
+ rubygems_version: 1.0.1
50
+ signing_key:
51
+ specification_version: 2
52
+ summary: This ruby on rails plugin enables you to utilize the geosack.com unique geocode caching service, which provides a persistent api that caches your google-map/geocode lookups.
53
+ test_files:
54
+ - test/geosack_test.rb