Search code examples
rubytestingshoulda

One-liner shoulda syntax using braces


In the book Rails Test Prescriptions (b10.0, page 176), there are examples of one-liner assertions like the following:

should "be successful" { assert_response :success }

This doesn’t appear to be valid ruby syntax to me, and ruby reports that the left curly brace is unexpected. In order for it to be parsed, I have to change it to

should "be successful"; do assert_response :success end

What's wrong with the syntax of the first example?


Solution

  • This is valid Ruby syntax. Well, sort of. It just doesn't make sense!

    Since the precedence of a literal block using curly braces is higher than passing an argument without parentheses, the block gets bound to the argument instead of the method call. If the argument is itself a method call, then you won't even get a syntax error. You'll just scratch your head wondering why your block doesn't get called.

    To fix this, you either put parentheses around the argument, since parentheses have higher precedence than curly braces, or use the do / end form, which is lower precedence than an argument list without parentheses.

    def foo; yield if block_given?; 'foo' end
    
    puts foo { puts 'block' }
    # block
    # foo
    
    puts(foo) { puts 'block' }
    # foo
    
    puts foo do puts 'block' end
    # foo
    
    puts foo { puts 'block' }, foo { puts 'block' }
    # block
    # block
    # foo
    # foo
    
    puts 'foo' { puts 'block' }
    # SyntaxError: (irb):19: syntax error, unexpected '{', expecting $end