geonames_api 0.0.6 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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