2

I've been scratching my head over how to add behaviour to a specific instance of a class in Ruby. If I use instance_exec like below however the method that calls the proc does not execute all of the way through.

class HasSecret
    def initialize(x)
        @secret = x
    end

    def doTheThing(&block)
        puts "before block"
        instance_exec(@secret, &block)
        puts "after block"
    end
end

foo = HasSecret.new(5)
foo.doTheThing do |x|
        puts "x"
        return x
end

This example simply gives:

before block

5

Is there any perscribed approach to doing this?

Community
  • 1
  • 1

1 Answers1

1

Try this:

foo.doTheThing do |x|
  puts x
end

Generally, you are not supposed to return in blocks. Calling return in a block will cause the method yielding (enclosing) to return, which is usually not the behaviour desired. It can also case a LocalJumpError.

In fact, because this scenario is so nuanced and uncommon, a lot of people say you can't return from a block. Check out the conversation in the comments of the answer on this question, for example: Unexpected Return (LocalJumpError)

In your case, you aren't seeing the "after block" puts because the return in the passed block is causing doTheThing to return before getting there.

Xavier
  • 3,423
  • 23
  • 36
  • Thanks for pointing me to the other thread. I'll see if I can use lambdas instead. – Ryan McCoskrie Jan 26 '18 at 08:32
  • "Calling return in a block will cause the method yielding (enclosing) to return" -- no, it will cause the method that created the block to return. – ComDubh May 21 '20 at 22:49