Existe um pouco de confusão quando estamos falando dos métodos: to_s e to_str. Qualquer objeto, no ruby, pode ser convertido para uma representação em string. Quando olhamos as classes no core nos deparamos com um método to_s (Por exemplo, execute Fixnum.methods e você verá o método), mas não vemos o método to_str. Pense que to_str é para conversão implícita e to_s é para conversão explícita.

Vamos ver um exemplo:

 

class Automovel
  def to_s
    "Carro"
  end

  def to_str
    "Fiat"
  end
end

auto = Automovel.new
puts auto
puts "O automóvel criado foi #{auto}"
puts "O automóvel criado foi " + auto

# Saída COM o método to_str definido
# Alberto:Desktop Alberto$ ruby post.rb
# Carro
# O automóvel criado foi Carro
# O automóvel criado foi Fiat

 

É possível notar que, quando definimos o método to_str estamos forçando uma conversão. Vamos executar o mesmo código acima, porém sem o método to_str definido:

class Automovel
  def to_s
    "Carro"
  end
end

auto = Automovel.new
puts auto
puts "O automóvel criado foi #{auto}"
puts "O automóvel criado foi " + auto

# Saída SEM o método to_str definido
# Alberto:Desktop Alberto$ ruby post.rb
# Carro
# O automóvel criado foi Carro
# post.rb:10:in `+': can't convert Automovel into String (TypeError) from post.rb:10

 

Vale ressaltar que, quando usamos o método puts, esse sempre chama o método to_s do objeto quando desejamos a representação textual de um objeto.

Vamos ver mais um exemplo: Quando tentamos concatenar uma String com um objeto do tipo Fixnum, diretamente, não conseguimos porque a classe Fixnum não possui o método to_str, para conversão implícita.

s = "Número: " + 007
TypeError: can't convert Fixnum into String
    from (irb):3:in `+'
    from (irb):3
    from :0

 

Agora, quando adicionamos o método em tempo de execução a classe Fixnum (via duck typing), conseguimos executar o código que antes acusava TypeError :

class Fixnum
  def to_str
    self.to_s
  end
end

s = "Número: "+ 007

Outra forma de executar o código, sem ter que adicionar o novo método a classe Fixnum, seria chamar o método to_s diretamente:

s = "Número: "+ 007.to_s