Just for the laugh of it (I've got the flu) I wrote a little Cache Proxy class. Basically, when you call a method on the proxyed object it checks if that method has been called with the same arguments before. If that's the case, it returns the cached return value. What I'm interested in knowing is how I check whether any supplied block matches the one from the cached call.
This is my code:
class EmptyClass
instance_methods(true).each do |method|
undef_method(method) unless ["__send__", "__id__"].include? method
end
end
class Proxy < EmptyClass
def initialize(obj)
@obj = obj
end
def method_missing(name, *args, &block)
@obj.send(name, *args, &block)
end
end
class CacheProxy < Proxy
def initialize(obj)
@calls = []
@obj = obj
end
def method_missing(name, *args, &block)
call = MethodCall.new(name, *args, &block)
if @calls.include? call
return @calls.detect do |cached_call|
cached_call == call
end.return_value
else
call.return_value = return_value = super
@calls << call
return return_value
end
end
class MethodCall
include Comparable
attr_reader :name, :args, :block
attr_accessor :return_value
def initialize(name, *args, &block)
@name, @args, @block = name, args, block
end
def <=> (other)
self.name <=> other.name
end
def == (other)
self.name == other.name and self.args == other.args
end
end
end
I bet this has already been done, and probably in a more efficient way, but hey, I'm bored...
Cheers,
Daniel