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.
Files changed (46) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +2 -0
  3. data/.travis.yml +7 -0
  4. data/CHANGELOG.md +28 -0
  5. data/README.md +13 -2
  6. data/Rakefile +13 -0
  7. data/geonames_api.gemspec +7 -5
  8. data/lib/geonames_api.rb +30 -19
  9. data/lib/geonames_api/alternate_names.rb +54 -0
  10. data/lib/geonames_api/base.rb +92 -0
  11. data/lib/geonames_api/children.rb +85 -0
  12. data/lib/geonames_api/city.rb +8 -0
  13. data/lib/geonames_api/country.rb +6 -6
  14. data/lib/geonames_api/country_code.rb +8 -0
  15. data/lib/geonames_api/country_subdivision.rb +8 -0
  16. data/lib/geonames_api/earthquake.rb +8 -0
  17. data/lib/geonames_api/elevation.rb +16 -0
  18. data/lib/geonames_api/entity.rb +64 -0
  19. data/lib/geonames_api/error.rb +25 -2
  20. data/lib/geonames_api/geoname.rb +4 -0
  21. data/lib/geonames_api/hierarchy.rb +10 -0
  22. data/lib/geonames_api/list_endpoint.rb +21 -0
  23. data/lib/geonames_api/nearby_postal_code.rb +17 -0
  24. data/lib/geonames_api/place.rb +8 -0
  25. data/lib/geonames_api/place_name.rb +8 -0
  26. data/lib/geonames_api/place_search.rb +16 -0
  27. data/lib/geonames_api/postal_code.rb +23 -0
  28. data/lib/geonames_api/singleton_endpoint.rb +7 -0
  29. data/lib/geonames_api/street.rb +8 -0
  30. data/lib/geonames_api/time_zone.rb +17 -14
  31. data/lib/geonames_api/version.rb +2 -2
  32. data/lib/geonames_api/weather.rb +16 -16
  33. data/lib/geonames_api/weather_i_c_a_o.rb +8 -0
  34. data/lib/geonames_api/wikipedia.rb +5 -5
  35. data/spec/geonames_api/country_subdivision_spec.rb +27 -0
  36. data/spec/geonames_api/hierarchy_spec.rb +38 -0
  37. data/spec/geonames_api/place_name_spec.rb +22 -0
  38. data/spec/geonames_api/place_search_spec.rb +50 -0
  39. data/spec/geonames_api/place_spec.rb +17 -0
  40. data/spec/geonames_api/retry_spec.rb +37 -0
  41. data/spec/geonames_api/street_spec.rb +22 -0
  42. data/spec/geonames_api/weather_icao_spec.rb +10 -0
  43. data/spec/spec_helper.rb +15 -0
  44. metadata +97 -21
  45. data/lib/geonames_api/hash.rb +0 -5
  46. data/lib/geonames_api/object.rb +0 -72
