1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118
|
module ReturnSpecs
class Blocks
def yielding_method
yield
ScratchPad.record :after_yield
end
def enclosing_method
yielding_method do
ScratchPad.record :before_return
return :return_value
ScratchPad.record :after_return
end
ScratchPad.record :after_call
end
end
class NestedCalls < Blocks
def invoking_method(&b)
yielding_method(&b)
ScratchPad.record :after_invoke
end
def enclosing_method
invoking_method do
ScratchPad.record :before_return
return :return_value
ScratchPad.record :after_return
end
ScratchPad.record :after_invoke
end
end
class NestedBlocks < Blocks
def enclosing_method
yielding_method do
yielding_method do
ScratchPad.record :before_return
return :return_value
ScratchPad.record :after_return
end
ScratchPad.record :after_invoke1
end
ScratchPad.record :after_invoke2
end
end
class SavedInnerBlock
def add(&b)
@block = b
end
def outer
yield
@block.call
end
def inner
yield
end
def start
outer do
inner do
add do
ScratchPad.record :before_return
return :return_value
end
end
end
ScratchPad.record :bottom_of_start
return false
end
end
class ThroughDefineMethod
lamb = proc { |x| x.call }
define_method :foo, lamb
def mp(&b); b; end
def outer
pr = mp { return :good }
foo(pr)
return :bad
end
end
class DefineMethod
lamb = proc { return :good }
define_method :foo, lamb
def outer
val = :bad
# This is tricky, but works. If lamb properly returns, then the
# return value will go into val before we run the ensure.
#
# If lamb's return keeps unwinding incorrectly, val will still
# have it's old value.
#
# We can therefore use val to figure out what happened.
begin
val = foo()
ensure
if val != :good
return :bad
end
end
return val
end
end
end
|