From: Daniel Schierbeck Date: 2005-12-09T05:17:36+09:00 Subject: Re: Transparent Caching Idiom beng wrote: > I've made good use of this idiom recently, and wanted to share it. > > Once this code is active, any method named with a "_c" suffix is > automatically cached. The method is assumed to follow a simple > contract: It performs no side-effects / mutations, and it's arguments > properly implement "Object.hash". > > This is specifically useful for expensive but functional calculations. > Enjoy! > > --Ben (b@gimpert.com) > > # > class Class > > alias old_new new > def new(*args, &block) > Class.defc_wrap(old_new(*args, &block)) > end > > def Class.defc_wrap(obj) > klass = obj.class > defc_methods = obj.methods.select { |n| n =~ /_c$/ } > defc_methods.each do |name| > meth = obj.method(name) > wrapped_name = Class.defc_next_name(klass) > 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 > obj > end > > def Class.defc_next_name(obj) > klass = obj.class > i = 1 > i += 1 while obj.respond_to?("_defc_#{i}") || > obj.instance_variables.member?("@_defc_#{i}") > "_defc_#{i}" > end > > end > > Neat. Though it would be cool if the methods that were to be cached were chosen through a class method rather than a method name suffix. class Klass def foo; end def bar; end cached_method :foo, :bar end Cheers, Daniel