@@ -0,0 +1,8 @@
1
+ module GeoNamesAPI
2
+ class CountryCode < SingletonEndpoint
3
+
4
+ METHOD = "countryCodeJSON"
5
+ FIND_PARAMS = %w(lat lng type lang radius)
6
+
7
+ end
8
+ end
@@ -0,0 +1,8 @@
1
+ module GeoNamesAPI
2
+ class CountrySubdivision < SingletonEndpoint
3
+
4
+ METHOD = "countrySubdivisionJSON"
5
+ FIND_PARAMS = %w(lat lng)
6
+
7
+ end
8
+ end
@@ -0,0 +1,8 @@
1
+ module GeoNamesAPI
2
+ class Earthquake < ListEndpoint
3
+
4
+ METHOD = "earthquakesJSON"
5
+ FIND_PARAMS = %w(north east south west date minMagnitude maxRows)
6
+
7
+ end
8
+ end
@@ -0,0 +1,16 @@
1
+ module GeoNamesAPI
2
+ class Elevation < SingletonEndpoint
3
+
4
+ METHOD = "astergdemJSON"
5
+ FIND_PARAMS = %w(lat lng)
6
+
7
+ end
8
+ end
9
+
10
+ =begin
11
+ {
12
+ "astergdem": 192,
13
+ "lng": 10.2,
14
+ "lat": 50.01
15
+ }
16
+ =end
@@ -0,0 +1,64 @@
1
+ require 'forwardable'
2
+
3
+ module GeoNamesAPI
4
+ class Entity
5
+ include Enumerable
6
+ extend Forwardable
7
+ def_delegator :geonames, :each
8
+ alias_method :size, :count
9
+ attr_reader :request_params
10
+
11
+ def initialize(response, request_params = nil)
12
+ @response = response
13
+ @request_params = request_params
14
+ parse_response
15
+ end
16
+
17
+ def parse_response
18
+ @response.keys.each { |ea| parse_attr(ea) }
19
+ end
20
+
21
+ def parse_attr(key)
22
+ return unless @response.has_key? key
23
+
24
+ aliases = []
25
+ value = @response[key]
26
+ parsed_value = case (key)
27
+ when 'geonames', 'streetSegment'
28
+ aliases = [:geonames, :results]
29
+ value.map { |ea| self.class.new(ea) }
30
+ when 'alternateNames'
31
+ AlternateNames.new(value)
32
+ when 'timezone'
33
+ TimeZone.new(value)
34
+ else
35
+ set_default_type(value)
36
+ end
37
+
38
+ attr_name = create_attribute(key, *aliases)
39
+ instance_variable_set(attr_name, parsed_value)
40
+ end
41
+
42
+ def create_attribute(attribute, *attribute_aliases)
43
+ attr_name = attribute.underscore.to_sym
44
+ self.class.send(:attr_reader, attr_name) unless respond_to?(attr_name)
45
+
46
+ attribute_aliases.each do |ea|
47
+ self.class.send(:alias_method, ea, attr_name) unless respond_to?(ea)
48
+ end
49
+
50
+ "@#{attr_name}".to_sym
51
+ end
52
+
53
+ def set_default_type(value)
54
+ case value
55
+ when /\A-?\d+\Z/
56
+ value.to_i
57
+ when /\A-?\d*\.\d*\Z/
58
+ value.to_f
59
+ else
60
+ value
61
+ end
62
+ end
63
+ end
64
+ end
@@ -1,5 +1,28 @@
1
1
  module GeoNamesAPI
2
2
  class Error < StandardError
3
-
3
+ # See http://www.geonames.org/export/webservice-exception.html
4
+ def self.from_status(status)
5
+ val = status['value'].to_i
6
+ error_type = case val
7
+ when 12, 13, 22
8
+ Timeout
9
+ when 14
10
+ InvalidParameter
11
+ when 21
12
+ InvalidInput
13
+ else
14
+ Error
15
+ end
16
+ raise error_type, "#{status['message']} (#{val})"
17
+ end
4
18
  end
