2012-02-22 2 views
12
class String 
    def hello 
    "world" 
    end 
end 

String.class_eval { 
    def world 
    "hello" 
    end 
} 

"a".world 
=> "hello" 
"b".hello 
=> "world" 

彼らは同じことをやっているようだ - 既存のクラスにメソッドを追加します。違いは何ですか?monkey patching vs class_eval?

答えて

12

class_evalを使用すると、よりダイナミックなことを行うことができます。

>> met = "hello" #=> "hello" 
>> String.class_eval "def #{met} ; 'hello' ; end" #=> nil 
>> "foo".hello #=> "hello" 
11

は概念的にクラス再開(またはサルのパッチ適用)を行うclass_evalメソッド。構文上の違いがほとんどあります。あなたは(マイケルの例のように)class_evalに文字列を渡す場合は、class String; ... endのように文字列の中で、ほとんど同じ構文を持っています。あなたがブロックを渡す場合:String.class_eval { ... }次のように比較しますclass_evalメソッドブロック外のローカル変数の内部

  • 外のローカル変数はclass_evalメソッド内部
  • 表示されていないリニューアルオープンクラス内で目に見える
  • ているあなたは、定数を割り当てることができませんし、クラス変数はスコープあなたは

をCANリニューアルオープンクラスの内部クラス

  • に他の違いを知ることは興味深いものになるだろう

  • 0

    他の答えは良いです。 class_evalはあなたがいないその定数によって参照クラスをしたいときに使用することができたり、特定のオブジェクトにパッチを適用することを追加します。

    huh = String 
    class huh 
    end 
    SyntaxError: (eval):2: class/module name must be CONSTANT 
    
    huh.class_eval <<-eof 
    def mamma 
    puts :papa 
    end 
    eof 
    
    "asdff".mamma 
    => papa 
    

    あなたはaffectin全体のルートクラスせずに特定のオブジェクトにパッチを適用するclass_evalを使用することができます。

    obj = "asd" 
    obj.singleton_class.class_eval <<-eof 
    def asd 
    puts "gah" 
    end 
    undef_method :some_method 
    

    上記と同じである:

    class << obj 
        ... 
    end 
    

    instance_evalいくつかの使用によって若干異なる振る舞いを持つことになります。

    私はこの質問と回答は興味深い見つける: How to monkey patch a ruby class inside a method

    はまたinstance_evalclass_evalについての質問があったが、私は便利なリンクを持っていません。

    関連する問題