2012-03-20 9 views
6

オブジェクトのメソッドの実装を、ユーザーが指定するブロックに置き換えたいと思います。 JavaScriptでは、これは容易に達成される:Rubyのオブジェクトのメソッド実装を動的に置き換えます

function Foo() { 
    this.bar = function(x) { console.log(x) } 
} 
foo = new Foo() 
foo.bar("baz") 
foo.bar = function(x) { console.error(x) } 
foo.bar("baz") 

C#では、それはまた

class Foo 
{ 
    public Action<string> Bar { get; set; } 
    public Foo() 
    { 
     Bar = x => Console.WriteLine(x); 
    } 
} 

var foo = Foo.new(); 
foo.Bar("baz"); 
foo.Bar = x => Console.Error.WriteLine(x); 
foo.Bar("baz"); 

非常に簡単です。しかし、どのように私はRubyで同じことを行うことができますか?

:私はインスタンス変数にラムダを格納し、この方法は、ラムダを呼び出しますが、私は本当にオーバーヘッドと構文

class Foo 
    def initialize 
    @bar = lambda {|x| puts x} 
    end 

    def bar x 
    @bar.call x 
    end 

    def bar= blk 
    @bar = blk 
    end 
end 

foo = Foo.new 
foo.bar "baz" 
foo.bar= lambda {|x| puts "*" + x.to_s} 
foo.bar "baz" 

のように私はそのような構文を持っているしたいと思いませんソリューションを持っています

foo.bar do |x| 
    puts "*" + x.to_s 
end 
foo.bar "baz" 

私は、次のコード

class Foo 
    def bar x = nil, &blk 
    if (block_given?) 
     @bar = blk 
    elsif (@bar.nil?) 
     puts x 
    else 
     @bar.call x 
    end 
    end 
end 

を思い付いた。しかし、これは複数のパラメータのためのちょっと醜いです、まだ「右」を感じることはありません。私はまた、set_barメソッドを定義することができますが、私はどちらか好きではありません:)。

class Foo 
    def bar x 
    if (@bar.nil?) 
     puts x 
    else 
     @bar.call x 
    end 
    end 

    def set_bar &blk 
    @bar = blk 
    end 
end 

そこで質問です:welldan97のアプローチの作品@ 、しかし、私は、ローカル変数のスコープ、すなわちを失う:より良い方法これを行うために行うそうでない場合、どのような方法あなたは

編集を好むがあります

prefix = "*" 
def foo.bar x 
    puts prefix + x.to_s 
end 

は機能しません。私はそれが働くためにラムダをしなければならないと思いますか?

答えて

11

使用def

foo = Foo.new 
foo.bar "baz" 

def foo.bar x 
    puts "*" + x.to_s 
end 

foo.bar "baz" 

はい、そのシンプル

編集:スコープを失うないためにあなたが(@freemanoidの答えのように)define_singleton_methodを使用することができます。

prefix = "*" 

foo.define_singleton_method(:bar) do |x| 
    puts prefix + x.to_s 
end 

foo.bar 'baz' 
+1

あまりにも簡単でしょう\ * facepalm \ * :) – kev

+0

hmm、私はローカル変数、すなわち 'prefix =" * "; def foo.bar x;接頭辞+ x.to_sを入れます。最後には動作しません:/ – kev

+0

@ welldan97、どうすれば "setter"メソッドを特定のオブジェクトに置き換えることができますか? – gaussblurinc

3

することができます次のようなものを実装してください:

class Foo; end 

foo = Foo.new 
prefix = '*' 
foo.send(:define_singleton_method, :bar, proc { |x| puts prefix + x.to_s }) 
foo.bar('baz') 
"*baz" <<<<<-- output 

これは絶対に正常であり、ルビーでは正しいです。

関連する問題