More on Methods

Now that you have met classes and objects, it’s worth revisiting methods from a few new angles — how to chain them, how to convert values between classes, and how to pass arguments more cleanly.

Method Chaining

A method returns a value, and you can call another method on that value right away. You will see long chains like this all over idiomatic Ruby code:

$ irb
>> a = 'a blue car'
=> "a blue car"
>> a.upcase
=> "A BLUE CAR"
>> a.upcase.reverse
=> "RAC EULB A"
>> exit

Each method hands its result to the next.

Converting Between Classes (Casting)

Ruby gives most classes a handful of to_* methods for converting into another class. to_s turns something into a String, to_i into an Integer, to_f into a Float, and so on.

$ irb
>> a = 10
=> 10
>> a.class
=> Integer
>> b = a.to_s
=> "10"
>> b.class
=> String
>> exit
puts uses to_s under the hood. That is why puts 10 just works — puts calls to_s on anything that is not already a string.

Going the other way:

$ irb
>> c = 10.0
=> 10.0
>> c.class
=> Float
>> d = c.to_i
=> 10
>> d.class
=> Integer
>> exit

Is + a Method?

Operators like + look like special syntax, but in Ruby they are ordinary method calls. You can see the method documented right alongside the rest of the class:

$ ri -T String.+
String.+

(from ruby site)
------------------------------------------------------------------------------
  str + other_str   -> new_str

------------------------------------------------------------------------------

Concatenation---Returns a new String containing other_str
concatenated to str.

  "Hello from " + self.to_s   #=> "Hello from main"

And for Integer:

$ ri -T Integer.+
Integer.+

(from ruby site)
------------------------------------------------------------------------------
  int + numeric  ->  numeric_result

------------------------------------------------------------------------------

Performs addition: the class of the resulting object depends on
the class of numeric and on the magnitude of the result.

Which means you can call + with the regular method-call syntax if you want to:

$ irb
>> 10 + 10
=> 20
>> 10+10
=> 20
>> 10.+10
=> 20
>> 10.+(10)
=> 20
>> exit

All four lines do the same thing. 10 + 10 is just nicer to read.

Can I Override +?

Yes — any method, including operators, can be redefined. That is rarely a good idea, but it is possible. Here we redefine Integer#+ to always return 42:

monkey-patch-a.rb
class Integer
  def +(name, *args, &blk)
    42
  end
end
irb
>> 10 + 10
=> 20
>> load './monkey-patch-a.rb'
=> true
>> 10 + 10
=> 42
>> exit

Reopening a class to change built-in behavior like this is called a monkey patch. Useful in tiny doses; a source of confusion at scale.

Agentic Coding Tip: Don’t Let the Agent Monkey-Patch a Core Class

Reopening Integer, String, Array or any other core class to add a method is powerful — too powerful. When asked "add a .palindrome? method to strings" or "make Integer have a .to_roman method," an agent will happily reopen the class because it’s the shortest code that demonstrably works.

The problems show up later, not at the point of writing:

  • Every library that touches that class now behaves subtly differently from how its authors tested it.

  • Two parts of the same codebase can redefine the same method and clobber each other, with the last one loaded winning silently.

  • Stack traces point into core/string.rb even though the surprising behaviour is local to your project.

In almost every beginner case, the better shape is a plain method on a helper module or a subclass. If you need a "reverse this string and uppercase it" operation, write a module method; don’t add .shout_reversed to String.

Rule to add to your project’s CLAUDE.md:

Never reopen Ruby's core classes (Integer, Float, String,
Array, Hash, Symbol, Range, Numeric, Object) to add or
override methods. Put helpers on a module, a class method,
or a small wrapper class instead. If you believe reopening a
core class is genuinely warranted (e.g. a gem's published
extension pattern), stop and explain why before writing the
code.

Keyword Arguments

So far we have passed arguments by position: the first argument goes into the first parameter, the second into the second, and so on. That works fine for one or two arguments but becomes error-prone with four or five. Which one was the name again, which one the age?

Keyword arguments fix that. A colon after the parameter name turns it into a keyword:

greet-a.rb
def greet(name:, age:)
  puts "Hello #{name}, you are #{age} years old."
end
$ irb
>> load './greet-a.rb'
=> true
>> greet(name: 'Stefan', age: 52)
Hello Stefan, you are 52 years old.
=> nil
>> greet(age: 52, name: 'Stefan')
Hello Stefan, you are 52 years old.
=> nil
>> exit

Order no longer matters, and the call reads almost like a sentence. If you leave a required keyword out, Ruby raises an error:

>> greet(name: 'Stefan')
ArgumentError (missing keyword: :age)

You can give a keyword a default value:

greet-b.rb
def greet(name:, age: 18)
  puts "Hello #{name}, you are #{age} years old."
end

Now age is optional:

$ irb
>> load './greet-b.rb'
=> true
>> greet(name: 'Stefan')
Hello Stefan, you are 18 years old.
=> nil
>> exit

Rails uses keyword arguments heavily. You will see them everywhere.

Multiple Assignment and the Splat Operator

Ruby lets you assign several variables on one line:

$ irb
>> a, b = 1, 2
=> [1, 2]
>> a
=> 1
>> b
=> 2
>> exit

Handy for swapping values without a temporary variable:

$ irb
>> a = 1
=> 1
>> b = 2
=> 2
>> a, b = b, a
=> [2, 1]
>> a
=> 2
>> b
=> 1
>> exit

If the right side has more elements than the left, Ruby drops the rest. If it has fewer, the leftover variables become nil. Use the splat operator * to collect the rest into an array:

$ irb
>> first, *rest = [1, 2, 3, 4]
=> [1, 2, 3, 4]
>> first
=> 1
>> rest
=> [2, 3, 4]
>> exit

The same splat works on method parameters, letting a method accept any number of arguments:

sum.rb
def sum(*numbers)
  total = 0
  numbers.each { |n| total += n }
  total
end
$ irb
>> load './sum.rb'
=> true
>> sum(1, 2, 3)
=> 6
>> sum(10, 20, 30, 40)
=> 100
>> exit

Inside sum, numbers is a regular array.