# $Id: cache.rb,v 1.4 2004/04/01 09:44:31 ianmacd Exp $
require 'fileutils'
require 'md5'
module Amazon
module Search
# This class is used internally by Ruby/Amazon. You should never need
# to manually instantiate it or invoke most of the methods here. The only
# exceptions are #flush_all and #flush_expired.
#
class Cache
# Exception class for bad cache paths.
#
class PathError < StandardError; end
# Length of one day in seconds
#
ONE_DAY = 86400 # :nodoc:
# Age in days below which to consider cache files valid.
#
MAX_AGE = 1.0
def initialize(path)
::FileUtils::mkdir_p(path) unless File.exists?(path)
unless File.directory?(path)
raise PathError, "cache path #{path} is not a directory"
end
unless File.readable?(path)
raise PathError, "cache path #{path} is not readable"
end
unless File.writable?(path)
raise PathError, "cache path #{path} is not writable"
end
@path = path
end
# Determine whether or not the the response to a given URL is cached.
# Returns +true+ or +false+.
#
def cached?(url)
digest = Digest::MD5.hexdigest(url)
cache_files = Dir.glob(File.join(@path, '*')).map do |d|
File.basename(d)
end
return cache_files.include?(digest) &&
(Time.now - File.mtime(File.join(@path, digest))) / ONE_DAY <= MAX_AGE
end
# Retrieve the cached response associated with _url_.
#
def get_cached(url)
digest = Digest::MD5.hexdigest(url)
cache_file = File.join(@path, digest)
return nil unless File.exist? cache_file
Amazon::dprintf("Fetching %s from cache...\n", digest)
File.open(File.join(cache_file)).readlines.to_s
end
# Cache the data from _contents_ and associate it with _url_.
#
def cache(url, contents)
digest = Digest::MD5.hexdigest(url)
cache_file = File.join(@path, digest)
Amazon::dprintf("Caching %s...\n", digest)
File.open(cache_file, 'w') { |f| f.puts contents }
end
# This method flushes all files from the cache directory specified
# in the object's @path variable.
#
def flush_all
FileUtils.rm Dir.glob(File.join(@path, '*'))
end
# This method flushes expired files from the cache directory specified
# in the object's @path variable.
#
def flush_expired
expired_files = Dir.glob(File.join(@path, '*')).find_all do |f|
(now - File.mtime(f)) / ONE_DAY > MAX_AGE
end
FileUtils.rm expired_files
end
end
end
end