heycarsten-gcoder 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
data/.document ADDED
@@ -0,0 +1,5 @@
1
+ README.rdoc
2
+ lib/**/*.rb
3
+ bin/*
4
+ features/**/*.feature
5
+ LICENSE
data/.gitignore ADDED
@@ -0,0 +1,3 @@
1
+ coverage
2
+ rdoc
3
+ pkg
data/README.rdoc ADDED
@@ -0,0 +1,7 @@
1
+ = GCoder
2
+
3
+ Instead of letting postal codes turn me into a postal coder, I made this gem!
4
+
5
+ == Copyright
6
+
7
+ Copyright (C) 2009 Carsten Nielsen. See LICENSE for details.
data/Rakefile ADDED
@@ -0,0 +1,58 @@
1
+ require 'rubygems'
2
+ require 'rake'
3
+
4
+
5
+ begin
6
+ require 'jeweler'
7
+ Jeweler::Tasks.new do |g|
8
+ g.name = 'gcoder'
9
+ g.summary = 'A library for geocoding postal codes via the Google Maps ' \
10
+ 'Geocoding API with a persisted cache through Tokyo Tyrant'
11
+ g.email = 'heycarsten@gmail.com'
12
+ g.homepage = 'http://github.com/heycarsten/gcoder'
13
+ g.authors = ['Carsten Nielsen']
14
+ end
15
+ rescue LoadError
16
+ puts 'Jeweler not available. Install it with: sudo gem install ' \
17
+ 'technicalpickles-jeweler -s http://gems.github.com'
18
+ end
19
+
20
+
21
+ require 'rake/testtask'
22
+ Rake::TestTask.new(:test) do |test|
23
+ test.libs << 'lib' << 'test'
24
+ test.pattern = 'test/**/*_test.rb'
25
+ test.verbose = true
26
+ end
27
+
28
+
29
+ begin
30
+ require 'rcov/rcovtask'
31
+ Rcov::RcovTask.new do |test|
32
+ test.libs << 'test'
33
+ test.pattern = 'test/**/*_test.rb'
34
+ test.verbose = true
35
+ end
36
+ rescue LoadError
37
+ task :rcov do
38
+ abort 'RCov is not available. In order to run rcov, you must: sudo gem ' \
39
+ 'install spicycode-rcov'
40
+ end
41
+ end
42
+
43
+
44
+ task :default => :test
45
+
46
+ # require 'rake/rdoctask'
47
+ # Rake::RDocTask.new do |rdoc|
48
+ # if File.exist?('VERSION.yml')
49
+ # config = YAML.load(File.read('VERSION.yml'))
50
+ # version = [config[:major], config[:minor], config[:patch]].join('.')
51
+ # else
52
+ # version = ''
53
+ # end
54
+ # rdoc.rdoc_dir = 'rdoc'
55
+ # rdoc.title = "GCoder #{version}"
56
+ # rdoc.rdoc_files.include('README*')
57
+ # rdoc.rdoc_files.include('lib/**/*.rb')
58
+ # end
data/VERSION.yml ADDED
@@ -0,0 +1,4 @@
1
+ ---
2
+ :minor: 3
3
+ :patch: 0
4
+ :major: 0
data/gcoder.gemspec ADDED
@@ -0,0 +1,57 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = %q{gcoder}
5
+ s.version = "0.3.0"
6
+
7
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
8
+ s.authors = ["Carsten Nielsen"]
9
+ s.date = %q{2009-06-26}
10
+ s.email = %q{heycarsten@gmail.com}
11
+ s.extra_rdoc_files = [
12
+ "README.rdoc"
13
+ ]
14
+ s.files = [
15
+ ".document",
16
+ ".gitignore",
17
+ "README.rdoc",
18
+ "Rakefile",
19
+ "VERSION.yml",
20
+ "gcoder.gemspec",
21
+ "lib/gcoder.rb",
22
+ "lib/gcoder/config.rb",
23
+ "lib/gcoder/geocoding_api.rb",
24
+ "lib/gcoder/persistence.rb",
25
+ "lib/gcoder/resolver.rb",
26
+ "test/config_test.rb",
27
+ "test/gcoder_test.rb",
28
+ "test/geocoding_api_test.rb",
29
+ "test/persistence_test.rb",
30
+ "test/resolver_test.rb",
31
+ "test/test_helper.rb"
32
+ ]
33
+ s.has_rdoc = true
34
+ s.homepage = %q{http://github.com/heycarsten/gcoder}
35
+ s.rdoc_options = ["--charset=UTF-8"]
36
+ s.require_paths = ["lib"]
37
+ s.rubygems_version = %q{1.3.1}
38
+ s.summary = %q{A library for geocoding postal codes via the Google Maps Geocoding API with a persisted cache through Tokyo Tyrant}
39
+ s.test_files = [
40
+ "test/config_test.rb",
41
+ "test/gcoder_test.rb",
42
+ "test/geocoding_api_test.rb",
43
+ "test/persistence_test.rb",
44
+ "test/resolver_test.rb",
45
+ "test/test_helper.rb"
46
+ ]
47
+
48
+ if s.respond_to? :specification_version then
49
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
50
+ s.specification_version = 2
51
+
52
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
53
+ else
54
+ end
55
+ else
56
+ end
57
+ end
@@ -0,0 +1,26 @@
1
+ module GCoder
2
+ module Config
3
+
4
+ # If :tt_port is 0 then :tt_host should point to a Unix socket.
5
+ @default_settings = {
6
+ :gmaps_api_key => nil,
7
+ :gmaps_api_timeout => 2,
8
+ :tt_host => nil,
9
+ :tt_port => 0,
10
+ :append_query => nil,
11
+ :no_raise_on_connection_fail => false }
12
+
13
+ def self.merge(overrides)
14
+ @default_settings.merge(overrides)
15
+ end
16
+
17
+ def self.update(hsh)
18
+ @default_settings.update(hsh)
19
+ end
20
+
21
+ def self.[](key)
22
+ @default_settings[key]
23
+ end
24
+
25
+ end
26
+ end
@@ -0,0 +1,167 @@
1
+ module GCoder
2
+ module GeocodingAPI
3
+
4
+ BASE_URI = 'http://maps.google.com/maps/geo'
5
+ BASE_PARAMS = {
6
+ :q => nil,
7
+ :output => 'json',
8
+ :oe => 'utf8',
9
+ :sensor => 'false',
10
+ :key => nil }
11
+
12
+
13
+ class Request
14
+
15
+ def self.get(query, options = {})
16
+ response = new(query, options).get
17
+ response.validate!
18
+ response.to_h
19
+ end
20
+
21
+ def initialize(query, options = {})
22
+ unless query
23
+ raise Errors::BlankRequestError, "query cannot be nil"
24
+ end
25
+ unless query.is_a?(String)
26
+ raise Errors::MalformedQueryError, "query must be String, not: #{query.class}"
27
+ end
28
+ @config = Config.merge(options)
29
+ @query = query
30
+ validate_state!
31
+ end
32
+
33
+ def params
34
+ BASE_PARAMS.merge(:key => @config[:gmaps_api_key], :q => query)
35
+ end
36
+
37
+ def to_params
38
+ params.inject([]) do |array, (key, value)|
39
+ array << "#{uri_escape key}=#{uri_escape value}"
40
+ end.join('&')
41
+ end
42
+
43
+ def query
44
+ @config[:append_query] ? "#{@query} #{@config[:append_query]}" : @query
45
+ end
46
+
47
+ def uri
48
+ [BASE_URI, '?', to_params].join
49
+ end
50
+
51
+ def get
52
+ return @json_response if @json_response
53
+ Timeout.timeout(@config[:gmaps_api_timeout]) do
54
+ Response.new(http_get)
55
+ end
56
+ rescue Timeout::Error
57
+ raise Errors::RequestTimeoutError, 'The query timed out at ' \
58
+ "#{@config[:timeout]} second(s)"
59
+ end
60
+
61
+ protected
62
+
63
+ def http_get
64
+ open(uri).read
65
+ end
66
+
67
+ # Snaked from Rack::Utils which 'stole' it from Camping.
68
+ def uri_escape(string)
69
+ string.to_s.gsub(/([^ a-zA-Z0-9_.-]+)/n) do
70
+ '%' + $1.unpack('H2' * $1.size).join('%').upcase
71
+ end.tr(' ', '+')
72
+ end
73
+
74
+ def validate_state!
75
+ if '' == query.strip.to_s
76
+ raise Errors::BlankRequestError, 'You must specifiy a query to resolve.'
77
+ end
78
+ unless @config[:gmaps_api_key]
79
+ raise Errors::NoAPIKeyError, 'You must provide a Google Maps API ' \
80
+ 'key in your configuration. Go to http://code.google.com/apis/maps/' \
81
+ 'signup.html to get one.'
82
+ end
83
+ end
84
+
85
+ end
86
+
87
+
88
+ class Response
89
+
90
+ def initialize(raw_response)
91
+ @response = JSON.parse(raw_response)
92
+ end
93
+
94
+ def status
95
+ @response['Status']['code']
96
+ end
97
+
98
+ def validate!
99
+ case status
100
+ when 400
101
+ raise Errors::APIMalformedRequestError, 'The GMaps Geo API has ' \
102
+ 'indicated that the request is not formed correctly: ' \
103
+ "(#{@response.inspect})"
104
+ when 602
105
+ raise Errors::APIGeocodingError, 'The GMaps Geo API has indicated ' \
106
+ "that it is not able to geocode the request: (#{@response.inspect})"
107
+ end
108
+ end
109
+
110
+ def to_h
111
+ { :accuracy => accuracy,
112
+ :country => {
113
+ :name => country_name,
114
+ :code => country_code,
115
+ :administrative_area => administrative_area },
116
+ :point => {
117
+ :longitude => longitude,
118
+ :latitude => latitude },
119
+ :box => box }
120
+ end
121
+
122
+ def box
123
+ { :north => placemark['ExtendedData']['LatLonBox']['north'],
124
+ :south => placemark['ExtendedData']['LatLonBox']['south'],
125
+ :east => placemark['ExtendedData']['LatLonBox']['east'],
126
+ :west => placemark['ExtendedData']['LatLonBox']['west'] }
127
+ end
128
+
129
+ def accuracy
130
+ placemark['AddressDetails']['Accuracy']
131
+ end
132
+
133
+ def latitude
134
+ placemark['Point']['coordinates'][1]
135
+ end
136
+
137
+ def longitude
138
+ placemark['Point']['coordinates'][0]
139
+ end
140
+
141
+ def latlon_box
142
+ placemark['ExtendedData']['LatLonBox']
143
+ end
144
+
145
+ def country_name
146
+ placemark['AddressDetails']['Country']['CountryName']
147
+ end
148
+
149
+ def country_code
150
+ placemark['AddressDetails']['Country']['CountryNameCode']
151
+ end
152
+
153
+ def administrative_area
154
+ placemark['AddressDetails']['Country']['AdministrativeArea']['AdministrativeAreaName']
155
+ end
156
+
157
+ private
158
+
159
+ def placemark
160
+ @response['Placemark'][0]
161
+ end
162
+
163
+ end
164
+
165
+
166
+ end
167
+ end
@@ -0,0 +1,80 @@
1
+ module GCoder
2
+ module Persistence
3
+
4
+
5
+ class DataStore
6
+
7
+ def initialize(options = {})
8
+ @config = Config.merge(options)
9
+ unless @config[:tt_host]
10
+ raise ArgumentError, ':tt_host must be specified when it is not ' \
11
+ 'present in the global configuration.'
12
+ end
13
+ @tyrant = Rufus::Tokyo::Tyrant.new(@config[:tt_host], @config[:tt_port])
14
+ rescue RuntimeError => boom
15
+ if boom.message.include?('couldn\'t connect to tyrant')
16
+ errmsg = 'Unable to connect to the Tokyo Tyrant server at ' \
17
+ "#{@config[:tt_host]} [#{@config[:tt_port]}]"
18
+ if @config[:no_raise_on_connection_fail]
19
+ @tyrant = nil
20
+ STDERR.puts("[GCODER] #{errmsg}")
21
+ else
22
+ raise Errors::TTUnableToConnectError, errmsg
23
+ end
24
+ else
25
+ raise boom
26
+ end
27
+ end
28
+
29
+ def fetch(key, &block)
30
+ unless block_given?
31
+ raise ArgumentError, 'no block was given but one was expected'
32
+ end
33
+ value = storage_get(key)
34
+ return value if value
35
+ storage_put(key, block.call(key.to_s))
36
+ end
37
+
38
+ def [](key)
39
+ storage_get(key)
40
+ end
41
+
42
+ def []=(key, value)
43
+ unless key.is_a?(String) || key.is_a?(Symbol)
44
+ raise ArgumentError, "key must be String or Symbol, not: #{key.class}"
45
+ end
46
+ storage_put(key, value)
47
+ end
48
+
49
+ protected
50
+
51
+ def storage_get(key)
52
+ if tyrant
53
+ value = tyrant[key.to_s]
54
+ value ? YAML.load(value) : nil
55
+ else
56
+ STDERR.puts "[GCODER] Unable to get #{key.inspect} " \
57
+ 'because there is no Tyrant connection.'
58
+ nil
59
+ end
60
+ end
61
+
62
+ def storage_put(key, value)
63
+ if tyrant
64
+ tyrant[key.to_s.downcase] = YAML.dump(value)
65
+ value # <- We don't want to return YAML in this case.
66
+ else
67
+ STDERR.puts "[GCODER] Unable to put #{key.inspect} " \
68
+ 'because there is no Tyrant connection.'
69
+ value
70
+ end
71
+ end
72
+
73
+ def tyrant
74
+ @tyrant
75
+ end
76
+
77
+ end
78
+
79
+ end
80
+ end
@@ -0,0 +1,15 @@
1
+ module GCoder
2
+ class Resolver < Persistence::DataStore
3
+
4
+ def resolve(query)
5
+ fetch(query) do |q|
6
+ GeocodingAPI::Request.get(q, @config)
7
+ end
8
+ end
9
+
10
+ def [](postal_code)
11
+ resolve(postal_code)
12
+ end
13
+
14
+ end
15
+ end
data/lib/gcoder.rb ADDED
@@ -0,0 +1,42 @@
1
+ require 'rubygems'
2
+ require 'rufus/tokyo/tyrant'
3
+ require 'json'
4
+ require 'yaml'
5
+ require 'open-uri'
6
+ require 'timeout'
7
+
8
+ $:.unshift(File.dirname(__FILE__))
9
+
10
+ require 'gcoder/config'
11
+ require 'gcoder/geocoding_api'
12
+ require 'gcoder/persistence'
13
+ require 'gcoder/resolver'
14
+
15
+
16
+ module GCoder
17
+
18
+ module Errors
19
+ class Error < StandardError; end
20
+ class MalformedQueryError < Error; end
21
+ class BlankRequestError < Error; end
22
+ class RequestTimeoutError < Error; end
23
+ class NoAPIKeyError < Error; end
24
+ class APIMalformedRequestError < Error; end
25
+ class APIGeocodingError < Error; end
26
+ class TTUnableToConnectError < Error; end
27
+ class InvalidStorageValueError < Error; end
28
+ class UnknownFormatSymbolError < Error; end
29
+ end
30
+
31
+
32
+ module ProxyMethods
33
+ def GCoder.config=(hsh)
34
+ Config.update(hsh)
35
+ end
36
+
37
+ def GCoder.connect(options = {})
38
+ Resolver.new(options)
39
+ end
40
+ end
41
+
42
+ end
@@ -0,0 +1,37 @@
1
+ require 'test_helper'
2
+
3
+ class ConfigTest < Test::Unit::TestCase
4
+
5
+ context 'Config#merge' do
6
+ setup do
7
+ @config = GCoder::Config.merge(:gmaps_api_timeout => 3)
8
+ end
9
+
10
+ should 'return a hash of updated config settings' do
11
+ assert_instance_of Hash, @config
12
+ assert_equal 6, @config.size
13
+ assert_equal 3, @config[:gmaps_api_timeout]
14
+ end
15
+
16
+ should 'not change default configuration' do
17
+ assert_equal 2, GCoder::Config[:gmaps_api_timeout]
18
+ end
19
+ end
20
+
21
+ context 'Config#update' do
22
+ setup do
23
+ @config = GCoder::Config.update(:gmaps_api_timeout => 1)
24
+ end
25
+
26
+ should 'return a hash of updated config settings' do
27
+ assert_instance_of Hash, @config
28
+ assert_equal 6, @config.size
29
+ assert_equal 1, @config[:gmaps_api_timeout]
30
+ end
31
+
32
+ should 'change default configuration' do
33
+ assert_equal 1, GCoder::Config[:gmaps_api_timeout]
34
+ end
35
+ end
36
+
37
+ end
@@ -0,0 +1,26 @@
1
+ require 'test_helper'
2
+
3
+ class GCoderTest < Test::Unit::TestCase
4
+
5
+ context 'ProxyMethods' do
6
+ should 'be present in GCoder module' do
7
+ assert_respond_to GCoder, :config=
8
+ assert_respond_to GCoder, :connect
9
+ end
10
+
11
+ context 'GCoder.config=' do
12
+ should 'proxy to Config.update' do
13
+ GCoder::Config.expects(:update).with({})
14
+ assert GCoder.config = {}
15
+ end
16
+ end
17
+
18
+ context 'GCoder.connect' do
19
+ should 'proxy to Resolver.new' do
20
+ GCoder::Resolver.expects(:new).with({}).returns(:it_works)
21
+ assert_equal :it_works, GCoder.connect
22
+ end
23
+ end
24
+ end
25
+
26
+ end
@@ -0,0 +1,74 @@
1
+ require 'test_helper'
2
+
3
+
4
+ class GeocodingAPITest < Test::Unit::TestCase
5
+
6
+ context 'initialize with incorrect arguments' do
7
+ should 'fail with no arguments' do
8
+ assert_raise ArgumentError do
9
+ GCoder::GeocodingAPI::Request.new
10
+ end
11
+ end
12
+
13
+ should 'fail with any argument other than a string' do
14
+ assert_raise GCoder::Errors::BlankRequestError do
15
+ GCoder::GeocodingAPI::Request.new(nil)
16
+ end
17
+ assert_raise GCoder::Errors::MalformedQueryError do
18
+ GCoder::GeocodingAPI::Request.new(0)
19
+ end
20
+ end
21
+
22
+ should 'fail when passed a blank string as an argument' do
23
+ assert_raise GCoder::Errors::BlankRequestError do
24
+ GCoder::GeocodingAPI::Request.new(' ')
25
+ end
26
+ end
27
+ end
28
+
29
+ context 'initialize with no API key present' do
30
+ should 'fall down, go boom' do
31
+ assert_raise GCoder::Errors::NoAPIKeyError do
32
+ GCoder::GeocodingAPI::Request.new('M6R2G5')
33
+ end
34
+ end
35
+ end
36
+
37
+ context 'query with correct arguments' do
38
+ setup do
39
+ @zip = GCoder::GeocodingAPI::Request.new('M6R2G5',
40
+ :gmaps_api_key => 'apikey')
41
+ end
42
+
43
+ should 'return parsed and tidied JSON' do
44
+ @zip.expects(:http_get).returns(PAYLOADS[:json_m6r2g5])
45
+ response = @zip.get.to_h
46
+ assert_equal 5, response[:accuracy]
47
+ assert_equal 'Canada', response[:country][:name]
48
+ assert_equal 'CA', response[:country][:code]
49
+ assert_equal 'ON', response[:country][:administrative_area]
50
+ assert_equal 43.6504650, response[:point][:latitude]
51
+ assert_equal -79.4449720, response[:point][:longitude]
52
+ assert_equal 43.6536126, response[:box][:north]
53
+ assert_equal 43.6473174, response[:box][:south]
54
+ assert_equal -79.4418244, response[:box][:east]
55
+ assert_equal -79.4481196, response[:box][:west]
56
+ end
57
+
58
+ should 'raise an error when API returns malformed request' do
59
+ @zip.expects(:http_get).returns(PAYLOADS[:json_400])
60
+ assert_raise GCoder::Errors::APIMalformedRequestError do
61
+ @zip.get.validate!
62
+ end
63
+ end
64
+
65
+ should 'have an appropriate URI' do
66
+ assert_match /output=json/, @zip.uri
67
+ assert_match /q=M6R2G5/, @zip.uri
68
+ assert_match /oe=u/, @zip.uri
69
+ assert_match /sensor=false/, @zip.uri
70
+ assert_match /key=apikey/, @zip.uri
71
+ end
72
+ end
73
+
74
+ end
@@ -0,0 +1,78 @@
1
+ require 'test_helper'
2
+
3
+ class PersistenceTest < Test::Unit::TestCase
4
+
5
+ context 'DataStore.new' do
6
+ should 'throw and argument error without :tt_host specified' do
7
+ assert_raise ArgumentError do
8
+ GCoder::Persistence::DataStore.new
9
+ end
10
+ end
11
+
12
+ should 'throw a better error if the Tokyo Tyrant connection fails' do
13
+ assert_raise GCoder::Errors::TTUnableToConnectError do
14
+ GCoder::Persistence::DataStore.new(:tt_host => '/tmp/fake')
15
+ end
16
+ end
17
+ end
18
+
19
+ context 'DataStore' do
20
+ setup do
21
+ Rufus::Tokyo::Tyrant.stubs(:new).returns({})
22
+ @db = GCoder::Persistence::DataStore.new(:tt_host => '/tmp/tttest')
23
+ end
24
+
25
+ context '#fetch' do
26
+ should 'raise an error without any block specified' do
27
+ assert_raise ArgumentError do
28
+ @db.fetch(:stuff)
29
+ end
30
+ end
31
+
32
+ should 'get a value that exists' do
33
+ @db[:test_key] = 'test_value'
34
+ assert_equal 'test_value', @db.fetch(:test_key) { raise 'ultrafail' }
35
+ end
36
+
37
+ should 'set the value to whatever the block yields if value is nil' do
38
+ @db.fetch(:test_key) { 'block_value' }
39
+ assert_equal 'block_value', @db[:test_key]
40
+ end
41
+ end
42
+
43
+ context '#[]=' do
44
+ should 'now allow numbers or nil as a key' do
45
+ assert_raise ArgumentError do
46
+ @db[nil] = 'extreme fail'
47
+ end
48
+ assert_raise ArgumentError do
49
+ @db[23] = 'massive fail'
50
+ end
51
+ end
52
+ end
53
+
54
+ context '#[]' do
55
+ should 'return nil for a key that does not exist' do
56
+ assert_nil @db['nope']
57
+ assert_nil @db['']
58
+ assert_nil @db[0]
59
+ assert_nil @db[nil]
60
+ end
61
+
62
+ should 'alow retrieval of nil' do
63
+ @db[:nil_key] = nil
64
+ assert_nil @db[:nil_key]
65
+ end
66
+
67
+ should 'return parsed JSON for keys that do exist' do
68
+ @db[:payload_1] = PAYLOADS[:test_string]
69
+ @db[:payload_2] = PAYLOADS[:test_hash]
70
+ @db[:payload_3] = PAYLOADS[:test_array]
71
+ assert_equal PAYLOADS[:test_string], @db[:payload_1]
72
+ assert_equal PAYLOADS[:test_hash], @db[:payload_2]
73
+ assert_equal PAYLOADS[:test_array], @db[:payload_3]
74
+ end
75
+ end
76
+ end
77
+
78
+ end
@@ -0,0 +1,36 @@
1
+ require 'test_helper'
2
+
3
+ class ResolverTest < Test::Unit::TestCase
4
+
5
+ context 'Resolver' do
6
+ setup do
7
+ Rufus::Tokyo::Tyrant.stubs(:new).returns({})
8
+ @db = GCoder::Resolver.new(:tt_host => '/tmp/tttest', :gmaps_api_key => 'testkey')
9
+ end
10
+
11
+ should 'return a hash of information for a new address' do
12
+ GCoder::GeocodingAPI::Request.any_instance.
13
+ expects(:http_get).returns(PAYLOADS[:json_m6r2g5])
14
+ assert_instance_of Hash, @db.resolve('m6r2g5')
15
+ end
16
+
17
+ should 'not call api when a cached postal code is called' do
18
+ assert_instance_of Hash, @db.resolve('m6r2g5')
19
+ end
20
+
21
+ should 'store the postal code key in the correct format' do
22
+ assert_instance_of Hash, @db.resolve('M6R2G5')
23
+ end
24
+
25
+ should 'allow [] to resolve with auto-instantiation' do
26
+ assert_instance_of Hash, @db['M6R2G5']
27
+ end
28
+
29
+ should 'raise malformed postal code error for a nil postal code' do
30
+ assert_raise GCoder::Errors::BlankRequestError do
31
+ @db.resolve(nil)
32
+ end
33
+ end
34
+ end
35
+
36
+ end
@@ -0,0 +1,58 @@
1
+ require 'rubygems'
2
+ require 'test/unit'
3
+ require 'shoulda'
4
+ require 'mocha'
5
+
6
+ $:.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
7
+ $:.unshift(File.dirname(__FILE__))
8
+ require 'gcoder'
9
+
10
+ class Test::Unit::TestCase
11
+
12
+ PAYLOADS = {
13
+ :json_m6r2g5 => %q<
14
+ {
15
+ "name": "M6R2G5",
16
+ "Status": {
17
+ "code": 200,
18
+ "request": "geocode"
19
+ },
20
+ "Placemark": [ {
21
+ "id": "p1",
22
+ "address": "Ontario M6R 2G5, Canada",
23
+ "AddressDetails": {"Country": {"CountryNameCode": "CA","CountryName": "Canada","AdministrativeArea": {"AdministrativeAreaName": "ON","PostalCode": {"PostalCodeNumber": "M6R 2G5"}}},"Accuracy": 5},
24
+ "ExtendedData": {
25
+ "LatLonBox": {
26
+ "north": 43.6536126,
27
+ "south": 43.6473174,
28
+ "east": -79.4418244,
29
+ "west": -79.4481196
30
+ }
31
+ },
32
+ "Point": {
33
+ "coordinates": [ -79.4449720, 43.6504650, 0 ]
34
+ }
35
+ } ]
36
+ }>,
37
+ :json_602 => %q<
38
+ {
39
+ "name": "crashbangboom",
40
+ "Status": {
41
+ "code": 602,
42
+ "request": "geocode"
43
+ }
44
+ }>,
45
+ :json_400 => %q<
46
+ {
47
+ "name": "",
48
+ "Status": {
49
+ "code": 400,
50
+ "request": "geocode"
51
+ }
52
+ }>,
53
+ :test_string => "test\nstring",
54
+ :test_hash => { 'test' => 'value', 100 => 'one hundred' },
55
+ :test_array => ['test', 1, 3.1415, true, false, nil]
56
+ }
57
+
58
+ end
metadata ADDED
@@ -0,0 +1,74 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: heycarsten-gcoder
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.3.0
5
+ platform: ruby
6
+ authors:
7
+ - Carsten Nielsen
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-06-26 00:00:00 -07:00
13
+ default_executable:
14
+ dependencies: []
15
+
16
+ description:
17
+ email: heycarsten@gmail.com
18
+ executables: []
19
+
20
+ extensions: []
21
+
22
+ extra_rdoc_files:
23
+ - README.rdoc
24
+ files:
25
+ - .document
26
+ - .gitignore
27
+ - README.rdoc
28
+ - Rakefile
29
+ - VERSION.yml
30
+ - gcoder.gemspec
31
+ - lib/gcoder.rb
32
+ - lib/gcoder/config.rb
33
+ - lib/gcoder/geocoding_api.rb
34
+ - lib/gcoder/persistence.rb
35
+ - lib/gcoder/resolver.rb
36
+ - test/config_test.rb
37
+ - test/gcoder_test.rb
38
+ - test/geocoding_api_test.rb
39
+ - test/persistence_test.rb
40
+ - test/resolver_test.rb
41
+ - test/test_helper.rb
42
+ has_rdoc: true
43
+ homepage: http://github.com/heycarsten/gcoder
44
+ post_install_message:
45
+ rdoc_options:
46
+ - --charset=UTF-8
47
+ require_paths:
48
+ - lib
49
+ required_ruby_version: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - ">="
52
+ - !ruby/object:Gem::Version
53
+ version: "0"
54
+ version:
55
+ required_rubygems_version: !ruby/object:Gem::Requirement
56
+ requirements:
57
+ - - ">="
58
+ - !ruby/object:Gem::Version
59
+ version: "0"
60
+ version:
61
+ requirements: []
62
+
63
+ rubyforge_project:
64
+ rubygems_version: 1.2.0
65
+ signing_key:
66
+ specification_version: 2
67
+ summary: A library for geocoding postal codes via the Google Maps Geocoding API with a persisted cache through Tokyo Tyrant
68
+ test_files:
69
+ - test/config_test.rb
70
+ - test/gcoder_test.rb
71
+ - test/geocoding_api_test.rb
72
+ - test/persistence_test.rb
73
+ - test/resolver_test.rb
74
+ - test/test_helper.rb