Transparent caching in Ruby
Found the following code in the ruby-talk archives. It allows to cache what a method returns.
class Class
alias_method :__new__, :new
def cached_method(*methods)
@cached_methods ||= []
@cached_methods += methods
@cached_methods.uniq!
end
def new(*args, &block)
obj = __new__(*args, &block)
klass = obj.class
@cached_methods ||= []
@cached_methods.each do |name|
meth = obj.method(name)
i = 1
while klass.instance_variables.member?("@_defc_#{i}")
i += 1
end
wrapped_name = "_defc_#{i}"
cache = klass.class_eval("@#{wrapped_name} = {}")
wrapper = Proc.new do |*args_a|
arg_hash = args_a.hash
if cache.has_key?(arg_hash)
cache[arg_hash]
else
cache[arg_hash] = meth.call(*args_a)
end
end
klass.send(:alias_method, wrapped_name, name)
klass.send(:define_method, name, wrapper)
end
return obj
end
end
if __FILE__ == $0
class Klass
def foo; end
def bar; end
cached_method :foo, :bar
end
end