aceofspades
aceofspades

Reputation: 7586

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?

Upvotes: 0

Views: 294

Answers (2)

Noel Rappin
Noel Rappin

Reputation: 61

This may be a mistake on my part in trying to get the example to take up fewer lines. The block is probably binding to the argument and not the method call, as Jorg said.

I think that the proper way to rewrite this as a one-liner is:

should("be successful") { assert_response :success }

But really, the way to go is to use the shoulda macro:

should respond_with(:success)

Thanks,

Noel

Upvotes: 2

Jörg W Mittag
Jörg W Mittag

Reputation: 369536

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

Upvotes: 4

Related Questions