Search code examples
rubydynamicblock

How to dynamically wrap code inside a block in Ruby?


Suppose a certain part of code needs to be run inside a different block/context, depending on a configuration option. For example,

if silence
  silence_stdout do
    # do something
  end
else
  # do the same thing
end

Is there a way to write this without repeating the # do something code?


Solution

  • Depending on how much code "do something" is you could throw it in a lambda:

    something = -> { do_something }
    if silence
      silence_stdout &something
    else
      something.call
    end
    

    or throw it in a method:

    def something
      # Do something, lots and lots of something.
    end
    
    if silence
        silence_stdout &method(:something)
    else
        something
    end
    

    You could also turn the logic inside out a bit:

    def no_op
      yield
    end
    def silence_stdout
      # Do whatever and then...
      yield
    end
    
    m = method(silence ? :no_op : :silence_stdout)
    m.call do
      # Do something
    end
    

    Or you could use whole classes or just lambdas instead of methods in that last one.