module Memoize
MEMOIZE_VERSION = "1.2.0"
Set a constant to the module version, so user code can check it as needed.
# Memoize the method +name+. If +file+ is provided, then the method results
# are stored on disk rather than in memory. This consumes virtually no
# memory and is persistant.
def memoize(name, file=nil)
meth = method(name)
Grab a reference to the original method.
if file
cache = Hash.new.update(Marshal.load(File.read(file))) rescue {}
else
cache = {}
end
Load an existing cache file, if requested and one exists. Otherwise, set the cache to an empty Hash.
if file
(class << self; self; end).class_eval do
define_method(name) do |*args|
unless cache.has_key?(args)
cache[args] = meth.call(*args)
File.open(file, "wb+"){|f| Marshal.dump(cache, f) }
end
cache[args]
end
end
This is the singleton class trick James Britt described. It this version, the cache is checked for an entry with all the arguments it was just called with. If it's not found, the original method is triggered to add that entry to the cache. The file is also modified to contain the new entry. Either way, the cache now has the needed entry, which is returned.
else
(class << self; self; end).class_eval do
define_method(name) do |*args|
if cache.has_key?(args)
cache[args]
else
cache[args] ||= meth.call(*args)
end
end
end
end
Exact same thing, minus the file dump. In fact, that whole if/else/end chunk of code could be simplified to:
(class << self; self; end).class_eval do
define_method(name) do |*args|
unless cache.has_key?(args)
cache[args] = meth.call(*args)
File.open(file, "wb+"){|f| Marshal.dump(cache, f) } if file
end
cache[args]
end
end
cache
Return the cache we will use for user code to examine/modify, if desired.
end
Hope that helps.
James Edward Gray II
···
On Jan 27, 2006, at 11:04 PM, Alex Combas wrote: