Reputation: 994
while building a website with rails, I found a little syntax error that I really don't understand what caused it.
class User < ApplicationRecord
has_secure_password
has_many :posts, dependent: :nullify
has_many :comments, dependent: :nullify
validates :first_name, :last_name, presence: true, length: {maximum: 30}
validates :email, presence: true, uniqueness: true, format: /\A[\w+\-.]+@[a-z\d\-]+(\.[a-z\d\-]+)*\.[a-z]+\z/i
def full_name
(first_name +" "+ last_name).titleize
end
end
this is model file for user. If I run this file, it causes an error: wrong number of arguments(given 1, expected 0). However if I give a space like so,
def full_name
(first_name + " "+ last_name).titleize
end
It runs normally.
Although I know I can just ignore it, I'm just so curious about how the space causes argument error, it ain't no argument I think..
I also ran the same code in normal ruby by making my own titleize method in string class, it works fine without the space. so curious !
Upvotes: 1
Views: 473
Reputation: 9485
You can use ruby_parser
to eliminate your doubts about how this is actually parsed.
RubyParser.for_current_ruby.parse '(first_name +" "+ last_name)'
results in:
s(:call, nil,
:first_name,
s(:call, s(:call, s(:str, " "),
:+@),
:+,
s(:call, nil,
:last_name)))
Effectively, you're getting first_name((+" ") + last_name)
, or in a more redundant/methody fashion, self.first_name((" ".+@).+(self.last_name))
.
Meaning there is an argument in a call of the first_name
method, stemming from accidental use of +@
, the unary plus, on " "
. But since first_name
is an attribute getter (I guess?) and does not accept any arguments, you're getting an ArgumentError
.
To help you interpret this output, a :call
S-expression consists of:
:call
nil
if self
)And by the way, Rubocop could have warned you about this:
Lint/AmbiguousOperator: Ambiguous positive number operator. Parenthesize the method
arguments if it's surely a positive number operator, or add a whitespace to the
right of the + if it should be a addition.
(first_name +" "+ last_name)
^
Consider adding it into your workflow.
Upvotes: 4
Reputation: 27747
This is likely going between the unary-plus operator and the binary-plus operator when you put code directly next to it.
unary plus is just like unary-minus eg -2
and I'm sure you understand the difference between writing 1 -2
and 1 - 2
?
As an aside, the standard "ruby way" would be to interpolate rather than use concatenation, so your line would be better written:
"#{first_name} #{last_name}".titleize
Upvotes: 2