earth_tools 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/earth_tools/configuration.rb +73 -0
- data/lib/earth_tools/exceptions.rb +30 -0
- data/lib/earth_tools/lookup/base.rb +104 -0
- data/lib/earth_tools/lookup/height.rb +18 -0
- data/lib/earth_tools/lookup/sunrise_sunset.rb +14 -0
- data/lib/earth_tools/lookup/time_zone.rb +14 -0
- data/lib/earth_tools/result/base.rb +49 -0
- data/lib/earth_tools/result/height.rb +39 -0
- data/lib/earth_tools/result/sunrise_sunset.rb +119 -0
- data/lib/earth_tools/result/time_zone.rb +78 -0
- data/lib/earth_tools/version.rb +4 -0
- data/lib/earth_tools.rb +91 -0
- data/test/configuration_test.rb +51 -0
- data/test/earth_tools_test.rb +24 -0
- data/test/fixtures/height_(52.4822,-1.8946).xml +10 -0
- data/test/fixtures/sun_(40.71417,-74.00639,4,12,99,0).xml +30 -0
- data/test/fixtures/timezone_(40.71417,-74.00639).xml +14 -0
- data/test/height_test.rb +39 -0
- data/test/integration/height_smoke_test.rb +30 -0
- data/test/integration/sunrise_sunset_smoke_test.rb +15 -0
- data/test/integration/time_zone_smoke_test.rb +13 -0
- data/test/mock_lookup.rb +18 -0
- data/test/sunrise_sunset_test.rb +92 -0
- data/test/test_helper.rb +5 -0
- data/test/time_zone_test.rb +58 -0
- metadata +93 -0
@@ -0,0 +1,73 @@
|
|
1
|
+
require 'singleton'
|
2
|
+
module EarthTools
|
3
|
+
|
4
|
+
## This method can be used to change some functional aspects, like,
|
5
|
+
# the geocoding service provider, or the units of calculations.
|
6
|
+
# Please see {include:Configuration}
|
7
|
+
def self.configure(&block)
|
8
|
+
if block_given?
|
9
|
+
block.call(Configuration.instance)
|
10
|
+
else
|
11
|
+
Configuration.instance
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
class Configuration
|
16
|
+
include Singleton
|
17
|
+
|
18
|
+
OPTIONS = [
|
19
|
+
:timeout,
|
20
|
+
:proxy,
|
21
|
+
:cache,
|
22
|
+
:cache_prefix,
|
23
|
+
:always_raise,
|
24
|
+
:units
|
25
|
+
]
|
26
|
+
|
27
|
+
attr_accessor *OPTIONS
|
28
|
+
|
29
|
+
def initialize # :nodoc
|
30
|
+
set_defaults
|
31
|
+
end
|
32
|
+
|
33
|
+
# This method will set the configuration options to the default values
|
34
|
+
def set_defaults
|
35
|
+
@timeout = 3 # geocoding service timeout (secs)
|
36
|
+
@proxy = nil # HTTP proxy server (user:pass@host:port)
|
37
|
+
@cache = nil # cache object (must respond to #[], #[]=, and #keys)
|
38
|
+
@cache_prefix = "earth_tools:" # prefix (string) to use for all cache keys
|
39
|
+
|
40
|
+
# exceptions that should not be rescued by default
|
41
|
+
# (if you want to implement custom error handling);
|
42
|
+
# supports SocketError and Timeout::Error
|
43
|
+
@always_raise = []
|
44
|
+
|
45
|
+
# calculation options
|
46
|
+
@units = :english # :metric or :english
|
47
|
+
end
|
48
|
+
|
49
|
+
|
50
|
+
# Delegates getters and setters for all configuration settings,
|
51
|
+
# and +set_defaults+ to the singleton instance.
|
52
|
+
instance_eval(OPTIONS.map do |option|
|
53
|
+
o = option.to_s
|
54
|
+
<<-EOS
|
55
|
+
def #{o}
|
56
|
+
instance.#{o}
|
57
|
+
end
|
58
|
+
|
59
|
+
def #{o}=(value)
|
60
|
+
instance.#{o} = value
|
61
|
+
end
|
62
|
+
EOS
|
63
|
+
end.join("\n\n"))
|
64
|
+
|
65
|
+
class << self
|
66
|
+
# This method will set the configuration options to the default values
|
67
|
+
def set_defaults
|
68
|
+
instance.set_defaults
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
end
|
73
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module EarthTools
|
2
|
+
|
3
|
+
class Error < StandardError
|
4
|
+
end
|
5
|
+
|
6
|
+
##
|
7
|
+
#
|
8
|
+
#
|
9
|
+
class ConfigurationError < Error
|
10
|
+
end
|
11
|
+
|
12
|
+
##
|
13
|
+
#
|
14
|
+
#
|
15
|
+
class OverQueryLimitError < Error
|
16
|
+
end
|
17
|
+
|
18
|
+
##
|
19
|
+
#
|
20
|
+
#
|
21
|
+
class InvalidInputError < Error
|
22
|
+
end
|
23
|
+
|
24
|
+
##
|
25
|
+
#
|
26
|
+
#
|
27
|
+
class UnsupportedOperationError < Error
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
@@ -0,0 +1,104 @@
|
|
1
|
+
require 'rest_client'
|
2
|
+
require 'xmlsimple'
|
3
|
+
require 'earth_tools/configuration'
|
4
|
+
|
5
|
+
module EarthTools
|
6
|
+
module Lookup
|
7
|
+
|
8
|
+
##
|
9
|
+
#
|
10
|
+
#
|
11
|
+
class Base
|
12
|
+
|
13
|
+
##
|
14
|
+
# Query the Earth Tools service and return a EarthTools::Result object.
|
15
|
+
# @return [EarthTools::Result, nil]
|
16
|
+
def search(*options)
|
17
|
+
begin
|
18
|
+
Timeout::timeout(EarthTools::Configuration.timeout) do
|
19
|
+
raw_results = retrieve(query(options))
|
20
|
+
parse_results(raw_results, :xml)
|
21
|
+
end
|
22
|
+
rescue Timeout::Error => err
|
23
|
+
raise_error(err) or warn "Earth Tools API took too long to respond. See EarthTools::Configuration to set the timeout time (currently set to #{EarthTools::Configuration.timeout} seconds)."
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
##
|
30
|
+
# The base URL for the web service endpoint (protocol and server)
|
31
|
+
# @return [String] the base URL
|
32
|
+
def base_service_url
|
33
|
+
"http://www.earthtools.org"
|
34
|
+
end
|
35
|
+
|
36
|
+
##
|
37
|
+
# URL to use for querying the geocoding engine.
|
38
|
+
# @return [String]
|
39
|
+
def query(*options)
|
40
|
+
base_service_url + query_base + options.join('/')
|
41
|
+
end
|
42
|
+
|
43
|
+
##
|
44
|
+
# Parse results depending on if xml or json
|
45
|
+
#
|
46
|
+
def parse_results(raw_results, type)
|
47
|
+
case type
|
48
|
+
when :xml
|
49
|
+
parse_xml(XmlSimple.xml_in( raw_results, { 'ForceArray' => false } ))
|
50
|
+
when :json
|
51
|
+
raise UnsupportedOperationError, "JSON is not supported"
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
##
|
56
|
+
# Handle XML results by validating them
|
57
|
+
#
|
58
|
+
def parse_xml(xml)
|
59
|
+
if xml['location']
|
60
|
+
result_class.new(xml)
|
61
|
+
else
|
62
|
+
warn "Invalid request."
|
63
|
+
puts xml
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
##
|
68
|
+
# Handles running query
|
69
|
+
#
|
70
|
+
def retrieve(query)
|
71
|
+
RestClient.proxy = EarthTools::Configuration.proxy if EarthTools::Configuration.proxy
|
72
|
+
#puts "Trying to connect to endpoint(#{query})"
|
73
|
+
#puts "Using proxy (#{RestClient.proxy})" if RestClient.proxy
|
74
|
+
RestClient.get query
|
75
|
+
end
|
76
|
+
|
77
|
+
##
|
78
|
+
# Raise exception if configuration specifies it should be raised.
|
79
|
+
# Return false if exception not raised.
|
80
|
+
#
|
81
|
+
def raise_error(error, message = nil)
|
82
|
+
if EarthTools::Configuration.always_raise.include?( error.is_a?(Class) ? error : error.class )
|
83
|
+
raise error, message
|
84
|
+
else
|
85
|
+
false
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
##
|
90
|
+
#
|
91
|
+
#
|
92
|
+
def query_base
|
93
|
+
raise NotImplementedError
|
94
|
+
end
|
95
|
+
|
96
|
+
##
|
97
|
+
#
|
98
|
+
#
|
99
|
+
def result_class
|
100
|
+
EarthTools::Result.const_get(self.class.to_s.split(":").last)
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
module EarthTools
|
2
|
+
module Result
|
3
|
+
|
4
|
+
##
|
5
|
+
#
|
6
|
+
#
|
7
|
+
class Base
|
8
|
+
attr_accessor :data
|
9
|
+
|
10
|
+
##
|
11
|
+
# Takes a hash of result data from a parsed Google result document.
|
12
|
+
#
|
13
|
+
def initialize(data)
|
14
|
+
@data = data
|
15
|
+
end
|
16
|
+
|
17
|
+
##
|
18
|
+
# Get the geographical location
|
19
|
+
# @returns [Array] a two-element array: [latitude, longitude]
|
20
|
+
def location
|
21
|
+
[latitude, longitude]
|
22
|
+
end
|
23
|
+
|
24
|
+
##
|
25
|
+
# Get the latitude
|
26
|
+
# See {http://en.wikipedia.org/wiki/Latitude}.
|
27
|
+
# @returns [Float] the latitude
|
28
|
+
def latitude
|
29
|
+
@data['latitude'].to_f
|
30
|
+
end
|
31
|
+
|
32
|
+
##
|
33
|
+
# Get the longitude
|
34
|
+
# See {http://en.wikipedia.org/wiki/Longitude}.
|
35
|
+
# @returns the longitude
|
36
|
+
def longitude
|
37
|
+
@data['longitude'].to_f
|
38
|
+
end
|
39
|
+
|
40
|
+
##
|
41
|
+
# The version of the response format
|
42
|
+
# @returns [Float] the version
|
43
|
+
def version
|
44
|
+
@data['version'].to_f
|
45
|
+
end
|
46
|
+
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'earth_tools/result/base'
|
2
|
+
require 'earth_tools/configuration'
|
3
|
+
|
4
|
+
module EarthTools::Result
|
5
|
+
|
6
|
+
##
|
7
|
+
#
|
8
|
+
#
|
9
|
+
class Height < Base
|
10
|
+
|
11
|
+
##
|
12
|
+
# Returns height based on unit requested in configuration
|
13
|
+
# @return [float]
|
14
|
+
def height
|
15
|
+
if EarthTools::Configuration.units == :metric
|
16
|
+
meters
|
17
|
+
else
|
18
|
+
feet
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
##
|
23
|
+
# The height above sea level in meters
|
24
|
+
# See {http://en.wikipedia.org/wiki/Meter}.
|
25
|
+
# @return [float] the height above sea level in meters
|
26
|
+
def meters
|
27
|
+
@data['meters'].to_f
|
28
|
+
end
|
29
|
+
|
30
|
+
##
|
31
|
+
# The height above sea level in feet
|
32
|
+
# See {http://en.wikipedia.org/wiki/Foot_(unit)}.
|
33
|
+
# @return [float] the height above sea level in feet
|
34
|
+
def feet
|
35
|
+
@data['feet'].to_f
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,119 @@
|
|
1
|
+
require 'earth_tools/result/base'
|
2
|
+
|
3
|
+
module EarthTools::Result
|
4
|
+
|
5
|
+
##
|
6
|
+
# The sunrise/sunset result object
|
7
|
+
#
|
8
|
+
class SunriseSunset < Base
|
9
|
+
|
10
|
+
##
|
11
|
+
# The date of the sunrise/sunset data as a hash
|
12
|
+
# @return [Hash] Hash containing year, month, and day as integers
|
13
|
+
def date
|
14
|
+
{ :year => Time.now.year, :month => @data['date']['month'].to_i, :day => @data['date']['day'].to_i }
|
15
|
+
end
|
16
|
+
|
17
|
+
##
|
18
|
+
# The sunrise time
|
19
|
+
# @return [Time] the sunrise time
|
20
|
+
def sunrise
|
21
|
+
create_time @data['morning']['sunrise']
|
22
|
+
end
|
23
|
+
|
24
|
+
##
|
25
|
+
# The sunset time
|
26
|
+
# @return [Time] the sunset time
|
27
|
+
def sunset
|
28
|
+
create_time @data['evening']['sunset']
|
29
|
+
end
|
30
|
+
|
31
|
+
##
|
32
|
+
# The twilight time for the specified time and type
|
33
|
+
# @param [Symbol] the time (:morning or :evening)
|
34
|
+
# @param [Symbol] the type (:astronomical, :civil, or :nautical)
|
35
|
+
# @return [Time] the requested twilight time
|
36
|
+
def twilight(time, type)
|
37
|
+
time = time.to_sym if time.is_a?(String)
|
38
|
+
type = type.to_sym if type.is_a?(String)
|
39
|
+
send "#{time}_#{type}_twilight" if [:morning, :evening].include?(time) && [:astronomical, :civil, :nautical].include?(type)
|
40
|
+
end
|
41
|
+
|
42
|
+
##
|
43
|
+
# The morning twilight time for the specified type
|
44
|
+
# @param [Symbol] the type of morning twilight time
|
45
|
+
# @return [Time] the specified morning twilight time
|
46
|
+
def morning_twilight(type)
|
47
|
+
twilight :morning, type
|
48
|
+
end
|
49
|
+
|
50
|
+
##
|
51
|
+
# The evening twilight time for the specified type
|
52
|
+
# @param [Symbol] the type of evening twilight time
|
53
|
+
# @return [Time] the specified evening twilight time
|
54
|
+
def evening_twilight(type)
|
55
|
+
twilight :evening, type
|
56
|
+
end
|
57
|
+
|
58
|
+
##
|
59
|
+
# The evening astronomical twilight time
|
60
|
+
# @return [Time] the astronomical twilight time for the evening
|
61
|
+
def evening_astronomical_twilight
|
62
|
+
create_time @data['evening']['twilight']['astronomical']
|
63
|
+
end
|
64
|
+
|
65
|
+
##
|
66
|
+
# The evening civil twilight time
|
67
|
+
# @return [Time] the civil twilight time for the evening
|
68
|
+
def evening_civil_twilight
|
69
|
+
create_time @data['evening']['twilight']['civil']
|
70
|
+
end
|
71
|
+
|
72
|
+
##
|
73
|
+
# The evening nautical twilight time
|
74
|
+
# @return [Time] the nautical twilight time for the evening
|
75
|
+
def evening_nautical_twilight
|
76
|
+
create_time @data['evening']['twilight']['nautical']
|
77
|
+
end
|
78
|
+
|
79
|
+
##
|
80
|
+
# The morning astronomical twilight time
|
81
|
+
# @return [Time] the astronomical twilight time for the morning
|
82
|
+
def morning_astronomical_twilight
|
83
|
+
create_time @data['morning']['twilight']['astronomical']
|
84
|
+
end
|
85
|
+
|
86
|
+
##
|
87
|
+
# The morning civil twilight time
|
88
|
+
# @return [Time] the civil twilight time for the morning
|
89
|
+
def morning_civil_twilight
|
90
|
+
create_time @data['morning']['twilight']['civil']
|
91
|
+
end
|
92
|
+
|
93
|
+
##
|
94
|
+
# The morning nautical twilight time
|
95
|
+
# @return [Time] the nautical twilight time for the morning
|
96
|
+
def morning_nautical_twilight
|
97
|
+
create_time @data['morning']['twilight']['nautical']
|
98
|
+
end
|
99
|
+
|
100
|
+
##
|
101
|
+
# The number of hours offset from UTC disregarding any correction for daylight saving time
|
102
|
+
# See {http://en.wikipedia.org/wiki/UTC_offset}.
|
103
|
+
# @return [Integer] the UTC offset
|
104
|
+
def utc_offset
|
105
|
+
@data['date']['timezone'].to_i
|
106
|
+
end
|
107
|
+
|
108
|
+
private
|
109
|
+
|
110
|
+
##
|
111
|
+
# Parses time
|
112
|
+
# @returns [Time] The parse time
|
113
|
+
def create_time(time)
|
114
|
+
times = time.split(':').collect{|s| s.to_i}
|
115
|
+
Time.new(date[:year], date[:month], date[:day], times[0], times[1], times[2], utc_offset * 3600)
|
116
|
+
end
|
117
|
+
|
118
|
+
end
|
119
|
+
end
|
@@ -0,0 +1,78 @@
|
|
1
|
+
require 'earth_tools/result/base'
|
2
|
+
|
3
|
+
module EarthTools::Result
|
4
|
+
|
5
|
+
##
|
6
|
+
#
|
7
|
+
#
|
8
|
+
class TimeZone < Base
|
9
|
+
|
10
|
+
##
|
11
|
+
# Whether or not the {#local_time} and {#iso_time} is currently in DST. If they do, the value of this element will be 'True'. If they do not, the value will be 'False'. If it can't be determined whether or not daylight saving time should be used, the value will be 'Unknown'.
|
12
|
+
# @return [String] 'True' || 'False' || 'Unknown'
|
13
|
+
def dst
|
14
|
+
@data['dst']
|
15
|
+
end
|
16
|
+
|
17
|
+
##
|
18
|
+
# Whether or not the {#local_time} and {#iso_time} is currently in DST
|
19
|
+
# @return [boolean] true || false || nil
|
20
|
+
def dst?
|
21
|
+
case @data['dst']
|
22
|
+
when 'True' then
|
23
|
+
true
|
24
|
+
when 'False'
|
25
|
+
false
|
26
|
+
else
|
27
|
+
nil
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
##
|
32
|
+
# The same value as {#local_time} but in ISO 8601 format instead
|
33
|
+
# See {http://en.wikipedia.org/wiki/ISO_8601}.
|
34
|
+
# @return [String] the ISO time
|
35
|
+
def iso_time
|
36
|
+
create_time @data['isotime']
|
37
|
+
end
|
38
|
+
|
39
|
+
##
|
40
|
+
# The local time taking into account the time zone offset and any local daylight saving time in effect
|
41
|
+
# @return [String] the local time
|
42
|
+
def local_time
|
43
|
+
iso_time
|
44
|
+
end
|
45
|
+
|
46
|
+
##
|
47
|
+
# The number of hours offset from UTC disregarding any correction for daylight saving time
|
48
|
+
# See {http://en.wikipedia.org/wiki/UTC_offset}.
|
49
|
+
# @return [Integer] the UTC offset
|
50
|
+
def utc_offset
|
51
|
+
@data['offset'].to_i
|
52
|
+
end
|
53
|
+
|
54
|
+
##
|
55
|
+
# The nautical suffix for the time zone
|
56
|
+
# See {http://en.wikipedia.org/wiki/Nautical_time}
|
57
|
+
# @return [String] the nautical suffix for the time zone
|
58
|
+
def suffix
|
59
|
+
@data['suffix']
|
60
|
+
end
|
61
|
+
|
62
|
+
##
|
63
|
+
# The reference UTC time
|
64
|
+
# See {http://en.wikipedia.org/wiki/Coordinated_Universal_Time}.
|
65
|
+
# @return [String] the UTC time
|
66
|
+
def utc_time
|
67
|
+
create_time @data['utctime'], "%Y-%m-%d %H:%M:%S"
|
68
|
+
end
|
69
|
+
|
70
|
+
private
|
71
|
+
|
72
|
+
def create_time(time, format = "%Y-%m-%d %H:%M:%S %z")
|
73
|
+
require 'date'
|
74
|
+
DateTime.strptime(time, format).to_time
|
75
|
+
end
|
76
|
+
|
77
|
+
end
|
78
|
+
end
|
data/lib/earth_tools.rb
ADDED
@@ -0,0 +1,91 @@
|
|
1
|
+
##
|
2
|
+
#
|
3
|
+
#
|
4
|
+
#
|
5
|
+
module EarthTools
|
6
|
+
extend self
|
7
|
+
|
8
|
+
##
|
9
|
+
# Retrieve for time zone based on latitude and longitude.
|
10
|
+
#
|
11
|
+
# @returns [EarthTools::Result::TimeZone]
|
12
|
+
#
|
13
|
+
def time_zone(latitude, longitude)
|
14
|
+
get_lookup(:time_zone).search(latitude, longitude) if valid_input?(latitude, longitude)
|
15
|
+
end
|
16
|
+
|
17
|
+
##
|
18
|
+
# Retrieve the sunrise & sunset values
|
19
|
+
#
|
20
|
+
# @returns [EarthTools::Result::SunriseSunset]
|
21
|
+
#
|
22
|
+
def sunrise_sunset(latitude, longitude, month, day, timezone = 99, dst = false)
|
23
|
+
get_lookup(:sunrise_sunset).search(latitude, longitude, day, month, timezone, dst ? 1 : 0)
|
24
|
+
end
|
25
|
+
|
26
|
+
##
|
27
|
+
# Retrieve the land height for a given latitude and longitude
|
28
|
+
#
|
29
|
+
# @returns [EarthTools::Result::Height]
|
30
|
+
#
|
31
|
+
def height(latitude, longitude)
|
32
|
+
get_lookup(:height).search(latitude, longitude)
|
33
|
+
end
|
34
|
+
|
35
|
+
private
|
36
|
+
|
37
|
+
##
|
38
|
+
# Retrieve a lookup object from the store.
|
39
|
+
#
|
40
|
+
def get_lookup(name)
|
41
|
+
@lookups = {} unless defined?(@lookups)
|
42
|
+
@lookups[name] = spawn_lookup(name) unless @lookups.include?(name)
|
43
|
+
@lookups[name]
|
44
|
+
end
|
45
|
+
|
46
|
+
##
|
47
|
+
# Spawn a lookup of the given name.
|
48
|
+
#
|
49
|
+
def spawn_lookup(name)
|
50
|
+
name = name.to_s
|
51
|
+
require "earth_tools/lookup/#{name}"
|
52
|
+
klass = name.split("_").map{ |i| i[0...1].upcase + i[1..-1] }.join
|
53
|
+
EarthTools::Lookup.const_get(klass).new
|
54
|
+
end
|
55
|
+
|
56
|
+
##
|
57
|
+
# Validates input
|
58
|
+
#
|
59
|
+
def valid_input?(latitude, longitude)
|
60
|
+
coordinates?(latitude, longitude)
|
61
|
+
end
|
62
|
+
|
63
|
+
##
|
64
|
+
# Validates input
|
65
|
+
#
|
66
|
+
def valid_full_input?(latitude, longitude, day, month, timezone, dst)
|
67
|
+
coordinates?(latitude, longitude) && !blank?(day) && !blank(month) && !blank?(timezone) && !blank?(dst)
|
68
|
+
end
|
69
|
+
|
70
|
+
##
|
71
|
+
# Validates a pair of coordinates
|
72
|
+
#
|
73
|
+
def coordinates?(latitude, longitude)
|
74
|
+
coordinate?(latitude) && coordinate?(longitude)
|
75
|
+
end
|
76
|
+
|
77
|
+
##
|
78
|
+
# Determine if given value is a coordinate
|
79
|
+
#
|
80
|
+
def coordinate?(value)
|
81
|
+
!! value.to_f
|
82
|
+
end
|
83
|
+
|
84
|
+
##
|
85
|
+
# Determine if given value is blank
|
86
|
+
#
|
87
|
+
def blank?(value)
|
88
|
+
value.nil? || value.to_s.empty?
|
89
|
+
end
|
90
|
+
|
91
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
require 'test_helper'
|
3
|
+
|
4
|
+
class ConfigurationTest < MiniTest::Unit::TestCase
|
5
|
+
|
6
|
+
def setup
|
7
|
+
EarthTools::Configuration.set_defaults
|
8
|
+
end
|
9
|
+
|
10
|
+
# --- class method configuration ---
|
11
|
+
def test_configurated_by_class_method
|
12
|
+
EarthTools::Configuration.units = :metric
|
13
|
+
assert_equal EarthTools::Configuration.units, :metric
|
14
|
+
result = EarthTools.height(52.4822, -1.8946)
|
15
|
+
if result.height == 0
|
16
|
+
assert_equal result.height, result.feet
|
17
|
+
else
|
18
|
+
refute_equal result.height, result.feet
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
# --- EarthTools#configure distances configuration ---
|
23
|
+
def test_configuration
|
24
|
+
|
25
|
+
# DSL
|
26
|
+
EarthTools.configure do |config|
|
27
|
+
config.units = :metric
|
28
|
+
end
|
29
|
+
|
30
|
+
assert_equal EarthTools::Configuration.units, :metric
|
31
|
+
result = EarthTools.height(52.4822, -1.8946)
|
32
|
+
if result.height == 0
|
33
|
+
assert_equal result.height, result.feet
|
34
|
+
else
|
35
|
+
refute_equal result.height, result.feet
|
36
|
+
end
|
37
|
+
|
38
|
+
# Direct
|
39
|
+
EarthTools.configure.units = :metric
|
40
|
+
|
41
|
+
assert_equal EarthTools::Configuration.units, :metric
|
42
|
+
result = EarthTools.height(52.4822, -1.8946)
|
43
|
+
assert_equal result.height, result.meters
|
44
|
+
if result.height == 0
|
45
|
+
assert_equal result.height, result.feet
|
46
|
+
else
|
47
|
+
refute_equal result.height, result.feet
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'test_helper'
|
4
|
+
require 'earth_tools'
|
5
|
+
require 'earth_tools/result/height'
|
6
|
+
require 'earth_tools/result/sunrise_sunset'
|
7
|
+
require 'earth_tools/result/time_zone'
|
8
|
+
require 'mock_lookup'
|
9
|
+
|
10
|
+
class EarthToolsTest < MiniTest::Unit::TestCase
|
11
|
+
|
12
|
+
def test_time_zone_method_returns_result_object
|
13
|
+
assert EarthTools.time_zone(40.71417, -74.00639).is_a?(EarthTools::Result::TimeZone)
|
14
|
+
end
|
15
|
+
|
16
|
+
def test_sunrise_sunset_method_returns_result_object
|
17
|
+
assert EarthTools.sunrise_sunset(40.71417, -74.00639, 12, 4).is_a?(EarthTools::Result::SunriseSunset)
|
18
|
+
end
|
19
|
+
|
20
|
+
def test_height_method_returns_result_object
|
21
|
+
assert EarthTools.height(52.4822, -1.8946).is_a?(EarthTools::Result::Height)
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
<?xml version="1.0" encoding="ISO-8859-1" ?>
|
2
|
+
<height xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://www.earthtools.org/height.xsd">
|
3
|
+
<version>1.0</version>
|
4
|
+
<location>
|
5
|
+
<latitude>52.4822</latitude>
|
6
|
+
<longitude>-1.8946</longitude>
|
7
|
+
</location>
|
8
|
+
<meters>141</meters>
|
9
|
+
<feet>462.6</feet>
|
10
|
+
</height>
|
@@ -0,0 +1,30 @@
|
|
1
|
+
<?xml version="1.0" encoding="ISO-8859-1" ?>
|
2
|
+
<sun xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://www.earthtools.org/sun.xsd">
|
3
|
+
<version>1.0</version>
|
4
|
+
<location>
|
5
|
+
<latitude>40.71417</latitude>
|
6
|
+
<longitude>-74.00639</longitude>
|
7
|
+
</location>
|
8
|
+
<date>
|
9
|
+
<day>4</day>
|
10
|
+
<month>12</month>
|
11
|
+
<timezone>-5</timezone>
|
12
|
+
<dst>0</dst>
|
13
|
+
</date>
|
14
|
+
<morning>
|
15
|
+
<sunrise>07:05:50</sunrise>
|
16
|
+
<twilight>
|
17
|
+
<civil>06:35:06</civil>
|
18
|
+
<nautical>06:00:50</nautical>
|
19
|
+
<astronomical>05:27:39</astronomical>
|
20
|
+
</twilight>
|
21
|
+
</morning>
|
22
|
+
<evening>
|
23
|
+
<sunset>16:26:59</sunset>
|
24
|
+
<twilight>
|
25
|
+
<civil>16:57:43</civil>
|
26
|
+
<nautical>17:31:59</nautical>
|
27
|
+
<astronomical>18:05:10</astronomical>
|
28
|
+
</twilight>
|
29
|
+
</evening>
|
30
|
+
</sun>
|
@@ -0,0 +1,14 @@
|
|
1
|
+
<?xml version="1.0" encoding="ISO-8859-1" ?>
|
2
|
+
<timezone xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="http://www.earthtools.org/timezone-1.1.xsd">
|
3
|
+
<version>1.1</version>
|
4
|
+
<location>
|
5
|
+
<latitude>40.71417</latitude>
|
6
|
+
<longitude>-74.00639</longitude>
|
7
|
+
</location>
|
8
|
+
<offset>-5</offset>
|
9
|
+
<suffix>R</suffix>
|
10
|
+
<localtime>14 Jun 2012 13:29:06</localtime>
|
11
|
+
<isotime>2012-06-14 13:29:06 -0500</isotime>
|
12
|
+
<utctime>2012-06-14 18:29:06</utctime>
|
13
|
+
<dst>Unknown</dst>
|
14
|
+
</timezone>
|
data/test/height_test.rb
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'test_helper'
|
4
|
+
require 'earth_tools'
|
5
|
+
require 'earth_tools/result/height'
|
6
|
+
require 'mock_lookup'
|
7
|
+
|
8
|
+
##
|
9
|
+
#
|
10
|
+
#
|
11
|
+
class HeightTest < MiniTest::Unit::TestCase
|
12
|
+
|
13
|
+
def setup
|
14
|
+
@result = EarthTools.height(52.4822, -1.8946)
|
15
|
+
end
|
16
|
+
|
17
|
+
def test_height_is_float
|
18
|
+
assert @result.height.is_a?(Float), 'Height should be a float'
|
19
|
+
end
|
20
|
+
|
21
|
+
# Tests for height configuration in configuration_test.rb
|
22
|
+
|
23
|
+
def test_feet_is_float
|
24
|
+
assert @result.feet.is_a?(Float), 'Feet should be a float'
|
25
|
+
end
|
26
|
+
|
27
|
+
def test_feet_parsed_correctly
|
28
|
+
assert_equal 462.6, @result.feet, 'Feet was not parsed correctly'
|
29
|
+
end
|
30
|
+
|
31
|
+
def test_meters_is_float
|
32
|
+
assert @result.meters.is_a?(Float), 'Meters should be a float'
|
33
|
+
end
|
34
|
+
|
35
|
+
def test_meters_parsed_correctly
|
36
|
+
assert_equal 141, @result.meters, 'Meters was not parsed correctly'
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'minitest/autorun'
|
3
|
+
require 'earth_tools'
|
4
|
+
require 'test_helper'
|
5
|
+
|
6
|
+
class HeightSmokeTest < MiniTest::Unit::TestCase
|
7
|
+
|
8
|
+
def test_height_search
|
9
|
+
result = EarthTools.height(52.4822, -1.8946)
|
10
|
+
|
11
|
+
default_units = EarthTools::Configuration.units
|
12
|
+
begin
|
13
|
+
|
14
|
+
# Default as :english
|
15
|
+
assert_equal 462.6, result.height
|
16
|
+
|
17
|
+
# Set to :metric units
|
18
|
+
EarthTools::Configuration.units = :metric
|
19
|
+
assert_equal 141, result.height
|
20
|
+
|
21
|
+
# Set to :english units
|
22
|
+
EarthTools::Configuration.units = :english
|
23
|
+
assert_equal 462.6, result.height
|
24
|
+
ensure
|
25
|
+
EarthTools::Configuration.units = default_units
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'minitest/autorun'
|
3
|
+
require 'earth_tools'
|
4
|
+
require 'test_helper'
|
5
|
+
|
6
|
+
class SunriseSunsetSmokeTest < MiniTest::Unit::TestCase
|
7
|
+
|
8
|
+
def test_sunrise_sunset_search
|
9
|
+
result = EarthTools.sunrise_sunset(40.71417, -74.00639, 11, 9, 0, 0)
|
10
|
+
|
11
|
+
assert_equal Time.utc(Time.now.year, 11, 9, 11, 37, 32), result.sunrise
|
12
|
+
assert_equal Time.utc(Time.now.year, 11, 9, 21, 41, 12), result.sunset
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'minitest/autorun'
|
3
|
+
require 'earth_tools'
|
4
|
+
require 'test_helper'
|
5
|
+
|
6
|
+
class TimeZoneSmokeTest < MiniTest::Unit::TestCase
|
7
|
+
|
8
|
+
def test_time_zone_search
|
9
|
+
result = EarthTools.time_zone(40.71417, -74.00639)
|
10
|
+
assert_equal -5, result.offset
|
11
|
+
end
|
12
|
+
|
13
|
+
end
|
data/test/mock_lookup.rb
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'earth_tools/lookup/base'
|
2
|
+
class EarthTools::Lookup::Base
|
3
|
+
|
4
|
+
private
|
5
|
+
|
6
|
+
def read_fixture(file)
|
7
|
+
File.read(File.join("test", "fixtures", file)).strip.gsub(/\n\s*/, "")
|
8
|
+
end
|
9
|
+
|
10
|
+
##
|
11
|
+
# Handles running query
|
12
|
+
#
|
13
|
+
def retrieve(query)
|
14
|
+
query = query.split('/')
|
15
|
+
read_fixture "#{ query[3] }_(#{ query[4, query.size-1].join(',') }).xml"
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
@@ -0,0 +1,92 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'test_helper'
|
4
|
+
require 'earth_tools'
|
5
|
+
require 'earth_tools/result/sunrise_sunset'
|
6
|
+
require 'mock_lookup'
|
7
|
+
|
8
|
+
class SunriseSunsetTest < MiniTest::Unit::TestCase
|
9
|
+
|
10
|
+
def setup
|
11
|
+
@result = EarthTools.sunrise_sunset(40.71417, -74.00639, 12, 4)
|
12
|
+
end
|
13
|
+
|
14
|
+
# ---------------------------------------------------------------------------
|
15
|
+
# sunrise
|
16
|
+
# ---------------------------------------------------------------------------
|
17
|
+
|
18
|
+
def test_sunrise_is_time
|
19
|
+
assert @result.sunrise.is_a?(Time), 'Sunrise should be a time'
|
20
|
+
end
|
21
|
+
|
22
|
+
def test_sunrise_parsed_correctly
|
23
|
+
assert_equal Time.new(2012, 12, 4, 7, 5, 50, '-05:00'), @result.sunrise, 'Sunrise was not parsed correctly'
|
24
|
+
end
|
25
|
+
|
26
|
+
# ---------------------------------------------------------------------------
|
27
|
+
# sunset
|
28
|
+
# ---------------------------------------------------------------------------
|
29
|
+
|
30
|
+
def test_sunset_is_time
|
31
|
+
assert @result.sunset.is_a?(Time), 'Sunset should be a time'
|
32
|
+
end
|
33
|
+
|
34
|
+
def test_sunset_parsed_correctly
|
35
|
+
assert_equal Time.new(2012, 12, 4, 16, 26, 59, '-05:00'), @result.sunset, 'Sunset was not parsed correctly'
|
36
|
+
end
|
37
|
+
|
38
|
+
# ---------------------------------------------------------------------------
|
39
|
+
# twilight :time, :type
|
40
|
+
# ---------------------------------------------------------------------------
|
41
|
+
|
42
|
+
def test_twilight_is_time
|
43
|
+
assert @result.twilight(:morning, :astronomical).is_a?(Time), 'Twilight should be a time'
|
44
|
+
assert @result.twilight(:morning, :civil).is_a?(Time), 'Twilight should be a time'
|
45
|
+
assert @result.twilight(:morning, :nautical).is_a?(Time), 'Twilight should be a time'
|
46
|
+
assert @result.twilight(:evening, :astronomical).is_a?(Time), 'Twilight should be a time'
|
47
|
+
assert @result.twilight(:evening, :civil).is_a?(Time), 'Twilight should be a time'
|
48
|
+
assert @result.twilight(:evening, :nautical).is_a?(Time), 'Twilight should be a time'
|
49
|
+
end
|
50
|
+
|
51
|
+
def test_twilight_parsed_correctly
|
52
|
+
assert_equal Time.new(2012, 12, 4, 5, 27, 39, '-05:00'), @result.twilight(:morning, :astronomical), 'Twilight was not parsed correctly'
|
53
|
+
assert_equal Time.new(2012, 12, 4, 6, 35, 6, '-05:00'), @result.twilight(:morning, :civil), 'Twilight was not parsed correctly'
|
54
|
+
assert_equal Time.new(2012, 12, 4, 6, 0, 50, '-05:00'), @result.twilight(:morning, :nautical), 'Twilight was not parsed correctly'
|
55
|
+
assert_equal Time.new(2012, 12, 4, 18, 5, 10, '-05:00'), @result.twilight(:evening, :astronomical), 'Twilight was not parsed correctly'
|
56
|
+
assert_equal Time.new(2012, 12, 4, 16, 57, 43, '-05:00'), @result.twilight(:evening, :civil), 'Twilight was not parsed correctly'
|
57
|
+
assert_equal Time.new(2012, 12, 4, 17, 31, 59, '-05:00'), @result.twilight(:evening, :nautical), 'Twilight was not parsed correctly'
|
58
|
+
end
|
59
|
+
|
60
|
+
# ---------------------------------------------------------------------------
|
61
|
+
# morning_twilight :type
|
62
|
+
# ---------------------------------------------------------------------------
|
63
|
+
|
64
|
+
# ---------------------------------------------------------------------------
|
65
|
+
# evening_twilight :type
|
66
|
+
# ---------------------------------------------------------------------------
|
67
|
+
|
68
|
+
# ---------------------------------------------------------------------------
|
69
|
+
# *_*_twilight
|
70
|
+
# ---------------------------------------------------------------------------
|
71
|
+
|
72
|
+
def test_morning_astronomical_twilight_is_time
|
73
|
+
assert @result.morning_astronomical_twilight.is_a?(Time), 'Morning astronomical twilight should be a time'
|
74
|
+
end
|
75
|
+
|
76
|
+
def test_twilight_parsed_correctly
|
77
|
+
assert_equal Time.new(2012, 12, 4, 5, 27, 39, '-05:00'), @result.morning_astronomical_twilight, 'Twilight was not parsed correctly'
|
78
|
+
end
|
79
|
+
|
80
|
+
# ---------------------------------------------------------------------------
|
81
|
+
# utc_offset
|
82
|
+
# ---------------------------------------------------------------------------
|
83
|
+
|
84
|
+
def test_utc_offset_is_integer
|
85
|
+
assert @result.utc_offset.is_a?(Integer), 'UTC offset should be an integer'
|
86
|
+
end
|
87
|
+
|
88
|
+
def test_utc_offset_parsed_correctly
|
89
|
+
assert_equal -5, @result.utc_offset, 'UTC offset was not parsed correctly'
|
90
|
+
end
|
91
|
+
|
92
|
+
end
|
data/test/test_helper.rb
ADDED
@@ -0,0 +1,58 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
require 'test_helper'
|
4
|
+
require 'earth_tools'
|
5
|
+
require 'earth_tools/result/time_zone'
|
6
|
+
require 'mock_lookup'
|
7
|
+
|
8
|
+
class TimeZoneTest < MiniTest::Unit::TestCase
|
9
|
+
|
10
|
+
def setup
|
11
|
+
@result = EarthTools.time_zone(40.71417, -74.00639)
|
12
|
+
end
|
13
|
+
|
14
|
+
def test_time_zone_method_returns_result_object
|
15
|
+
assert @result.is_a?(EarthTools::Result::TimeZone), 'Result should be a time zone object'
|
16
|
+
end
|
17
|
+
|
18
|
+
def test_iso_time_is_time
|
19
|
+
assert @result.iso_time.is_a?(Time), 'ISO time should be a time object'
|
20
|
+
end
|
21
|
+
|
22
|
+
def test_iso_time_parsed_correctly
|
23
|
+
assert_equal Time.new(2012, 6, 14, 13, 29, 6, '-05:00'), @result.iso_time, 'ISO time was not parsed correctly'
|
24
|
+
end
|
25
|
+
|
26
|
+
def test_local_time_is_time
|
27
|
+
assert @result.local_time.is_a?(Time), 'Local time should be a time object'
|
28
|
+
end
|
29
|
+
|
30
|
+
def test_local_time_parsed_correctly
|
31
|
+
assert_equal Time.new(2012, 6, 14, 13, 29, 6, '-05:00'), @result.local_time, 'Local time was not parsed correctly'
|
32
|
+
end
|
33
|
+
|
34
|
+
def test_suffix_is_string
|
35
|
+
assert @result.suffix.is_a?(String), 'Suffix should be a string'
|
36
|
+
end
|
37
|
+
|
38
|
+
def test_suffix_parsed_correctly
|
39
|
+
assert_equal 'R', @result.suffix, 'Suffix was not parsed correctly'
|
40
|
+
end
|
41
|
+
|
42
|
+
def test_utc_offset_is_integer
|
43
|
+
assert @result.utc_offset.is_a?(Integer), 'UTC offset should be an integer'
|
44
|
+
end
|
45
|
+
|
46
|
+
def test_utc_offset_parsed_correctly
|
47
|
+
assert_equal -5, @result.utc_offset, 'UTC offset was not parsed correctly'
|
48
|
+
end
|
49
|
+
|
50
|
+
def test_utc_time_is_time
|
51
|
+
assert @result.utc_time.is_a?(Time), 'UTC time should be a time object'
|
52
|
+
end
|
53
|
+
|
54
|
+
def test_utc_time_parsed_correctly
|
55
|
+
assert_equal Time.utc(2012, 6, 14, 18, 29, 6), @result.utc_time, 'UTC time was not parsed correctly'
|
56
|
+
end
|
57
|
+
|
58
|
+
end
|
metadata
ADDED
@@ -0,0 +1,93 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: earth_tools
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
prerelease:
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Max Kramer
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2012-08-09 00:00:00.000000000Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: rest-client
|
16
|
+
requirement: &26402964 !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ~>
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: 1.6.1
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: *26402964
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: xml-simple
|
27
|
+
requirement: &26402628 !ruby/object:Gem::Requirement
|
28
|
+
none: false
|
29
|
+
requirements:
|
30
|
+
- - ~>
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: 1.1.1
|
33
|
+
type: :runtime
|
34
|
+
prerelease: false
|
35
|
+
version_requirements: *26402628
|
36
|
+
description: Client library to query the earthtools.org web services
|
37
|
+
email: max@maxkramer.me
|
38
|
+
executables: []
|
39
|
+
extensions: []
|
40
|
+
extra_rdoc_files: []
|
41
|
+
files:
|
42
|
+
- lib/earth_tools/configuration.rb
|
43
|
+
- lib/earth_tools/exceptions.rb
|
44
|
+
- lib/earth_tools/lookup/base.rb
|
45
|
+
- lib/earth_tools/lookup/height.rb
|
46
|
+
- lib/earth_tools/lookup/sunrise_sunset.rb
|
47
|
+
- lib/earth_tools/lookup/time_zone.rb
|
48
|
+
- lib/earth_tools/result/base.rb
|
49
|
+
- lib/earth_tools/result/height.rb
|
50
|
+
- lib/earth_tools/result/sunrise_sunset.rb
|
51
|
+
- lib/earth_tools/result/time_zone.rb
|
52
|
+
- lib/earth_tools/version.rb
|
53
|
+
- lib/earth_tools.rb
|
54
|
+
- test/configuration_test.rb
|
55
|
+
- test/earth_tools_test.rb
|
56
|
+
- test/fixtures/height_(52.4822,-1.8946).xml
|
57
|
+
- test/fixtures/sun_(40.71417,-74.00639,4,12,99,0).xml
|
58
|
+
- test/fixtures/timezone_(40.71417,-74.00639).xml
|
59
|
+
- test/height_test.rb
|
60
|
+
- test/integration/height_smoke_test.rb
|
61
|
+
- test/integration/sunrise_sunset_smoke_test.rb
|
62
|
+
- test/integration/time_zone_smoke_test.rb
|
63
|
+
- test/mock_lookup.rb
|
64
|
+
- test/sunrise_sunset_test.rb
|
65
|
+
- test/test_helper.rb
|
66
|
+
- test/time_zone_test.rb
|
67
|
+
homepage: http://github.com/mckramer/earth_tools
|
68
|
+
licenses:
|
69
|
+
- MIT
|
70
|
+
post_install_message:
|
71
|
+
rdoc_options: []
|
72
|
+
require_paths:
|
73
|
+
- lib
|
74
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
75
|
+
none: false
|
76
|
+
requirements:
|
77
|
+
- - ! '>='
|
78
|
+
- !ruby/object:Gem::Version
|
79
|
+
version: '0'
|
80
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
81
|
+
none: false
|
82
|
+
requirements:
|
83
|
+
- - ! '>='
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: '0'
|
86
|
+
requirements: []
|
87
|
+
rubyforge_project:
|
88
|
+
rubygems_version: 1.7.2
|
89
|
+
signing_key:
|
90
|
+
specification_version: 3
|
91
|
+
summary: Client library to query the earthtools.org web services
|
92
|
+
test_files: []
|
93
|
+
has_rdoc:
|