Search code examples
rubyerbyield

Ruby erb templates with yield


I can't understand why this code works fine

def func
  ERB.new('<%= yield %>').result(binding)
end
func { 123 } # => it prints 123 as expected

but this one doesn't work and raises an exception

ERB.new('<%= yield %>').result(binding) { 123 } # => LocalJumpError: no block given (yield)

Any thoughts?


Solution

  • This problem is independent of ERB and is because of the way yield works. Yield expects to be called within the message body and expects a block to yield it. Let's take this example

    # This is equivalent to 
    # def func
    # ERB.new('<%= yield %>').result(binding)
    # end
    
    def test_print
      yield
    end
    

    If we call the method without a block

    irb(main):038:0> test_print
    LocalJumpError: no block given (yield)
        from (irb):36:in `test_print'
        from (irb):38
        from /Users/agupta/.rvm/rubies/ruby-2.4.0/bin/irb:11:in `<main>'
    irb(main):039:0>
    

    If we call the method with block

    irb(main):039:0> test_print { "hello world" }
    => "hello world"
    irb(main):040:0>
    

    In the latter case

    ERB.new('<%= yield %>').result(binding) { 123 } 
    

    Your block is not being passed as yield is outside the message body and you cannot do

    irb(main):042:0> yield.tap { "hello world" }
    LocalJumpError: no block given (yield)
        from (irb):42
        from /Users/agupta/.rvm/rubies/ruby-2.4.0/bin/irb:11:in `<main>'
    irb(main):043:0>