require 'monitor' class Module def cache_method *methods DeclarativeCache.cache_method self, *methods end def cache_method_with_params *methods DeclarativeCache.cache_method_with_params self, *methods end end class Object def clear_cache_method instance_variables.each do |iv| remove_instance_variable iv if iv =~ /^@cached_/ end end end module DeclarativeCache DISABLED = false warn "CASHE DISABLED" if DISABLED unless DISABLED class << self def cache_method klass, *methods methods.each do |method| klass.class_eval do als = "cached_#{escape_method(method)}" iv_check = "@#{als}_check" iv = "@#{als}" raise "Can't cache the #{method} twice!" if instance_methods.include?(als) alias_method als, method define_method method do |*args| raise "You tried to use cache without params for method with params (use 'cache_method_with_params' instead)!" unless args.empty? unless cached = instance_variable_get(iv) unless check = instance_variable_get(iv_check) cached = send als instance_variable_set iv, cached instance_variable_set iv_check, true end end cached end end end end def cache_method_with_params klass, *methods methods.each do |method| klass.class_eval do als = "cached_#{escape_method(method)}" iv = "@#{als}" raise "Can't cache the '#{method}' twice!" if instance_methods.include?(als) alias_method als, method define_method method do |*args| unless results = instance_variable_get(iv) results = Hash.new(NotDefined) instance_variable_set iv, results end result = results[args] if result.equal? NotDefined result = send als, *args results[args] = result end result end end end end end end end