How to Use Ruby Conversion Methods (to_s, to_a, to_str)

You’re working with an integer but you would like to use string methods (like gsub) instead.

What can you do?

Convert it into a string (with to_s) then convert it back to an integer (with to_i).

For example:

You can convert the Integer 1 to the String “1”.

Then you can use methods from the new class, which helps you do something that wasn’t possible before.

Remember that in Ruby…

Every object is associated with a class, and every class has a specific set of methods.

In this article, you’re going to learn about:

  • What conversion methods are available in Ruby
  • What are the differences between them!
  • How to choose the right one in different situations

Let’s do this!

Short Conversion Methods (to_s, to_i)

You’re probably familiar with this first group of conversion methods.

Methods like:

  • to_i
  • to_s
  • to_a

These methods return a new object of a specific class that represents the current object.

For example:

(1..10).to_a

# [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

This says:

“I want to convert the Range 1..10 into an Array that represents that range.”

There are ways in which Ruby calls these conversion methods for you implicitly.

Like in string interpolation:

"#{1}"

This calls 1.to_s for you, even if you don’t see it.

You can check yourself with this code:

module Log
  def to_s
    puts "to_s called"
    super
  end
end

class Integer
  prepend Log
end

puts "#{1}"
# "to_s called"

Note: You have to use Fixnum instead of Integer if you’re on Ruby 2.3 or older. Or better yet, update your Ruby version 🙂

These methods are pretty permissive & they’re not supposed to raise an exception.

For example:

"aaaaaa".to_i

# 0

This 0 may surprise you.

But that’s what you get when you call to_i on a string without integers on it.

As you’ll see later in this article there is a more strict version of this method.

Long Conversion Methods (to_str, to_int)

Now:

If we have those short conversion methods, why do we need methods like to_str, or to_int?

What’s the difference?

The difference is in their intent.

Every Ruby class (with the exception of BasicObject) implements the to_s method to return itself as some type of string representation.

But just because a class returns a string doesn’t mean it behaves like a string!

Let’s look at an example:

"" + 1
# TypeError: no implicit conversion of Fixnum into String

Think about this:

What should an empty string plus integer return?

I don’t know.

You could say “1” (a string with the number one).

But why?

That’s not what most people expect in this case.

It doesn’t make sense to add them up… that’s why we get this TypeError.

And even if that was allowed.

What about this:

"" + {}

That’s an empty string plus an empty hash.

Doesn’t make sense either!

So Ruby instead of checking if the other object is a string, which wouldn’t be good for Polymorphism, it checks if it ACTS like a string.

That’s where the to_str method comes in.

The only classes that implement to_str in Ruby 2.5:

  • String
  • NameError::message
  • Warning::buffer

How to Implement Your Own Conversion Methods

You can implement to_str on any class.

Then you’ll be able to use it like a string.

Here’s an example:

class Cat
  def to_str
    "meow"
  end
end

"" + Cat.new

# "meow"

But unless your class is equivalent to a string you shouldn’t do this.

Use to_s instead.

Btw, this is not only for the + method.

It’s also used on other places where only a string-like object makes sense.

Like:

[1,2,3].join(",")

The other long conversion methods like to_int & to_hash follow the same logic.

That’s why we have these different methods.

How to Use Conversion Wrappers

If you haven’t had enough conversion methods yet… don’t worry because I have a few more for you!

I like to call these “Conversion Wrappers”.

They are:

  • Array()
  • Integer()
  • Hash[]

That’s some unusually-looking methods right there!

Notice the parenthesis & square brackets…

…it’s the only thing separating these methods from their class names.

What’s the purpose of these?

Array() will convert ANYTHING into an array.

Here’s some examples for you:

Array(nil)
# []

Array([])
# []

Array(1)
# [1]

Array("")
# [""]

What kind of logic is this???

Well, this method follows a very specific set of rules:

  • If the object responds to to_ary, or to_a it’ll call that & return the value
  • Otherwise, it will put the object inside an empty array & return that

That explains the behavior shown above.

This is useful if you’re writing a method that expects an array but it could get anything else & make your method crash the whole application. You can make sure it’s an array by passing it to Array() first to avoid that.

Now Integer().

It has some special rules:

  • If the object is a string & the contents of the string strictly conform to a valid numeric representation in Ruby this method will return an Integer. Raises ArgumentError if invalid format.
  • If the object isn’t a string it will try to call to_int, then to_i.
  • It’ll raise a TypeError if the object can’t be converted into a valid Integer using a conversion method.

Example:

Integer(1)
# 1

Integer("25")
# 25

Integer("abc123")
# ArgumentError (invalid value for Integer(): "abc123")

Integer([])
# TypeError (can't convert Array into Integer)

This Integer() method is useful if you want to make 100% sure you’re working with a valid Integer.

Now Hash[].

You can pass an array of even elements to get a new hash:

Hash[[["a", 1], ["b", 2], ["c", 3]]]

# {"a"=>1, "b"=>2, "c"=>3}

Useful if you are building your hash by merging the elements of two arrays, or using a method like map.

Summary

You’ve learned about the different conversion methods in Ruby, why they exist & how to use them!

I hope you found this helpful 🙂

If you enjoyed this article you’ll also love my book, Ruby Deep Dive, check it out.