Ruby | 文字列への明示的変換と暗黙的変換。Object#to_s , Object#to_str の使い分け

# Ruby | 文字列への明示的変換と暗黙的変換。Object#to_s , Object#to_str の使い分け

## 概要
文字列への明示的変換と暗黙的変換。Object#to_s , Object#to_str の使い分けについて。

## Object#to_s と  Object#to_str に関する Matz さんの発言
### Matz さんの発言
http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-dev/18648

~~~
to_sは(どのオブジェクトにもデフォルトで定義されている)文字列
化のフォーマットを変えるために再定義します。

to_strはそのクラス/オブジェクトが文字列として振る舞うことが
できるようにするために定義します。
~~~

## Object#to_s
### るりまのドキュメント
http://docs.ruby-lang.org/ja/2.1.0/method/Object/i/to_s.html

明示的な変換。

Kernel#print や文字列の変数展開でも使われている to_s。
オブジェクトの文字列表現を返却する。

オブジェクトの文字列化が目的。

## Object#to_str
### るりまのドキュメント
http://docs.ruby-lang.org/ja/2.1.0/method/Object/i/to_str.html

暗黙的な変換。

文字列の + 演算子利用時に呼び出されている to_str。

### Matz さんの発言

~~~
Stringと類似のメソッド集合を持たないオブジェクトはto_strを定義するべ
きではないように思います(実害がない限り)。
~~~

http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-dev/23332

ダックタイピングが目的。

つまり、String のように振る舞う

### to_str の実装例
Rails の ActiveView の Template で to_str を実装していました

#### ActiveView::Template::Text / HTML / Resolver
https://github.com/rails/rails/blob/master/actionview/lib/action_view/template/text.rb
https://github.com/rails/rails/blob/master/actionview/lib/action_view/template/html.rb
https://github.com/rails/rails/blob/master/actionview/lib/action_view/template/resolver.rb

## to_s , to_str の動作確認用サンプルコード

~~~ruby
class Person
  attr_reader :name, :age

  def initialize(name, age)
    @name, @age = name, age
  end

  def to_str
    @name
  end
end

class NotStringPerson
  attr_reader :name, :age

  def initialize(name, age)
    @name, @age = name, age
  end

  def to_s
    @name
  end
end

tanaka = Person.new("tanaka", 34)
suzuki = NotStringPerson.new("suzuki", 44)
puts "■ to_s, to_str を直接呼び出し"
puts "tanaka.to_s = " + tanaka.to_s
puts "tanaka.to_str = " + tanaka.to_str
puts "suzuki.to_s = " + suzuki.to_s
begin
  puts "suzuki.to_str = " + suzuki.to_str
rescue => e
  puts e.message
end

# + 演算子利用時に暗黙的に to_str を利用した変換が行われる
puts "■ + 演算子利用時の to_str  呼び出し確認"
puts "tanaka name = " + tanaka
begin
  puts "suzuki name = " + suzuki
rescue => e
  puts e.message
end

# 変数展開時にも暗黙的に to_s を利用した変換が行われる
puts "■ 変数展開"
puts "tanaka name = #{tanaka}"
puts "suzuki name = #{suzuki}"

class StringUser
  def self.use_string(text)
    fail 'error!' unless text.respond_to? :to_str
    text = text.to_str
    puts text.upcase
  end
end

puts "■ StringUser クラスから呼び出し"
StringUser.use_string("hoge")
StringUser.use_string(tanaka)
begin
  StringUser.use_string(suzuki)
rescue => e
  puts e.message
end
~~~

* 出力

~~~
■ to_s, to_str を直接呼び出し
tanaka.to_s = #<Person:0x2bcd370>
tanaka.to_str = tanaka
suzuki.to_s = suzuki
undefined method `to_str' for #<NotStringPerson:0x2bcd328 @name="suzuki", @age=44>
■ + 演算子利用時の to_str  呼び出し確認
tanaka name = tanaka
no implicit conversion of NotStringPerson into String
■ 変数展開
tanaka name = #<Person:0x2bcd370>
suzuki name = suzuki
■ StringUser クラスから呼び出し
HOGE
TANAKA
error!
~~~

## 参照
* http://docs.ruby-lang.org/ja/2.1.0/method/Object/i/to_s.html
* http://docs.ruby-lang.org/ja/2.1.0/method/Object/i/to_str.html

* https://github.com/rails/rails/blob/master/actionview/lib/action_view/template/text.rb
* https://github.com/rails/rails/blob/master/actionview/lib/action_view/template/html.rb
* https://github.com/rails/rails/blob/master/actionview/lib/action_view/template/resolver.rb