まりぴよこのブログ

日々の日記。技術ネタでまとまりきってないものの記録、伝わる文章の書き方を練習とか。

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)

シンボルと文字列を比較しても、一致しない。ということは、メソッド名がシンボルとして定義されていることをチェックするためには、探したいメソッド名のシンボルを渡さなければならない。

メソッド名がシンボルになっていることをテストしようとしてるのに、メソッド名がシンボルであることを利用して証明するわけにはいかない・・から・・?

合ってますかね・・??

回答

stackoverflow.com

あった!コレだ!! さすが、Stakoverflow

原文を正しく解釈できたか、私の英語力が問われるところですが・・ ざっくり噛み砕くと、

assert_equal true, all_symbols.include?(:mymethod)

をやってしまうことで、シンボルを新しく作り出してしまうから・・

そ・・そうなの?? なんかまだちょっと意味がわからん・・

完全回答

github.com

コレだ。納得。

どんなメソッド名を渡しても、その瞬間にシンボルとして定義されてしまうので、どんなメソッド名が書かれても、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が含まれてしまうのかの回答を見つけた。

qiita.com

コードが構文解析されるタイミングですでにシンボルテーブルにシンボルが追加されてしまう

なるほど。。

Ruby KoansのスクリプトでUnit Testしてる時は、スクリプト読み込み時点でシンボルテーブルに入ってしまうから、なのか。。 irbで実行すると、freezeしても、しなくても大丈夫。 スクリプトで実行とirbで実行だと、こういうところ細かく挙動違うんだ。。