2011-01-13 4 views
70

を文字列にシンボルのリストを変換 https://github.com/edgecase/ruby_koans/blob/master/src/about_symbols.rb#L26ルビーKoans:なぜ私はRubyのKoansにabout_symbols.rbにこのテストを参照しています

def test_method_names_become_symbols 
    symbols_as_strings = Symbol.all_symbols.map { |x| x.to_s } 
    assert_equal true, symbols_as_strings.include?("test_method_names_become_symbols") 
end 


    # THINK ABOUT IT: 
    # 
    # Why do we convert the list of symbols to strings and then compare 
    # against the string value rather than against symbols? 

なぜまさに我々は最初の文字列にそのリストを変換する必要がありますか?

答えて

93

これはシンボルの仕組みと関係があります。各シンボルについて、そのシンボルの1つだけが実際に存在します。背後にあるシンボルは、名前(コロンで始まる)で参照される数字に過ぎません。したがって、2つのシンボルが等しいかどうかを比較するときは、オブジェクト識別とではなく、とこのシンボルを参照する識別子の内容を比較しています。

:test == "test"という簡単なテストを行う場合は、falseになります。したがって、今までに定義されたシンボルをすべて配列に集める場合は、それらを比較する前に、それらを文字列に変換する必要があります。これを逆にすることはできません(比較したい文字列を最初にシンボルに変換してください)。これを行うとそのシンボルの単一インスタンスが作成され、存在をテストしているシンボルでリストが汚染されます。

希望に役立ちます。テスト中にシンボルを誤って作成することなく、シンボルの存在をテストする必要があるため、これはちょっと変わったものです。そのようなコードは通常表示されません。

+1

これを安全に実行するには、 'Symbol.all_symbols'の出力を変数に代入し、インクルードをテストするのが良い方法です。シンボルは比較の速度が速く、何千ものシンボルを文字列に変換することは避けています。 – coreyward

+4

まだ破壊できないシンボルを作成するという問題があります。そのシンボルの今後のテストはすべて破棄されます。しかしこれはちょうどコーン(Koan)であり、それはあまり意味がなくても速くなくても、シンボルがどのように機能するかを実証するだけです。 – AboutRuby

+1

この回答は私には役に立たない。 '':test_method_names_become_symbols''を指定した場合、それらのシンボルをすべて文字列に変換する必要はありません。 –

68

あなたはそれがかもしれ

assert_equal true, all_symbols.include?(:test_method_names_become_symbols) 

を行うかどうかを尋ねる程度:test_method_names_become_symbolsそれを作成するため、自動的に真である(あなたのルビーの実装に依存する)ので。 this bug reportを参照してください。上記

+1

受け入れられた答えは間違ったものです(それは私にとってはそうです)。 –

+3

アイザック、他の答えは間違っていませんが、簡潔に説明されていません。確かに。とにかく、Andrewが言っていることを次のように確認することができます: assert_equal true、Symbol.all_symbols.include?(:abcdef) これはシンボルに関係なく常に(少なくとも私にとっては)合格します。私は1つの教訓がブーリアンフラグとしてシンボルの有無を使用しようとしないことを推測します。 – Stephen

+1

2年後、まだ私に興味があるこの質問を見て、私は本当にこの答えとコメントに感謝します。私はIsaacが正しかったと思うのですが、これは文字列への変換が行く方法かもしれない理由を最も明確に説明している答えですが、中間段階(比較の前にすべての記号を格納) – codenoob

3

どちらの答えが正しいですが、カルティクの質問の光の中で私は、私は1つが正確にinclude方法

def test_you_create_a_new_symbol_in_the_test 
    array_of_symbols = [] 
    array_of_symbols << Symbol.all_symbols 
    all_symbols = Symbol.all_symbols.map {|x| x} 
    assert_equal false, array_of_symbols.include?(:this_should_not_be_in_the_symbols_collection) #this works because we stored all symbols in an array before creating the symbol :this_should_not_be_in_the_symbols_collection in the test 
    assert_equal true, all_symbols.include?(:this_also_should_not_be_in_the_symbols_collection) #This is the case noted in previous answers...here we've created a new symbol (:this_also_should_not_be_in_the_symbols_collection) in the test and then mapped all the symbols for comparison. Since we created the symbol before querying all_symbols, this test passes. 
end 

Koansに関する追加の音符に記号を渡すかもしれない方法を示してテストを投稿するだろうと思ったの上:あなたが何かを理解していない場合は、putsステートメントとカスタムテストを使用してください。あなたが見る場合たとえば、:

string = "the:rain:in:spain" 
words = string.split(/:/) 

をしてwordsが何であるか見当がつかない、ライン

puts words 

を追加して、コマンドラインでrakeを実行します。同様に、私が上に追加したもののようなテストは、Rubyのニュアンスを理解するうえで役立ちます。

+0

2年後、まだ私に興味があるこの質問を見て、私は本当にこの答えとコメントに感謝します。 – codenoob

関連する問題