This thread caused me to do some experimenting and I came across some
Proc semantics that I hadn't seen discussed before and that might
be useful in a DSL context. Consider:

class A
   Foo = define_method(:foo) { |x|
     p "self: #{self}"
     return 'positive' if x > 0
     'negative'
   }
end

p A::Foo                   # #<Proc:0x00026520 / proc.question:6>
p A::Foo.call(0)           # "self: A" "negative"
p A::Foo.call(1)           # "self: A" "positive"
p A.new.foo(0)             # "self: #<A:0x25ecc>" "negative"
p A.new.foo(1)             # "self: #<A:0x25e2c>" "positive"

I was unaware that define_method returned a proc.  I was even more
surprised that it appears to be of the lambda "flavor".  That is to
say that a 'return' within the block is relative to the block and not
to the scope where the block is defined.

Previously I thought that only Kernel#proc and Kernel#lambda had
the 'magic' property of altering the return semantics of a block.
I understand why this is also necessary for define_method to be
useful, I was just not aware that the resulting proc was accessible
as the return value of define_method.

I was going to ask if there was any way to write a method like
'define_method' that forces any provided blocks to be interpreted
as lambda vs. 'regular' procs.  Then I did some more experimenting:

a = Proc.new { return 42 }
a.call		# LocalJumpError

b = lambda &a
a.call		# 42

This was another surprise for me as I figured that when lambda was
used, the first proc would be 'wrapped' in a new proc with
lambda semantics, something like:

c = lambda { a.call }

But that isn't the case.  If you try 'c.call' you'll get the
LocalJumpError again.

I hadn't see this type of transformation before.  It might be
useful in some DSL situations:

   class A
     filter {|x| x.to_s }  	# ok
     filter {|x| return x.to_s } # potential LocalJumpError
   end

If you wrote filter as:

   def A.filter(&b)
     lambda(&b).call(42)
   end

you can avoid the LocalJumpError.


Gary Wright