5
- end
19
+
20
+ class Timeout < Error
21
+ end
22
+
23
+ class InvalidParameter < Error
24
+ end
25
+
26
+ class InvalidInput < Error
27
+ end
28
+ end
@@ -0,0 +1,4 @@
1
+ module GeoNamesAPI
2
+ class GeoName < Entity
3
+ end
4
+ end
@@ -0,0 +1,10 @@
1
+ module GeoNamesAPI
2
+ # This endpoint returns a list of geonames, but it's a single hierarchy,
3
+ # so it should be considered a singleton endpoint.
4
+ class Hierarchy < SingletonEndpoint
5
+
6
+ METHOD = "hierarchyJSON"
7
+ FIND_PARAMS = %w(geonameId)
8
+
9
+ end
10
+ end
@@ -0,0 +1,21 @@
1
+ require 'forwardable'
2
+ module GeoNamesAPI
3
+ class ListEndpoint < Base
4
+ def self.endpoint_returns_list?
5
+ true
6
+ end
7
+
8
+ def next_page
9
+ self.class.where(request_params.merge(
10
+ startRow: request_params[:startRow].to_i + size
11
+ ))
12
+ end
13
+
14
+ # Pages are 0-indexed.
15
+ def to_page(page_idx)
16
+ self.class.where(request_params.merge(
17
+ startRow: (request_params[:maxRows] || size).to_i * page_idx
18
+ ))
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,17 @@
1
+ module GeoNamesAPI
2
+ class NearbyPostalCode < ListEndpoint
3
+
4
+ #radius in km
5
+ METHOD = "findNearbyPostalCodesJSON"
6
+ FIND_PARAMS = %w(postalcode country radius maxRows)
7
+
8
+ def self.find_all_by_lat_lng(lat, lng, radius=10, maxRows=5)
9
+ where({
10
+ 'lat' => lat,
11
+ 'lng' => lng,
12
+ 'radius' => radius,
13
+ 'maxRows' => maxRows
14
+ }).collect { |response| PostalCode.new(response) if response }.compact
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,8 @@
1
+ module GeoNamesAPI
2
+ class Place < ListEndpoint
3
+
4
+ METHOD = "findNearbyJSON"
5
+ FIND_PARAMS = %w(lat lng radius maxRows)
6
+
7
+ end
8
+ end
@@ -0,0 +1,8 @@
1
+ module GeoNamesAPI
2
+ class PlaceName < ListEndpoint
3
+
4
+ METHOD = "findNearbyPlaceNameJSON"
5
+ FIND_PARAMS = %w(lat lng radius maxRows)
6
+
7
+ end
8
+ end
@@ -0,0 +1,16 @@
1
+ module GeoNamesAPI
2
+ class PlaceSearch < ListEndpoint
3
+
4
+ METHOD = 'searchJSON'
5
+ FIND_PARAMS = %w(q maxRows)
6
+ DEFAULT_MAX_ROWS = 100
7
+
8
+ def self.find_by_place_name(name, max_rows = DEFAULT_MAX_ROWS)
9
+ where(name: name, maxRows: max_rows)
10
+ end
11
+
12
+ def self.find_by_exact_place_name(name, max_rows = DEFAULT_MAX_ROWS)
13
+ where(name_equals: name, maxRows: max_rows)
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,23 @@
1
+ module GeoNamesAPI
2
+ class PostalCode < ListEndpoint
3
+
4
+ METHOD = "postalCodeLookupJSON"
5
+ FIND_PARAMS = %w(postalcode country)
6
+
7
+ def city
8
+ place_name
9
+ end
10
+
11
+ def state
12
+ admin_name1
13
+ end
14
+
15
+ def state_short
16
+ admin_code1
17
+ end
18
+
19
+ def nearby_codes(radius=10, maxRows=5)
20
+ NearbyPostalCode.all(postalcode, country_code, radius, maxRows)
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,7 @@
1
+ module GeoNamesAPI
2
+ class SingletonEndpoint < Base
3
+ def self.endpoint_returns_list?
4
+ false
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,8 @@
1
+ module GeoNamesAPI
2
+ class Street < ListEndpoint
3
+
4
+ METHOD = "findNearbyStreetsJSON"
5
+ FIND_PARAMS = %w(lat lng radius maxRows)
6
+
7
+ end
8
+ end
@@ -1,31 +1,34 @@
1
1
  module GeoNamesAPI
2
- class TimeZone < GeoNamesAPI::Object
3
-
2
+ class TimeZone < SingletonEndpoint
3
+
4
4
  METHOD = "timezoneJSON"
5
- ID = ["lat", "lng"]
6
- NESTED = false
7
-
5
+ FIND_PARAMS = %w(lat lng radius date)
6
+
8
7
  def time_zone
9
8
  ActiveSupport::TimeZone.new(timezone_id)
10
9
  end
11
-
10
+
11
+ def common_name
12
+ ActiveSupport::TimeZone::MAPPING.key(timezone_id)
13
+ end
14
+
12
15
  def local(time_type)
13
16
  t = DateTime.parse(send(time_type))
14
17
  time_zone.local(t.year, t.month, t.day, t.hour, t.minute)
15
18
  end
16
-
19
+
17
20
  def utc(time_type)
18
21
  local(time_type).utc
19
22
  end
20
-
23
+
21
24
  def method_missing(method, *args)
22
25
  case method
23
- # Provides the local and utc time variant of each time
24
- # Examples: time_zone.sunrise_local, time_zone.time_utc
25
- when /\A(.*)_(local|utc)\Z/
26
- send($2, $1)
26
+ # Provides the local and utc time variant of each time
27
+ # Examples: time_zone.sunrise_local, time_zone.time_utc
28
+ when /\A(.*)_(local|utc)\Z/
29
+ send($2, $1)
27
30
  end
