geonames_api 0.0.6 → 0.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.
- checksums.yaml +7 -0
- data/.gitignore +2 -0
- data/.travis.yml +7 -0
- data/CHANGELOG.md +28 -0
- data/README.md +13 -2
- data/Rakefile +13 -0
- data/geonames_api.gemspec +7 -5
- data/lib/geonames_api.rb +30 -19
- data/lib/geonames_api/alternate_names.rb +54 -0
- data/lib/geonames_api/base.rb +92 -0
- data/lib/geonames_api/children.rb +85 -0
- data/lib/geonames_api/city.rb +8 -0
- data/lib/geonames_api/country.rb +6 -6
- data/lib/geonames_api/country_code.rb +8 -0
- data/lib/geonames_api/country_subdivision.rb +8 -0
- data/lib/geonames_api/earthquake.rb +8 -0
- data/lib/geonames_api/elevation.rb +16 -0
- data/lib/geonames_api/entity.rb +64 -0
- data/lib/geonames_api/error.rb +25 -2
- data/lib/geonames_api/geoname.rb +4 -0
- data/lib/geonames_api/hierarchy.rb +10 -0
- data/lib/geonames_api/list_endpoint.rb +21 -0
- data/lib/geonames_api/nearby_postal_code.rb +17 -0
- data/lib/geonames_api/place.rb +8 -0
- data/lib/geonames_api/place_name.rb +8 -0
- data/lib/geonames_api/place_search.rb +16 -0
- data/lib/geonames_api/postal_code.rb +23 -0
- data/lib/geonames_api/singleton_endpoint.rb +7 -0
- data/lib/geonames_api/street.rb +8 -0
- data/lib/geonames_api/time_zone.rb +17 -14
- data/lib/geonames_api/version.rb +2 -2
- data/lib/geonames_api/weather.rb +16 -16
- data/lib/geonames_api/weather_i_c_a_o.rb +8 -0
- data/lib/geonames_api/wikipedia.rb +5 -5
- data/spec/geonames_api/country_subdivision_spec.rb +27 -0
- data/spec/geonames_api/hierarchy_spec.rb +38 -0
- data/spec/geonames_api/place_name_spec.rb +22 -0
- data/spec/geonames_api/place_search_spec.rb +50 -0
- data/spec/geonames_api/place_spec.rb +17 -0
- data/spec/geonames_api/retry_spec.rb +37 -0
- data/spec/geonames_api/street_spec.rb +22 -0
- data/spec/geonames_api/weather_icao_spec.rb +10 -0
- data/spec/spec_helper.rb +15 -0
- metadata +97 -21
- data/lib/geonames_api/hash.rb +0 -5
- data/lib/geonames_api/object.rb +0 -72
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 1e01b04a032c053533c4b76638fc31b4777f5b8e
|
4
|
+
data.tar.gz: bd3e6b7a88b1376282220737a1d2870046db9af4
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: f175f17720e7a8e6b3b404320593f1f7a2a6841d0c63bae16b95d6f5dc4c40a779b8e0b95f4902ea93da69f280b98718ce25ed2722b2586e0084057fbffc4e27
|
7
|
+
data.tar.gz: 088b25cd53a9c1533aa67df6b11d709020c45d67514911384859ef1b7fa28aeef94b10c490197e559b8ab9e43bbe942bdc3f4a5bb35702bd67d7d099165ecc63
|
data/.gitignore
CHANGED
data/.travis.yml
ADDED
data/CHANGELOG.md
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
## 0.1.0
|
2
|
+
|
3
|
+
### New features:
|
4
|
+
|
5
|
+
* When the GeoNames API returns a database or server timeout, your request
|
6
|
+
will be retried at most ```GeoNamesAPI.retries``` times. Default is 2, and
|
7
|
+
the delay between requests is at most ```GeoNamesAPI.max_sleep_time_between_retries```
|
8
|
+
(which defaults to 5 seconds).
|
9
|
+
|
10
|
+
* Several endpoints accept multiple param sets, and the order of the parameters
|
11
|
+
is not always in the order or priority, so ```find``` and ```all``` and ```where```
|
12
|
+
now also accept a parameter hash.
|
13
|
+
|
14
|
+
* ```GeoNamesAPI::Hierarchy``` is now an Enumerable of ```GeoName``` instances, as
|
15
|
+
all responses will have an ordered set of those entity types.
|
16
|
+
|
17
|
+
* URL parameters are properly encoded now.
|
18
|
+
|
19
|
+
* For paid users, set ```GeoNamesAPI.token``` and set the ```GeoNamesAPI.url```
|
20
|
+
to the ```https``` endpoint.
|
21
|
+
|
22
|
+
* Callers can rescue on ```GeoNamesAPI::InvalidParameter``` and ```GeoNamesAPI::InvalidInput``` now.
|
23
|
+
|
24
|
+
* GeoNamesAPI.formatted was deleted. The consumer shouldn't care if the JSON response
|
25
|
+
was pretty-printed.
|
26
|
+
|
27
|
+
* Timezones, AlternateNames, and GeoName entities are encoded as class instances now
|
28
|
+
|
data/README.md
CHANGED
@@ -1,12 +1,23 @@
|
|
1
1
|
# GeoNames API
|
2
2
|
|
3
|
+
[](http://travis-ci.org/mceachen/geonames_api)
|
4
|
+
[](https://codeclimate.com/github/mceachen/geonames_api)
|
5
|
+
|
3
6
|
This is a lightweight client for the [GeoNames](http://www.geonames.org) API. Huge thanks to them for such a great service!
|
4
7
|
|
5
8
|
There are many GeoNames API clients. BUT, most are rewritten versions of a Java API whose interface is a little funny =|
|
6
9
|
|
7
10
|
This is a simplified ruby implementation that does not implement the entire API. But, its lightweight and has a nice interface and will be easy to extend :)
|
8
11
|
|
9
|
-
The gem was written by [@barelyknown](http://twitter.com/barelyknown).
|
12
|
+
The gem was originally written by [@barelyknown](http://twitter.com/barelyknown).
|
13
|
+
|
14
|
+
This fork adds
|
15
|
+
* automatic retries on timeout,
|
16
|
+
* properly encoded url parameters,
|
17
|
+
* support for paid users (with https and API tokens)
|
18
|
+
* more consistent ```find``` and ```where``` methods across endpoints
|
19
|
+
* Timezone, AlternateName, and GeoName entries properly encoded in results
|
20
|
+
* better test coverage, Travis CI, and CodeClimate integration
|
10
21
|
|
11
22
|
## Getting Started
|
12
23
|
|
@@ -184,4 +195,4 @@ The other services will be implemented as needed. In the mean time, feel free to
|
|
184
195
|
3. Commit your changes (`git commit -am 'Add some feature'`)
|
185
196
|
4. Push to the branch (`git push origin my-new-feature`)
|
186
197
|
5. Create new Pull Request
|
187
|
-
6. Thanks <3
|
198
|
+
6. Thanks <3
|
data/Rakefile
CHANGED
@@ -1 +1,14 @@
|
|
1
1
|
require "bundler/gem_tasks"
|
2
|
+
|
3
|
+
require 'rspec/core'
|
4
|
+
require 'rspec/core/rake_task'
|
5
|
+
RSpec::Core::RakeTask.new(:spec) do |spec|
|
6
|
+
spec.pattern = FileList['spec/**/*_spec.rb']
|
7
|
+
end
|
8
|
+
|
9
|
+
RSpec::Core::RakeTask.new(:rcov) do |spec|
|
10
|
+
spec.pattern = 'spec/**/*_spec.rb'
|
11
|
+
spec.rcov = true
|
12
|
+
end
|
13
|
+
|
14
|
+
task :default => :spec
|
data/geonames_api.gemspec
CHANGED
@@ -6,17 +6,19 @@ require 'geonames_api/version'
|
|
6
6
|
Gem::Specification.new do |gem|
|
7
7
|
gem.name = "geonames_api"
|
8
8
|
gem.version = GeoNamesAPI::VERSION
|
9
|
-
gem.authors = ["Sean Devine"]
|
10
|
-
gem.email = ["barelyknown@icloud.com"]
|
9
|
+
gem.authors = ["Sean Devine", "Matthew McEachen"]
|
10
|
+
gem.email = ["barelyknown@icloud.com", "matthew-github@mceachen.org"]
|
11
11
|
gem.description = %q{Simple ruby client for the GeoNames API to get free and easy geographic info.}
|
12
|
-
gem.summary = %q{This is a lightweight client for the GeoNames API. Huge thanks to them for such a great service! There are many GeoNames API clients. BUT, most are rewritten versions of a Java API whose interface is a little funny =| This is a simplified ruby implementation that does not implement the entire API. But,
|
12
|
+
gem.summary = %q{This is a lightweight client for the GeoNames API. Huge thanks to them for such a great service! There are many GeoNames API clients. BUT, most are rewritten versions of a Java API whose interface is a little funny =| This is a simplified ruby implementation that does not implement the entire API. But, it's lightweight and has a nice interface and will be easy to extend :)}
|
13
13
|
gem.homepage = "https://github.com/buytruckload/geonames_api"
|
14
14
|
|
15
15
|
gem.add_runtime_dependency "activesupport"
|
16
|
+
gem.add_runtime_dependency "tzinfo"
|
16
17
|
gem.add_runtime_dependency "zipruby"
|
17
|
-
|
18
|
+
gem.add_development_dependency 'rake'
|
19
|
+
gem.add_development_dependency 'rspec'
|
20
|
+
|
18
21
|
gem.files = `git ls-files`.split($/)
|
19
|
-
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
20
22
|
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
21
23
|
gem.require_paths = ["lib"]
|
22
24
|
end
|
data/lib/geonames_api.rb
CHANGED
@@ -3,34 +3,45 @@ require 'json'
|
|
3
3
|
require 'csv'
|
4
4
|
require 'active_support/all'
|
5
5
|
require 'zipruby'
|
6
|
-
require "geonames_api/version"
|
7
|
-
require "geonames_api/hash"
|
8
|
-
require "geonames_api/error"
|
9
|
-
require "geonames_api/object"
|
10
|
-
require "geonames_api/country"
|
11
|
-
require "geonames_api/weather"
|
12
|
-
require "geonames_api/time_zone"
|
13
|
-
require "geonames_api/wikipedia"
|
14
6
|
|
15
7
|
module GeoNamesAPI
|
16
|
-
|
8
|
+
|
17
9
|
mattr_accessor :url
|
18
|
-
|
10
|
+
self.url = 'http://api.geonames.org/'
|
19
11
|
|
20
|
-
mattr_accessor :formatted
|
21
|
-
@@formatted = true
|
22
|
-
|
23
12
|
mattr_accessor :lang
|
24
|
-
|
13
|
+
self.lang = :en
|
25
14
|
|
26
15
|
mattr_accessor :username
|
27
|
-
|
28
|
-
|
16
|
+
self.username = 'demo'
|
17
|
+
|
18
|
+
mattr_accessor :token
|
19
|
+
self.token = nil
|
20
|
+
|
29
21
|
mattr_accessor :style
|
30
|
-
|
31
|
-
|
22
|
+
self.style = :full
|
23
|
+
|
24
|
+
mattr_accessor :logger
|
25
|
+
self.logger = nil
|
26
|
+
|
27
|
+
mattr_accessor :retries
|
28
|
+
self.retries = 3
|
29
|
+
|
30
|
+
mattr_accessor :max_sleep_time_between_retries
|
31
|
+
self.max_sleep_time_between_retries = 5
|
32
|
+
|
32
33
|
def self.params
|
33
|
-
{
|
34
|
+
{
|
35
|
+
lang: lang,
|
36
|
+
username: username,
|
37
|
+
token: token,
|
38
|
+
style: style
|
39
|
+
}.delete_if{ |k, v| v.blank? }
|
34
40
|
end
|
35
41
|
|
36
42
|
end
|
43
|
+
|
44
|
+
Dir[File.dirname(__FILE__) + '/geonames_api/*.rb'].each do |file|
|
45
|
+
tgt = File.basename(file, File.extname(file))
|
46
|
+
GeoNamesAPI.autoload tgt.camelize, "geonames_api/#{tgt}"
|
47
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
module GeoNamesAPI
|
2
|
+
# Arrays of Geoname instances are returned by `Hierarchy.find`
|
3
|
+
class AlternateNames
|
4
|
+
|
5
|
+
def initialize(alternate_names_array)
|
6
|
+
@name_by_lang = {}
|
7
|
+
alternate_names_array.each do |hash|
|
8
|
+
@name_by_lang[hash['lang']] = hash['name']
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def [](lang)
|
13
|
+
@name_by_lang[lang]
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
=begin
|
19
|
+
Expected input:
|
20
|
+
[
|
21
|
+
{
|
22
|
+
"name": "els Abruços",
|
23
|
+
"lang": "ca"
|
24
|
+
},
|
25
|
+
{
|
26
|
+
"name": "Abruzzen",
|
27
|
+
"lang": "de"
|
28
|
+
},
|
29
|
+
{
|
30
|
+
"name": "Abruzzo",
|
31
|
+
"lang": "en"
|
32
|
+
},
|
33
|
+
{
|
34
|
+
"name": "Los Abruzos",
|
35
|
+
"lang": "es"
|
36
|
+
},
|
37
|
+
{
|
38
|
+
"name": "Abruzzes",
|
39
|
+
"lang": "fr"
|
40
|
+
},
|
41
|
+
{
|
42
|
+
"name": "Abruzzo",
|
43
|
+
"lang": "it"
|
44
|
+
},
|
45
|
+
{
|
46
|
+
"name": "http://en.wikipedia.org/wiki/Abruzzo",
|
47
|
+
"lang": "link"
|
48
|
+
},
|
49
|
+
{
|
50
|
+
"name": "Abruzzen",
|
51
|
+
"lang": "nl"
|
52
|
+
}
|
53
|
+
]
|
54
|
+
=end
|
@@ -0,0 +1,92 @@
|
|
1
|
+
require 'cgi'
|
2
|
+
|
3
|
+
module GeoNamesAPI
|
4
|
+
class Base < Entity
|
5
|
+
|
6
|
+
def self.find(*names_or_params)
|
7
|
+
result = where(name_params(names_or_params))
|
8
|
+
if result
|
9
|
+
endpoint_returns_list? ? result.first : result
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.all(*names_or_params)
|
14
|
+
result = where(name_params(names_or_params))
|
15
|
+
if result
|
16
|
+
endpoint_returns_list? ? result : [result]
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.where(params={})
|
21
|
+
retries_remaining = GeoNamesAPI.retries
|
22
|
+
url = url(params)
|
23
|
+
begin
|
24
|
+
response = make_request(url)
|
25
|
+
unless response.empty?
|
26
|
+
parse_response(response, params)
|
27
|
+
end
|
28
|
+
rescue Timeout => e
|
29
|
+
if retries_remaining > 0
|
30
|
+
retries_remaining -= 1
|
31
|
+
puts "retrying!"
|
32
|
+
sleep rand * GeoNamesAPI.max_sleep_time_between_retries
|
33
|
+
retry
|
34
|
+
else
|
35
|
+
raise e
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def self.make_request(url)
|
41
|
+
JSON.load(open(url).read)
|
42
|
+
end
|
43
|
+
|
44
|
+
private_class_method :make_request
|
45
|
+
|
46
|
+
KEYS = %w(streetSegment geonames)
|
47
|
+
|
48
|
+
def self.parse_response(response, request_params)
|
49
|
+
GeoNamesAPI.logger.info "GEONAMES RESPONSE (#{Time.now}): #{response}" if GeoNamesAPI.logger
|
50
|
+
if (status = response['status'])
|
51
|
+
raise Error.from_status(status)
|
52
|
+
end
|
53
|
+
new(response, request_params)
|
54
|
+
end
|
55
|
+
|
56
|
+
private_class_method :parse_response
|
57
|
+
|
58
|
+
def self.url(params={})
|
59
|
+
endpoint = GeoNamesAPI.url + self::METHOD + params_to_url(GeoNamesAPI.params.merge(params))
|
60
|
+
GeoNamesAPI.logger.info "GEONAMES REQUEST (#{Time.now}): #{endpoint}" if GeoNamesAPI.logger
|
61
|
+
endpoint
|
62
|
+
end
|
63
|
+
|
64
|
+
private_class_method :url
|
65
|
+
|
66
|
+
def self.name_params(names)
|
67
|
+
return names.first if names.first.is_a? Hash
|
68
|
+
params, n = {}, 0
|
69
|
+
if names.any?
|
70
|
+
[self::FIND_PARAMS].flatten.each { |i| params[i] = names[n]; n+= 1 }
|
71
|
+
end
|
72
|
+
params.delete_if { |k, v| v.blank? }
|
73
|
+
end
|
74
|
+
|
75
|
+
private_class_method :name_params
|
76
|
+
|
77
|
+
def self.params_to_url(params={})
|
78
|
+
esc_params = params.map do |key, value|
|
79
|
+
"#{esc(key)}=#{esc(value)}"
|
80
|
+
end
|
81
|
+
"?#{esc_params.join('&')}"
|
82
|
+
end
|
83
|
+
|
84
|
+
private_class_method :params_to_url
|
85
|
+
|
86
|
+
def self.esc(str)
|
87
|
+
CGI::escape(str.to_s)
|
88
|
+
end
|
89
|
+
|
90
|
+
private_class_method :esc
|
91
|
+
end
|
92
|
+
end
|
@@ -0,0 +1,85 @@
|
|
1
|
+
module GeoNamesAPI
|
2
|
+
class Children < ListEndpoint
|
3
|
+
|
4
|
+
METHOD = "childrenJSON"
|
5
|
+
FIND_PARAMS = %w(geonameId)
|
6
|
+
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
=begin
|
11
|
+
{
|
12
|
+
"totalResultsCount": 20,
|
13
|
+
"geonames": [
|
14
|
+
{
|
15
|
+
"alternateNames": [
|
16
|
+
{
|
17
|
+
"name": "els Abruços",
|
18
|
+
"lang": "ca"
|
19
|
+
},
|
20
|
+
{
|
21
|
+
"name": "Abruzzen",
|
22
|
+
"lang": "de"
|
23
|
+
},
|
24
|
+
{
|
25
|
+
"name": "Abruzzo",
|
26
|
+
"lang": "en"
|
27
|
+
},
|
28
|
+
{
|
29
|
+
"name": "Los Abruzos",
|
30
|
+
"lang": "es"
|
31
|
+
},
|
32
|
+
{
|
33
|
+
"name": "Abruzzes",
|
34
|
+
"lang": "fr"
|
35
|
+
},
|
36
|
+
{
|
37
|
+
"name": "Abruzzo",
|
38
|
+
"lang": "it"
|
39
|
+
},
|
40
|
+
{
|
41
|
+
"name": "http://en.wikipedia.org/wiki/Abruzzo",
|
42
|
+
"lang": "link"
|
43
|
+
},
|
44
|
+
{
|
45
|
+
"name": "Abruzzen",
|
46
|
+
"lang": "nl"
|
47
|
+
}
|
48
|
+
],
|
49
|
+
"countryName": "Italy",
|
50
|
+
"adminCode1": "01",
|
51
|
+
"lng": "13.75",
|
52
|
+
"adminName2": "",
|
53
|
+
"fcodeName": "first-order administrative division",
|
54
|
+
"adminName3": "",
|
55
|
+
"timezone": {
|
56
|
+
"dstOffset": 2,
|
57
|
+
"gmtOffset": 1,
|
58
|
+
"timeZoneId": "Europe/Rome"
|
59
|
+
},
|
60
|
+
"adminName4": "",
|
61
|
+
"adminName5": "",
|
62
|
+
"bbox": {
|
63
|
+
"south": 41.68307876586914,
|
64
|
+
"east": 14.783888816833496,
|
65
|
+
"north": 42.8957405090332,
|
66
|
+
"west": 13.019405364990234
|
67
|
+
},
|
68
|
+
"name": "Abruzzo",
|
69
|
+
"fcode": "ADM1",
|
70
|
+
"geonameId": 3183560,
|
71
|
+
"lat": "42.25",
|
72
|
+
"population": 1338898,
|
73
|
+
"adminName1": "Abruzzo",
|
74
|
+
"countryId": "3175395",
|
75
|
+
"adminId1": "3183560",
|
76
|
+
"fclName": "country, state, region,...",
|
77
|
+
"countryCode": "IT",
|
78
|
+
"wikipediaURL": "",
|
79
|
+
"toponymName": "Regione Abruzzo",
|
80
|
+
"fcl": "A",
|
81
|
+
"numberOfChildren": 4,
|
82
|
+
"continentCode": "EU"
|
83
|
+
},
|
84
|
+
|
85
|
+
=end
|
data/lib/geonames_api/country.rb
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
module GeoNamesAPI
|
2
|
-
class Country <
|
2
|
+
class Country < ListEndpoint
|
3
3
|
|
4
4
|
METHOD = "countryInfoJSON"
|
5
|
-
|
5
|
+
FIND_PARAMS = %w(country)
|
6
6
|
|
7
7
|
EXPORT_BASE_URL = "http://download.geonames.org/export/zip/"
|
8
8
|
EXPORT_HEADERS = %W(country_code postal_code place_name admin_name1 admin_code1 admin_name2 admin_code2 admin_name3 admin_code3 latitude longitude accuracy)
|
@@ -18,14 +18,14 @@ module GeoNamesAPI
|
|
18
18
|
end
|
19
19
|
csv
|
20
20
|
end
|
21
|
-
|
21
|
+
|
22
22
|
def postal_code_csv
|
23
23
|
CSV.parse(postal_code_export, headers: true, col_sep: "\t", header_converters: :symbol, encoding: "ISO8859-1")
|
24
24
|
end
|
25
|
-
|
25
|
+
|
26
26
|
def postal_code_export_url
|
27
27
|
EXPORT_BASE_URL + country_code + ".zip"
|
28
28
|
end
|
29
|
-
|
29
|
+
|
30
30
|
end
|
31
|
-
end
|
31
|
+
end
|