From: James Edward Gray II Date: 2006-01-29T01:28:28+09:00 Subject: Re: Memoization? On Jan 27, 2006, at 11:04 PM, Alex Combas wrote: > 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