28
31
  end
29
-
32
+
30
33
  end
31
- end
34
+ end
@@ -1,3 +1,3 @@
1
1
  module GeoNamesAPI
2
- VERSION = "0.0.6"
3
- end
2
+ VERSION = Gem::Version.new('0.1.0')
3
+ end
@@ -1,38 +1,38 @@
1
1
  module GeoNamesAPI
2
- class Weather < GeoNamesAPI::Object
3
-
2
+ class Weather < List
3
+
4
4
  METHOD = "findNearByWeatherJSON"
5
- ID = ["lat", "lng"]
6
-
5
+ FIND_PARAMS = %w(lat lng radius)
6
+
7
7
  def geo_names_api_country
8
8
  @geo_names_api_country ||= GeoNamesAPI::Country.find(country_code)
9
9
  end
10
-
10
+
11
11
  def geo_names_api_time_zone
12
12
  @geo_names_api_time_zone ||= GeoNamesAPI::TimeZone.find(lat, lng)
13
13
  end
14
-
14
+
15
15
  def time_zone
16
16
  geo_names_api_time_zone.time_zone
17
17
  end
18
-
18
+
19
19
  def at_local
20
20
  t = DateTime.parse(datetime)
21
21
  time_zone.local(t.year, t.month, t.day, t.hour, t.minute)
22
22
  end
23
-
23
+
24
24
  def at_utc
25
25
  at_local.utc
26
26
  end
27
-
27
+
28
28
  def elevation_feet
29
29
  elevation * 3.28084 if elevation
30
30
  end
31
-
31
+
32
32
  def elevation_meters
33
33
  elevation if elevation
34
34
  end
35
-
35
+
36
36
  def convert_c_to_f(temp)
37
37
  temp * 9.to_f / 5.to_f + 32
38
38
  end
@@ -40,18 +40,18 @@ module GeoNamesAPI
40
40
  def temperature_f
41
41
  convert_c_to_f(temperature) if temperature
42
42
  end
43
-
43
+
44
44
  def temperature_c
45
45
  temperature if temperature
46
46
  end
47
-
47
+
48
48
  def dew_point_f
49
49
  convert_c_to_f(dew_point) if temperature
50
50
  end
51
-
51
+
52
52
  def dew_point_c
53
53
  dew_point if temperature
54
54
  end
55
-
55
+
56
56
  end
57
- end
57
+ end
@@ -0,0 +1,8 @@
1
+ module GeoNamesAPI
2
+ class WeatherICAO < SingletonEndpoint
3
+
4
+ METHOD = 'weatherIcaoJSON'
5
+ FIND_PARAMS = %w(ICAO)
6
+
7
+ end
8
+ end
@@ -1,8 +1,8 @@
1
1
  module GeoNamesAPI
2
- class Wikipedia < GeoNamesAPI::Object
3
-
2
+ class Wikipedia < ListEndpoint
3
+
4
4
  METHOD = "findNearbyWikipediaJSON"
5
- ID = %W(lat lng)
6
-
5
+ FIND_PARAMS = %W(lat lng radius maxRows)
6
+
7
7
  end
8
- end
8
+ end
@@ -0,0 +1,27 @@
1
+ require 'spec_helper'
2
+
3
+
4
+ describe GeoNamesAPI::CountrySubdivision do
5
+ def should_be_sf(result)
6
+ result.should be_present
7
+ result.admin_code1.should == 'CA'
8
+ result.admin_name1.should == 'California'
9
+ result.country_code.should == 'US'
10
+ result.country_name.should == 'United States'
11
+ end
12
+
13
+ describe '::find' do
14
+ it 'should find one subdivision' do
15
+ result = GeoNamesAPI::CountrySubdivision.find(37.8, -122.4)
16
+ should_be_sf(result)
17
+ end
18
+ end
19
+
20
+ describe '::all' do
21
+ it 'should find multiple subdivisions' do
22
+ result = GeoNamesAPI::CountrySubdivision.all(37.8, -122.4)
23
+ result.size.should > 0
24
+ should_be_sf(result.first)
25
+ end
26
+ end
27
+ end