Skip to content
Browse files

Add cache.

  • Loading branch information...
1 parent 769156b commit f329d98f667332e479871ef105f7efe13ddece4f @mckramer committed Nov 3, 2012
View
26 README.md
@@ -78,40 +78,36 @@ Earth Tools imposes some [usage restrictions](http://www.earthtools.org/webservi
2. You *must* cache results if you believe that you will need to make another identical request within any 24-hour period.
3. You *must* delete any cached data when you no longer need it and in any case after 14 days. You should then make a new request for the data in line with the previous two rules. If you wish to keep access to data I am able to license the data for use in this way.
-### Caching (*TBD update this section*)
+### Caching (*Future feature*)
It is recommended to cache retrieved data when relying on an external service. You can configure a cache store:
EarthTools::Configuration.cache = Redis.new
+ EarthTools::Configuration.cache_prefix = "..." # Provide a custom cache prefix, defaults to 'earth_tools:'
The cache store can be any object that supports the following methods:
<table>
<tr>
- <td>`store#[](key)`</td><td>retrieves a value</td>
+ <th>Method</th><th>Description</th><th>Examples</th>
</tr>
<tr>
- <td>`store#[]=(key, value)`</td><td>stores a value</td>
+ <td><code>store#[](key)</code></td><td>Retrieves a value by with the key</td><td></td>
</tr>
<tr>
- <td>`store#keys`</td><td>lists all keys</td>
+ <td><code>store#[]=(key, value)</code></td><td>Stores a value with the key</td><td></td>
+ </tr>
+ <tr>
+ <td><code>store#keys</code></td><td>Retrieves all keys</td><td></td>
</tr>
</table>
-Even a plain Ruby hash will work, though it's not a great choice (cleared out when app is restarted, not shared between app instances, etc).
-
-You can also set a custom prefix to be used for cache keys:
-
- EarthTools::Configuration.cache_prefix = "..."
-
-By default the prefix is `earth_tools:`
-
If you need to expire cached content:
- EarthTools.cache.expire("http://...") # expire cached result for a URL
- EarthTools.cache.expire(:all) # expire all cached results
+ EarthTools.cache.expire("http://...") # Expire cached result for a URL
+ EarthTools.cache.expire(:all) # Expire all cached results
-Do *not* include the prefix when passing a URL to be expired. Expiring `:all` will only expire keys with the configured prefix (won't kill every entry in your key/value store).
+There is no need to include the prefix when passing a URL to be expired. Expiring `:all` will only expire keys with the configured prefix (won't kill every entry in your key/value store).
## Error handling
View
2 Rakefile
@@ -5,7 +5,7 @@ Bundler::GemHelper.install_tasks
require 'rake/testtask'
-desc 'Default: run unit test'
+desc 'Default: run unit tests'
task :default => :test
desc 'Run all tests'
View
17 earth_tools.gemspec
@@ -6,13 +6,22 @@ Gem::Specification.new do |gem|
gem.version = EarthTools::VERSION
gem.author = "Max Kramer"
- gem.email = %q{max@maxkramer.me}
+ gem.email = %q{max@maxckramer.com}
gem.homepage = %q{http://github.com/mckramer/earth_tools}
- gem.summary = %q{Client library to query the earthtools.org web services}
- gem.description = %q{Client library to query the earthtools.org web services}
+ gem.summary = %q{Client library to query the earthtools.org web services.}
+ gem.description = <<-EOF
+
+ The earth_tools gem is a client library to query the earthtools.org web services.
+ Available features include determining time zone, sunset/sunrise times, and height
+ above sea level for a given longitute/latitude pair. See the README for more
+ information. Also, please follow the web service restrictions for use described
+ in the README.
+
+ EOF
+
gem.license = "MIT"
- gem.files = FileList['lib/**/*.rb', 'test/**/*'].to_a
+ gem.files = FileList['README.md', 'CHANGELOG.md', 'Gemfile', 'Rakefile', 'lib/**/*.rb', 'test/**/*'].to_a
gem.add_runtime_dependency "rest-client", "~> 1.6.1"
gem.add_runtime_dependency "xml-simple", "~> 1.1.1"
View
81 lib/earth_tools/cache.rb
@@ -0,0 +1,81 @@
+module EarthTools
+
+ ##
+ # The Earth Tools cache wrapper.
+ #
+ # Must respond to:
+ # -> [] -- read
+ # -> []= -- write
+ # -> del -- delete
+ # -> keys -- list of keys
+ #
+ class Cache
+
+ ##
+ # Constructor.
+ def initialize(store, prefix)
+ @store = store
+ @prefix = prefix
+ end
+
+ ##
+ # Read from the cache.
+ # @return the object saved in the cache
+ def [](url)
+ store[key_for(url)]
+ end
+
+ ##
+ # Write to the cache.
+ def []=(url, value)
+ store[key_for(url)] = value
+ end
+
+ ##
+ # Delete cache entry for given URL,
+ # or pass <tt>:all</tt> to clear all URLs.
+ def expire(url)
+ if url == :all
+ urls.each{ |u| expire(u) }
+ else
+ store.del(key_for(url))
+ end
+ end
+
+
+ private
+
+ attr_reader :prefix, :store
+
+ ##
+ # Cache key for a given URL.
+ # @return [String] the cache key
+ def key_for(url)
+ [prefix, url].join
+ end
+
+ ##
+ # Array of keys with the currently configured prefix
+ # that have non-nil values.
+ # @return [Array] the list of keys
+ def keys
+ store.keys.select{ |k| k.match /^#{prefix}/ and cleave(store[k]) }
+ end
+
+ ##
+ # Array of cached URLs.
+ # @return [Array] the list of cached URLs
+ def urls
+ keys.map{ |k| k[/^#{prefix}(.*)/, 1] }
+ end
+
+ ##
+ # Convert empty string to nil.
+ # (Some key/value stores return empty string instead of nil.)
+ # @return [Object, nil] the object or nil
+ def cleave(value)
+ value == "" ? nil : value
+ end
+
+ end
+end
View
75 lib/earth_tools/lookup/base.rb
@@ -6,18 +6,27 @@ module EarthTools
module Lookup
##
- #
+ # Base lookup object.
#
class Base
##
# Query the Earth Tools service and return a EarthTools::Result object.
- # @return [EarthTools::Result, nil]
+ # @return [EarthTools::Result, nil] the results object
def search(*options)
begin
Timeout::timeout(EarthTools::Configuration.timeout) do
- raw_results = retrieve(query(options))
- parse_results(raw_results, :xml)
+ uri = query(options)
+ if cache && results = cache[uri]
+ # Boom, cached
+ else
+ # Not cached, so go get the data
+ raw_results = retrieve(uri)
+ results = parse_xml(raw_results)
+ # Save results to cache, if available
+ cache(uri, results) if cache && results
+ end
+ results
end
rescue Timeout::Error => err
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)."
@@ -27,75 +36,67 @@ def search(*options)
private
##
- # The base URL for the web service endpoint (protocol and server)
+ # The base URL for the web service endpoint (protocol and server).
# @return [String] the base URL
def base_service_url
"http://www.earthtools.org"
end
+
+ ##
+ # Gets the cache.
+ # @return [EarthTools::Cache] the cache
+ def cache
+ EarthTools::Configuration.cache
+ end
##
# URL to use for querying the geocoding engine.
- # @return [String]
+ # @return [String] the url
def query(*options)
base_service_url + query_base + options.join('/')
+ # ([base_service_url, query_base] + options).join('/')
end
##
- # Parse results depending on if xml or json
- #
- def parse_results(raw_results, type)
- case type
- when :xml
- parse_xml(XmlSimple.xml_in( raw_results, { 'ForceArray' => false } ))
- when :json
- raise UnsupportedOperationError, "JSON is not supported"
- end
- end
-
- ##
- # Handle XML results by validating them
- #
- def parse_xml(xml)
+ # Handle XML results by validating them.
+ # @param raw_xml the xml to parse
+ # @return [Height, SunriseSunset, TimeZone] the result
+ def parse_xml(raw_xml)
+ xml = XmlSimple.xml_in( raw_xml, { 'ForceArray' => false } )
if xml['location']
result_class.new(xml)
else
warn "Invalid request."
- puts xml
end
end
##
- # Handles running query
- #
+ # Handles running query.
+ # @return [xml] the results
def retrieve(query)
RestClient.proxy = EarthTools::Configuration.proxy if EarthTools::Configuration.proxy
- #puts "Trying to connect to endpoint(#{query})"
- #puts "Using proxy (#{RestClient.proxy})" if RestClient.proxy
RestClient.get query
end
##
# Raise exception if configuration specifies it should be raised.
- # Return false if exception not raised.
- #
+ # @return [boolean] false, if exception not raised
def raise_error(error, message = nil)
- if EarthTools::Configuration.always_raise.include?( error.is_a?(Class) ? error : error.class )
- raise error, message
- else
- false
- end
+ raise error, message if EarthTools::Configuration.always_raise.include?( error.is_a?(Class) ? error : error.class )
+ false
end
##
- #
- #
+ # The base of the query for the function.
+ # @return [String] the base of the query
+ # @throws NotImplementedError when child class does not implement method
def query_base
raise NotImplementedError
end
##
- #
- #
+ # The class for the result.
+ # @return [EarthTools::Result::Height, EarthTools::Result::SunriseSunset, EarthTools::Result::TimeZone] the result class
def result_class
EarthTools::Result.const_get(self.class.to_s.split(":").last)
end
View
12 lib/earth_tools/lookup/time_zone.rb
@@ -2,8 +2,18 @@
require 'earth_tools/result/time_zone'
module EarthTools::Lookup
+
+ ##
+ # The Time Zone lookup.
+ #
class TimeZone < Base
-
+
+ #class << self
+ # def function
+ # @function ||= 'timezone'
+ # end
+ #end
+
private
def query_base
View
10 lib/earth_tools/result/base.rb
@@ -9,37 +9,37 @@ class Base
##
# Takes a hash of result data from a parsed Google result document.
- #
+ # @param [Object] the
def initialize(data)
@data = data
end
##
# Get the geographical location
- # @returns [Array] a two-element array: [latitude, longitude]
+ # @return [Array] a two-element array: [latitude, longitude]
def location
[latitude, longitude]
end
##
# Get the latitude
# See {http://en.wikipedia.org/wiki/Latitude}.
- # @returns [Float] the latitude
+ # @return [Float] the latitude
def latitude
@data['latitude'].to_f
end
##
# Get the longitude
# See {http://en.wikipedia.org/wiki/Longitude}.
- # @returns the longitude
+ # @return the longitude
def longitude
@data['longitude'].to_f
end
##
# The version of the response format
- # @returns [Float] the version
+ # @return [Float] the version
def version
@data['version'].to_f
end
View
2 lib/earth_tools/result/sunrise_sunset.rb
@@ -3,7 +3,7 @@
module EarthTools::Result
##
- # The sunrise/sunset result object
+ # The sunrise/sunset result.
#
class SunriseSunset < Base
View
3 lib/earth_tools/result/time_zone.rb
@@ -3,8 +3,9 @@
module EarthTools::Result
##
+ # The Time Zone result.
#
- #
+ # @see http://www.earthtools.org/webservices.htm#timezone
class TimeZone < Base
##
View
2 lib/earth_tools/version.rb
@@ -1,4 +1,4 @@
module EarthTools
# The gem version
- VERSION = "0.0.1"
+ VERSION = "0.1.0"
end

0 comments on commit f329d98

Please sign in to comment.
Something went wrong with that request. Please try again.