Ruby Koans で学ぶ Symbol
シンボルはさすがに何度も勉強したし・・わかるでしょ・・と思いつつ・・
改めて確認
- シンボルは比較できる
- 同名のシンボルは内部的に1つのオブジェクト
symbol1 = :a_symbol symbol2 = :a_symbol assert_equal true, symbol1 == symbol2 assert_equal true, symbol1.object_id == symbol2.object_id
うむうむ。 さすがRuby。驚き最小の原則に従っている♪
知らなかった・・
メソッド名はシンボルになる
確認方法
確認コード
def mymethod end symbols_as_strings = Symbol.all_symbols.map { |x| x.to_s } assert_equal true, symbols_as_strings.include?("mymethod")
Koansから「考えてみよう」の課題が・・
原文:
THINK ABOUT IT:
Why do we convert the list of symbols to strings and then compare against the string value rather than against symbols?
すげー意訳:
何故シンボルのリストを文字列リストに変換したのか? シンボルで比較せずに文字列で比較した理由を考えてみよう。
ぐぬぬ・・なんで・・?
シンボルのまま比較してみたらどうなるか、やってみた。
def mymethod end all_symbols = Symbol.all_symbols assert_equal false, all_symbols.include?("mymethod") assert_equal true, all_symbols.include?(:mymethod)
シンボルと文字列を比較しても、一致しない。ということは、メソッド名がシンボルとして定義されていることをチェックするためには、探したいメソッド名のシンボルを渡さなければならない。
今メソッド名がシンボルになっていることをテストしようとしてるのに、メソッド名がシンボルであることを利用して証明するわけにはいかない・・から・・?
合ってますかね・・??
回答
あった!コレだ!! さすが、Stakoverflow
原文を正しく解釈できたか、私の英語力が問われるところですが・・ ざっくり噛み砕くと、
assert_equal true, all_symbols.include?(:mymethod)
をやってしまうことで、シンボルを新しく作り出してしまうから・・
そ・・そうなの?? なんかまだちょっと意味がわからん・・
完全回答
コレだ。納得。
どんなメソッド名を渡しても、その瞬間にシンボルとして定義されてしまうので、どんなメソッド名が書かれても、trueが返ってしまう・・と。
つまりコードで書くとこんな感じ。
all_symbols = Symbol.all_symbols assert_equal true, all_symbols.include?(:my_dearly_new_method)
ここで更にもう一度つまづいたんだけど、all_symbolsを変数に取ってるとこ、次の行の新しいシンボル定義より前に書いてあるのに・・なんで??
(ここまだよくわかってない) 別にその行に来た時にシンボルを定義するって決まってる訳じゃない・・・から・・かな??(でも実際はどうなんだろう?) その行に来た時に定義する、だと結構面倒くさいことになりそう(使う側が) この辺まだ全然調べきれてない・・・
さっきのテストコードだと、どんなシンボル名渡してもtrueになってたから、先に定義されてるのは確実っぽいんだけど・・
まだシンボルの章半分くらいだよ。。 シンボル・・めちゃめちゃ深淵すぎて、溺れていく〜〜;; 後半は明日に持ち越し!
【2015/8/29 追記】
なぜ先に定義したはずの、 all_symbols
に新しく定義したsymbolが含まれてしまうのかの回答を見つけた。
なるほど。。
Ruby KoansのスクリプトでUnit Testしてる時は、スクリプト読み込み時点でシンボルテーブルに入ってしまうから、なのか。。 irbで実行すると、freezeしても、しなくても大丈夫。 スクリプトで実行とirbで実行だと、こういうところ細かく挙動違うんだ。。