问题
The following code results in an error
Example 1
if params[:id] == '2' || params.has_key? :id
abort('params id = 2 or nothing')
end
syntax error, unexpected tSYMBEG, expecting keyword_then or ';' or '\n'
if params[:id] == '2' || params.has_key? :id
However, switching the conditional statements || adding parentheses works 100%.
Example 2
if params.has_key? :id || params[:id] == '2'
abort('params id = 2 or nothing')
end
Example 3
if (params[:id] == '2') || (params.has_key? :id)
abort('params id = 2 or nothing')
end
Can anyone explain to me why Example 1 will result in an error ?
Thanks
回答1:
Your problem is happening at:
params[:id] == '2' || params.has_key? :id
which can be simplified to:
:foo || some_method :bar
which causes the same error. This expression is in principle, ambiguous between
(:foo || some_method) :bar (1)
and
:foo || (some_method :bar) (2)
When an expression is ambiguous, it is resolved by other factors. One factor, operator precedence tells nothing here about disambiguating between (1) and (2). The next factor is linear order. Since ||
appears before argument application ()
(omitted) in the expression in question, the former applies before the latter. Therefore, the expression is interpreted as
(1). Since (:foo || some_method)
would then be parsed as an expression, there would be two expressions next to each other. That is ungrammatical, just as:
:baz :bar
is ungrammatical.
In fact, if you switch the order as:
some_method :bar || :foo
then, it will be interpreted as
(some_method :bar) || :foo
for the same reason, and syntax error will disappear.
Also when you resolve ambiguity by explicitly using parentheses to indicate argument application:
:foo || some_method(:bar)
then there is no ambiguity needed to be resolved, and the syntax error disappears.
回答2:
Your :id
is a symbol in Ruby.
a = {'id' => 'a', 'value' => 'value'}
a.has_key? 'id'
=> true
a.has_key? :id
=> false
So you need to change your code:
if params[:id] == '2' or params.has_key? 'id'
abort('params id = 2 or nothing')
end
Note: If you are going to use this code checking for key before checking for value makes more sense.
Note #2: Tested with :
params = {'id' => 'a', 'value' => 'value'}
if params[:id] == '2' or params.has_key? 'id'
abort('params id = 2 or nothing')
end
and Ruby 2.0.0
Also check this question for more information about Ruby Symbols.
回答3:
It has to do with how Ruby
evaluates that if
statement.
Example 1 is like
if (params[:id] == '2' || params.has_key?) :id
which resolves in an unexpected symbol error as you can see syntax error, unexpected tSYMBEG
.
回答4:
As guy says... the parser doesn't assume that the symbol is a parameter for the has_key? method
You can bypass the error by explicitly coding the parentheses
if params[:id] == '2' || params.has_key?(:id)
来源:https://stackoverflow.com/questions/17720115/ruby-on-rails-ruby-operator-precedence-parentheses