class FileCache

A file-based caching library. It uses Marshal::dump and Marshal::load to serialize/deserialize cache values - so you should be OK to cache object values.

Constants

MAX_DEPTH

Public Class Methods

new(domain = "default", root_dir = "/tmp", expiry = 0, depth = 2) click to toggle source

Create a new reference to a file cache system.

domain

A string that uniquely identifies this caching system on the given host

root_dir

The root directory of the cache file hierarchy The cache will be rooted at root_dir/domain/

expiry

The expiry time for cache entries, in seconds. Use 0 if you want cached values never to expire.

depth

The depth of the file tree storing the cache. Should be large enough that no cache directory has more than a couple of hundred objects in it

# File lib/filecache.rb, line 21
def initialize(domain = "default", root_dir = "/tmp", expiry = 0, depth = 2)
  @domain  = domain
  @root_dir = root_dir
  @expiry  = expiry
  @depth   = depth > MAX_DEPTH ? MAX_DEPTH : depth
  FileUtils.mkdir_p(get_root)
end

Public Instance Methods

clear() click to toggle source

Delete ALL data from the cache, regardless of expiry time

# File lib/filecache.rb, line 74
def clear
  if File.exists?(get_root)
    FileUtils.rm_r(get_root)
    FileUtils.mkdir_p(get_root)
  end
end
delete(key) click to toggle source

Delete the value for the given key from the cache

# File lib/filecache.rb, line 69
def delete(key)
  FileUtils.rm(get_path(key))
end
get(key) click to toggle source

Return the value for the specified key from the cache. Returns nil if the value isn’t found.

# File lib/filecache.rb, line 39
def get(key)
  path = get_path(key)

  # expire
  if @expiry > 0 && File.exists?(path) && Time.new - File.new(path).mtime >= @expiry
    FileUtils.rm(path)
  end
  
  if File.exists?(path)
    f = File.open(path, "r")
    result = Marshal.load(f)
    f.close
    return result
  else
    return nil
  end
end
get_or_set(key) { || ... } click to toggle source

Return the value for the specified key from the cache if the key exists in the cache, otherwise set the value returned by the block. Returns the value if found or the value from calling the block that was set.

# File lib/filecache.rb, line 60
def get_or_set(key)
  value = get(key)
  return value if value
  value = yield
  set(key, value)
  value
end
purge() click to toggle source

Delete all expired data from the cache

# File lib/filecache.rb, line 82
def purge
  @t_purge = Time.new
  purge_dir(get_root) if @expiry > 0
end
set(key, value) click to toggle source

Set a cache value for the given key. If the cache contains an existing value for the key it will be overwritten.

# File lib/filecache.rb, line 31
def set(key, value)
  f = File.open(get_path(key), "w")
  Marshal.dump(value, f)
  f.close
end

Private Instance Methods

get_path(key) click to toggle source
# File lib/filecache.rb, line 89
def get_path(key)
  md5 = Digest::MD5.hexdigest(key.to_s).to_s
  
  dir = File.join(get_root, md5.split(//)[0..@depth - 1])
  FileUtils.mkdir_p(dir)
  return File.join(dir, md5)
end
get_root() click to toggle source
# File lib/filecache.rb, line 97
def get_root
  if @root == nil
    @root = File.join(@root_dir, @domain)
  end
  return @root
end
purge_dir(dir) click to toggle source
# File lib/filecache.rb, line 104
def purge_dir(dir)
  Dir.foreach(dir) do |f|
    next if f =~ /^\.\.?$/
    path = File.join(dir, f)
    if File.directory?(path) 
      purge_dir(path)
    elsif @t_purge - File.new(path).mtime >= @expiry
      # Ignore files starting with . - we didn't create those
      next if f =~ /^\./
      FileUtils.rm(path)
    end
  end
  
  # Delete empty directories
  if Dir.entries(dir).delete_if{|e| e =~ /^\.\.?$/}.empty?
    Dir.delete(dir)
  end
end