sundawg_geonames_client 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,8 @@
1
+ Manifest
2
+ README.rdoc
3
+ Rakefile
4
+ lib/geonames_client.rb
5
+ lib/geonames_client_helper.rb
6
+ test/geonames_client_helper_test.rb
7
+ test/geonames_client_integration_test.rb
8
+ test/geonames_client_test.rb
@@ -0,0 +1,65 @@
1
+ == About
2
+
3
+ Sundawg Geonames Client is a ruby gem for the RESTful web services provided by geonames.org. This client attempts to use the method_missing functionality of Ruby to quickly provide generic support for any and all services provided by geonames.org. For more information on these services and geonames, please see the following:
4
+
5
+ - http://www.geonames.org
6
+ - http://www.geonames.org/export/ws-overview.html
7
+
8
+ == Installation
9
+
10
+ You can install the gem as so:
11
+
12
+ gem install sundawg_geonames_client
13
+
14
+ == Tests
15
+
16
+ You can confirm tests and functionality with geonames.org by running:
17
+
18
+ rake tests
19
+
20
+ == Usage
21
+
22
+ To use the client, you simply call the service method you want on geonames.org directly on the client. Any parameters that the service requires are passed as a hash object to the client.
23
+
24
+ For example, to call the postalCodeLookup service, you would do the following:
25
+
26
+ SunDawg::GeonamesClient.new.postal_code_lookup :postalcode => "10069", :country => "US"
27
+ => {"postalcodes":[{"adminName2":"New York","adminCode2":"061","postalcode":"10069","adminCode1":"NY","countryCode":"US","lng":-73.988381,"placeName":"New York City","lat":40.777952,"adminName1":"New York"}]}
28
+
29
+ By default, the client uses the JSON service provided by geonames.org and provides the raw JSON output back to you. You can then use the JSON parser of your choice to parse the data i.e. json gem or ActiveSupport.
30
+
31
+ - http://flori.github.com/json/
32
+ - http://api.rubyonrails.org/classes/ActiveSupport/JSON.html
33
+
34
+ The client allows you to pass in several configration changes. If you want to use camelcase notation as the service is provided, then you can pass in :camelize => true when creating the client. This will remove all of the string manipulation to turn snake case notation into camel notation, thus allowing you to break out of the Ruby conventions if you want.
35
+
36
+ Here is the same call, but with camel notation.
37
+
38
+ SunDawg::GeonamesClient.new(:camelize => true).postalCodeLookup :postalcode => "10069", :country => "US"
39
+
40
+ You can also turn off JSON support and attempt to hit the standard service with :json => false. One small warning, is that the documentation is unclear as to whether you will always get XML or non-markup text in your response. For example the countryCode service seems to return the ISO Alpha2 country when you hit the non-JSON service. Passing in a :type => "xml" will force XML.
41
+
42
+ SunDawg::GeonamesClient.new(:json => false).country_code :lat => "47.03", :lng => "10.2", :type => "xml"
43
+
44
+ Lastly, you can pass a username to the client. This is a new requirement imposed by geonames.org to identify a malignant client that is creating DDOS issues for geonames.org. Their explanation is here:
45
+
46
+ http://geonames.wordpress.com/2010/03/16/ddos-part-ii/
47
+
48
+ SunDawg::Geonames client will default the username if you do not provide one.
49
+
50
+ == Helper Feature
51
+
52
+ The reason for this library is for my need to convert postal code information into other sorts of useful information. This requires two calls to the geonames.org services, one to turn a postal code into longitude and latitude coordinates, then a call to the service that will provide the interesting information.
53
+
54
+ There is a small helper class that will allow you to chain a postal_code_lookup service call with other geonames.org service calls. For example, if I want to get the timezone associated with a postal code, I can use the helper as so:
55
+
56
+ json = SunDawg::GeonamesClientHelper.postal_code_to(:postalcode => "10069", :country => "US") do |client, params, original_json|
57
+ assert_equal "40.777952", params[:lat]
58
+ assert_equal "-73.988381", params[:lng]
59
+ client.timezone params
60
+ end
61
+ assert_match "America/New_York", json
62
+
63
+ The helper is invoking the postal code service and then executing the yield block. You are provided an instance of the client with whatever options you specified, a hash containing longitude and latitude that can be passed to subsequent calls, and for complete-ness sake, the JSON response from the postal call.
64
+
65
+ The helper automatically uses the first match from the postal service.
@@ -0,0 +1,13 @@
1
+ # Rakefile
2
+ require 'rubygems'
3
+ require 'rake'
4
+ require 'echoe'
5
+
6
+ Echoe.new('sundawg_geonames_client', '0.0.1') do |p|
7
+ p.description = "Ruby client interface to all and future RESTful geo-services provided by geonames.org."
8
+ p.url = "http://github.com/SunDawg/geonames_client"
9
+ p.author = "Christopher Sun"
10
+ p.email = "christopher.sun@gmail.com"
11
+ p.ignore_pattern = ["tmp/*", "script/*"]
12
+ p.development_dependencies = ['mocha']
13
+ end
@@ -0,0 +1,48 @@
1
+ require 'net/http'
2
+ require 'uri'
3
+ require 'cgi'
4
+
5
+ module SunDawg
6
+ class GeonamesClient
7
+ URL = "http://ws.geonames.org"
8
+
9
+ def initialize(options = {})
10
+ options[:json].nil? ? options[:json] = true : nil
11
+ options[:camelize].nil? ? options[:camelize] = false : nil
12
+ options[:username].nil? ? options[:username] = "SunDawg" : nil
13
+ @options = options
14
+ end
15
+
16
+ def method_missing(signature, *args)
17
+ raise ArgumentError.new("must provide a hash of geoname parameters for first argument when calling web services [#{signature}] [#{args.inspect}]") if args.size < 1 || !args[0].is_a?(Hash)
18
+ signature = smart_camelize(signature.to_s) unless @options[:camelize]
19
+ do_http_call(service_resource(signature), args[0])
20
+ end
21
+
22
+ protected
23
+
24
+ def do_http_call(resource, params)
25
+ params.merge!(:username => @options[:username])
26
+ resource += "?" + query_string(params)
27
+ url = URI.parse(resource)
28
+ response = Net::HTTP.start(url.host, url.port) do |http|
29
+ http.get(resource)
30
+ end
31
+ response.body
32
+ end
33
+
34
+ def query_string(params)
35
+ params.keys.map { |i| "#{i}=#{CGI::escape(params[i])}#{i == params.keys.last ? "" : "&"}" }.join
36
+ end
37
+
38
+ # provided to remove active support dependency
39
+ def smart_camelize(s)
40
+ s = s.split(/[^a-z0-9]/i).map{|w| w.capitalize}.join
41
+ "#{s[0..0].swapcase!}#{s[1..s.length]}"
42
+ end
43
+
44
+ def service_resource(service)
45
+ "#{URL}/#{service}#{ @options[:json] ? "JSON" : "" }"
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,24 @@
1
+ module SunDawg
2
+ class GeonamesClientHelper
3
+
4
+ def self.postal_code_to(params, options = {})
5
+ json = SunDawg::GeonamesClient.new(options.reject { |k, v| k == :json }.reject { |k, v| k == :camelize }).postal_code_lookup params
6
+ yield(SunDawg::GeonamesClient.new(options), {:lat => get_lat(json), :lng => get_lng(json)}, json)
7
+ end
8
+
9
+ protected
10
+
11
+ # simple string search so we don't need to import a json library
12
+ def self.get_lat(s)
13
+ json_parse("lat", s)
14
+ end
15
+
16
+ def self.get_lng(s)
17
+ json_parse("lng", s)
18
+ end
19
+
20
+ def self.json_parse(field, s)
21
+ s.match(/"#{field}":-?(\d|\.)+/)[0].split(":")[1]
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,34 @@
1
+ # -*- encoding: utf-8 -*-
2
+
3
+ Gem::Specification.new do |s|
4
+ s.name = %q{sundawg_geonames_client}
5
+ s.version = "0.0.1"
6
+
7
+ s.required_rubygems_version = Gem::Requirement.new(">= 1.2") if s.respond_to? :required_rubygems_version=
8
+ s.authors = ["Christopher Sun"]
9
+ s.date = %q{2010-04-16}
10
+ s.description = %q{Ruby client interface to all and future RESTful geo-services provided by geonames.org.}
11
+ s.email = %q{christopher.sun@gmail.com}
12
+ s.extra_rdoc_files = ["README.rdoc", "lib/geonames_client.rb", "lib/geonames_client_helper.rb"]
13
+ s.files = ["Manifest", "README.rdoc", "Rakefile", "lib/geonames_client.rb", "lib/geonames_client_helper.rb", "test/geonames_client_helper_test.rb", "test/geonames_client_integration_test.rb", "test/geonames_client_test.rb", "sundawg_geonames_client.gemspec"]
14
+ s.homepage = %q{http://github.com/SunDawg/geonames_client}
15
+ s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "Sundawg_geonames_client", "--main", "README.rdoc"]
16
+ s.require_paths = ["lib"]
17
+ s.rubyforge_project = %q{sundawg_geonames_client}
18
+ s.rubygems_version = %q{1.3.6}
19
+ s.summary = %q{Ruby client interface to all and future RESTful geo-services provided by geonames.org.}
20
+ s.test_files = ["test/geonames_client_helper_test.rb", "test/geonames_client_integration_test.rb", "test/geonames_client_test.rb"]
21
+
22
+ if s.respond_to? :specification_version then
23
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
24
+ s.specification_version = 3
25
+
26
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
27
+ s.add_development_dependency(%q<mocha>, [">= 0"])
28
+ else
29
+ s.add_dependency(%q<mocha>, [">= 0"])
30
+ end
31
+ else
32
+ s.add_dependency(%q<mocha>, [">= 0"])
33
+ end
34
+ end
@@ -0,0 +1,29 @@
1
+ require 'test/unit'
2
+ require 'geonames_client_helper'
3
+
4
+ class GeonamesClientHelperTest < Test::Unit::TestCase
5
+ def test_postal_code_to_timezone
6
+ json = SunDawg::GeonamesClientHelper.postal_code_to(:postalcode => "10069", :country => "US") do |client, params|
7
+ assert_equal "40.777952", params[:lat]
8
+ assert_equal "-73.988381", params[:lng]
9
+ client.timezone params
10
+ end
11
+ assert_match "America/New_York", json
12
+ end
13
+
14
+ def test_get_lat
15
+ s = '{"postalcodes":[{"adminName2":"Olsztyn","postalcode":"10-069","countryCode":"PL","lng":20.4833333,"placeName":"Olsztyn","lat":53.7833333,"adminName1":"Warmińsko-Mazurskie"},{"adminName2":"New York","adminCode2":"061","postalcode":"10069","adminCode1":"NY","countryCode":"US","lng":-73.988381,"placeName":"New York City","lat":40.777952,"adminName1":"New York"},{"adminName2":"Torino","adminCode2":"TO","postalcode":"10069","countryCode":"IT","lng":7.248118,"placeName":"Villar Perosa","lat":44.91932,"adminName1":"Piemonte"}]}'
16
+ assert_equal "53.7833333", SunDawg::GeonamesClientHelper.send(:get_lat, s)
17
+
18
+ s = '{"postalcodes":[{"adminName2":"New York","adminCode2":"061","postalcode":"10069","adminCode1":"NY","countryCode":"US","lng":-73.988381,"placeName":"New York City","lat":40.777952,"adminName1":"New York"}]}'
19
+ assert_equal "40.777952", SunDawg::GeonamesClientHelper.send(:get_lat, s)
20
+ end
21
+
22
+ def test_get_lng
23
+ s = '{"postalcodes":[{"adminName2":"Olsztyn","postalcode":"10-069","countryCode":"PL","lng":20.4833333,"placeName":"Olsztyn","lat":53.7833333,"adminName1":"Warmińsko-Mazurskie"},{"adminName2":"New York","adminCode2":"061","postalcode":"10069","adminCode1":"NY","countryCode":"US","lng":-73.988381,"placeName":"New York City","lat":40.777952,"adminName1":"New York"},{"adminName2":"Torino","adminCode2":"TO","postalcode":"10069","countryCode":"IT","lng":7.248118,"placeName":"Villar Perosa","lat":44.91932,"adminName1":"Piemonte"}]}'
24
+ assert_equal "20.4833333", SunDawg::GeonamesClientHelper.send(:get_lng, s)
25
+
26
+ s = '{"postalcodes":[{"adminName2":"New York","adminCode2":"061","postalcode":"10069","adminCode1":"NY","countryCode":"US","lng":-73.988381,"placeName":"New York City","lat":40.777952,"adminName1":"New York"}]}'
27
+ assert_equal "-73.988381", SunDawg::GeonamesClientHelper.send(:get_lng, s)
28
+ end
29
+ end
@@ -0,0 +1,47 @@
1
+ require 'test/unit'
2
+ require 'rubygems'
3
+ require 'geonames_client'
4
+
5
+ class GeonamesClientIntegrationTest < Test::Unit::TestCase
6
+ def setup
7
+ @client = SunDawg::GeonamesClient.new
8
+ end
9
+
10
+ def test_postal_code_lookup_json
11
+ json = client.postal_code_lookup :postalcode => "10069", :country => "US"
12
+ assert_match "New York", json
13
+ end
14
+
15
+ def test_postal_code_lookup_camelize
16
+ json = SunDawg::GeonamesClient.new(:camelize => true).postalCodeLookup :postalcode => "10069", :country => "US"
17
+ assert_match "New York", json
18
+ end
19
+
20
+ def test_country_code_json
21
+ json = client.country_code :lat => "47.03", :lng => "10.2"
22
+ assert_match "Austria", json
23
+ assert_match "AT", json
24
+
25
+ json = client.country_code :lat => "40.7", :lng => "-73.98"
26
+ assert_match "United States", json
27
+ assert_match "US", json
28
+ end
29
+
30
+ def test_timezone
31
+ json = client.timezone :lat => "40.777952", :lng => "-73.988381"
32
+ assert_match "America/New_York", json
33
+ end
34
+
35
+ # validate hitting non JSON resource
36
+ def test_country_code_xml
37
+ xml = SunDawg::GeonamesClient.new(:json => false).country_code :lat => "47.03", :lng => "10.2", :type => "xml"
38
+ assert_match "<countryName>Austria</countryName>", xml
39
+ assert_match "<countryCode>AT</countryCode>", xml
40
+ end
41
+
42
+ protected
43
+
44
+ def client
45
+ @client
46
+ end
47
+ end
@@ -0,0 +1,40 @@
1
+ require 'test/unit'
2
+ require 'rubygems'
3
+ require 'geonames_client'
4
+ require 'mocha'
5
+
6
+ class GeonamesClientTest < Test::Unit::TestCase
7
+ def setup
8
+ @client = SunDawg::GeonamesClient.new
9
+ end
10
+
11
+ def test_invalid_arguments
12
+ assert_raise ArgumentError do
13
+ client.foo
14
+ end
15
+ end
16
+
17
+ def test_do_http_call
18
+ params = {:arg1 => "x", :arg2 => "y"}
19
+ client.expects(:do_http_call).with("http://ws.geonames.org/fooJSON", params)
20
+ client.foo params
21
+ end
22
+
23
+ def test_query_string
24
+ params = {:arg1 => "x", :arg2 => "123"}
25
+ query_string = client.send(:query_string, params)
26
+
27
+ # hash is not-ordered
28
+ assert (query_string == "arg1=x&arg2=123" or query_string == "arg2=123&arg1=x")
29
+ end
30
+
31
+ def test_smart_camelize
32
+ assert_equal "helloWorld", client.send(:smart_camelize, "hello_world")
33
+ end
34
+
35
+ protected
36
+
37
+ def client
38
+ @client
39
+ end
40
+ end
metadata ADDED
@@ -0,0 +1,91 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: sundawg_geonames_client
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 0
8
+ - 1
9
+ version: 0.0.1
10
+ platform: ruby
11
+ authors:
12
+ - Christopher Sun
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2010-04-16 00:00:00 -04:00
18
+ default_executable:
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ name: mocha
22
+ prerelease: false
23
+ requirement: &id001 !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - ">="
26
+ - !ruby/object:Gem::Version
27
+ segments:
28
+ - 0
29
+ version: "0"
30
+ type: :development
31
+ version_requirements: *id001
32
+ description: Ruby client interface to all and future RESTful geo-services provided by geonames.org.
33
+ email: christopher.sun@gmail.com
34
+ executables: []
35
+
36
+ extensions: []
37
+
38
+ extra_rdoc_files:
39
+ - README.rdoc
40
+ - lib/geonames_client.rb
41
+ - lib/geonames_client_helper.rb
42
+ files:
43
+ - Manifest
44
+ - README.rdoc
45
+ - Rakefile
46
+ - lib/geonames_client.rb
47
+ - lib/geonames_client_helper.rb
48
+ - test/geonames_client_helper_test.rb
49
+ - test/geonames_client_integration_test.rb
50
+ - test/geonames_client_test.rb
51
+ - sundawg_geonames_client.gemspec
52
+ has_rdoc: true
53
+ homepage: http://github.com/SunDawg/geonames_client
54
+ licenses: []
55
+
56
+ post_install_message:
57
+ rdoc_options:
58
+ - --line-numbers
59
+ - --inline-source
60
+ - --title
61
+ - Sundawg_geonames_client
62
+ - --main
63
+ - README.rdoc
64
+ require_paths:
65
+ - lib
66
+ required_ruby_version: !ruby/object:Gem::Requirement
67
+ requirements:
68
+ - - ">="
69
+ - !ruby/object:Gem::Version
70
+ segments:
71
+ - 0
72
+ version: "0"
73
+ required_rubygems_version: !ruby/object:Gem::Requirement
74
+ requirements:
75
+ - - ">="
76
+ - !ruby/object:Gem::Version
77
+ segments:
78
+ - 1
79
+ - 2
80
+ version: "1.2"
81
+ requirements: []
82
+
83
+ rubyforge_project: sundawg_geonames_client
84
+ rubygems_version: 1.3.6
85
+ signing_key:
86
+ specification_version: 3
87
+ summary: Ruby client interface to all and future RESTful geo-services provided by geonames.org.
88
+ test_files:
89
+ - test/geonames_client_helper_test.rb
90
+ - test/geonames_client_integration_test.rb
91
+ - test/geonames_client_test.rb