I recently ran into an oddity while looking at some Ruby code from the Rails docs.
Ruby lets you pass arguments like these examples:
redirect_to post_url(@post), alert: "Watch it, mister!"
redirect_to({ action: 'atom' }, alert: "Something serious happened")
But that second case looked odd to me. It seems like you should be able to pass it like so:
redirect_to { action: 'atom' }, alert: "Something serious happened"
And it would have the same meaning with or without parenthesis. But instead you get:
syntax error, unexpected ':', expecting '}'
Referring to the colon after action
. I'm not sure why it would be expecting }
there, and why using parenthesis would change that.
Because { ... }
has two meanings: hash literal and block.
Consider this:
%w(foo bar baz).select { |x| x[0] == "b" }
# => ["bar", "baz"]
Here, { ... }
is a block.
Now imagine that you are calling a method on the current object, so the explicit receiver is not needed:
select { |x| x[0]] == "b" }
Now imagine that you don't care about the parameter:
select { true }
Here, { true }
is still a block, not a hash. And so it is in your function call:
redirect_to { action: 'atom' }
is (mostly) equivalent to
redirect_to do
action: 'atom'
end
and it is nonsense. However,
redirect_to({ action: atom' })
has an argument list, consisting of a hash.
Curly braces serve double-duty in Ruby. They can delimit a hash, but they can also delimit a block. In this case, I believe your second example is getting parsed as:
redirect_to do
action: 'atom'
end, alert: "Something serious happened"
Therefore your action: 'atom'
, which is not valid as an independent expression, gets parsed as such.
The parentheses serve to disambiguate the {...}
as a hash.
来源:https://stackoverflow.com/questions/33602788/why-are-parenthesis-sometimes-required-in-ruby