Home > database >  (ArgumentError) Ruby : wrong number of arguments
(ArgumentError) Ruby : wrong number of arguments

Time:11-06

def visualization (name, age, looks)
  age.to_s
  puts name   ' is '   age   ' years old and looks '   looks
end

visualization (name = 'Mary', age = 5, looks = 'bad')

#=> `visualization': wrong number of arguments (given 1, expected 3) (ArgumentError)

CodePudding user response:

So the main problem here is the space between visualization and its arguments. When ruby sees visualization (name = 'Mary', age = 5, looks = 'bad') it recognizes `visualization as a method (because it has argument), but it first tries to calculate the expression in the brackets:

(name = 'Mary', age = 5, looks = 'bad')

This on its own is a valid ruby expression, but it might be quite a surprise to see how ruby interpretes it:

name = ('Mary', (age = 5), (looks = 'bad'))

Resulting in name being ['Mary', 5, 'bad'], age being 5 and looks being 'bad'.

As the expression is just an assignment, it returns the assigned value (array ['Mary', 5, 'bad']) which is then passed to your visualisation method. Since you are passing a single array and your method expects three arguments, you're getting the error.

AS per solution, just drop the space between method call and its arguments. You also don't need to name the arguments - this is not Python - here keywords are defined explicitly and you actually creating local variables by doing so.

There are some other issues there as well, but @Stefan has covered that already.

CodePudding user response:

age.to_s doesn't alter the age object (you can't change the class of an object in Ruby), it merely returns a new string. So you either have to re-assign age via age = age.to_s or move the to_s call to where it is needed:

def visualization(name, age, looks)
  puts name   ' is '   age.to_s   ' years old and looks '   looks
end

You can use string interpolation instead which is more idiomatic and makes to_s calls superfluous:

def visualization(name, age, looks)
  puts "#{name} is #{age} years old and looks #{looks}"
end

When calling this method, you pass the arguments via:

visualization('Mary', 5, 'cute')
#            ^ and no space here

The assignments in your code don't make much sense. You probably wanted to have keyword arguments: (note the colons)

def visualization(name:, age:, looks:)
  puts "#{name} is #{age} years old and looks #{looks}"
end

visualization(name: 'Mary', age: 5, looks: 'cute')

CodePudding user response:

TL;DR

Ruby isn't whitespace sensitive in the same way as languages like Python, but there are places where whitespace is confusing to the parser. In addition, while some of your code works, it's not idiomatic (it reads like JavaScript) and is less performant. Finally, in-place operators are usually bang methods, so you need to distinguish between methods that change the receiver and ones that return a new result.

Idiomatic Alternative

I changed some of your code for cultural reasons, but kept it close to your intent data-wise. The rest is intended to show how to do what you want more idiomatically.

Here's a more idiomatic and parser-friendly alternative that uses string interpolation:

def user_data(name, age, status)
  pp "name is #{name}; age is #{age}; status is #{status}"
end

String interpolation using the embedded expression operator #{expr} within double quotes is often more efficient, and implicitly converts values to strings if it supports a #to_s or #to_str method. The Kernel#p and Kernel#pp methods ensure that the method returns a value, as well as printing to $stdout.

Alternatively, you can also use other constructs like here-documents, String#sprintf, String#format, and many others to construct printf-style interpolations, but the example above is easiest to read for most Rubyists, and should generally be your go-to if you follow most of the popular Ruby style guides, including RuboCop's default style guide.

Note: Interpolation Works with Frozen String Literals

As a final note, this type of interpolation will also work even if you have the frozen-string literal "magic comment" enabled at the top of your file, e.g.:

#!/usr/bin/env ruby
# frozen_string_literal: true

which is often considered a best practice by RuboCop and other similar tools.

  • Related