Comparing Proc Objects?


#1

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


#2

On 11/14/05, Daniel S. removed_email_address@domain.invalid wrote:

What I’m interested in
knowing is how I check whether any supplied block matches the one from
the cached call.

I think the only way you’re going to get equality with a supplied
block is if it is an object, i.e. created with proc or Proc.new or by
passing through another method. Every other form is generated on the
fly AFAIK.

Regards,

Sean

P.S. This is what I used to test this:

require ‘pp’

@blocks = Hash.new(0)

def count_block(&block)
@blocks[block] += 1
end

def make_block(&block)
block
end

def test_method(x)
x + 1
end

block = proc {|x| x + 1}
block2 = Proc.new do |x| x + 1 end

count_block &block
count_block &block
count_block &block2
count_block &block2
count_block do |x| x + 1 end
count_block do |x| x + 1 end
count_block { |x| x + 1 }
count_block { |x| x + 1 }
count_block &make_block { |x| x + 1 }

count_block &method(:test_method)
count_block &method(:test_method)
meth = method(:test_method)
count_block &meth
count_block &meth

meth2 = Proc.new &method(:test_method)
count_block &meth2
count_block &meth2

pp @blocks
END
---------- OUTPUT ----------
{#Proc:0x02db4de8@C:/rubylib/experiments/ruby-talk/compare-blocks.rb:33=>1,
#Proc:0x028710f8@C:/rubylib/experiments/ruby-talk/compare-blocks.rb:20=>2,
#Proc:0x02871278@C:/rubylib/experiments/ruby-talk/compare-blocks.rb:19=>2,
#Proc:0x02db4d28@C:/rubylib/experiments/ruby-talk/compare-blocks.rb:38=>2,
#Proc:0x02db4e30@C:/rubylib/experiments/ruby-talk/compare-blocks.rb:32=>1,
#Proc:0x028708a0@C:/rubylib/experiments/ruby-talk/compare-blocks.rb:30=>1,
#Proc:0x02db4d70@C:/rubylib/experiments/ruby-talk/compare-blocks.rb:36=>1,
#Proc:0x028709d8@C:/rubylib/experiments/ruby-talk/compare-blocks.rb:29=>1,
#Proc:0x02870b10@C:/rubylib/experiments/ruby-talk/compare-blocks.rb:28=>1,
#Proc:0x02db4da0@C:/rubylib/experiments/ruby-talk/compare-blocks.rb:35=>1,
#Proc:0x02870c48@C:/rubylib/experiments/ruby-talk/compare-blocks.rb:27=>1,
#Proc:0x02870d80@C:/rubylib/experiments/ruby-talk/compare-blocks.rb:26=>1}