2012-03-20 7 views
6

में किसी ऑब्जेक्ट पर गतिशील रूप से विधि कार्यान्वयन को प्रतिस्थापित करें, मैं किसी ऑब्जेक्ट के लिए किसी ऑब्जेक्ट के लिए किसी विधि के कार्यान्वयन को प्रतिस्थापित करना चाहता हूं जो उपयोगकर्ता निर्दिष्ट करता है। जावास्क्रिप्ट में, यह आसानी से पूरा किया है:रुबी

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") 

सी # में यह भी काफी आसान है

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"); 

लेकिन यह कैसे मैं रूबी में एक ही कर सकते हैं? मैं एक समाधान है कि एक उदाहरण चर में एक लैम्ब्डा संग्रहीत करता है और विधि लैम्ब्डा कॉल है, लेकिन मैं वास्तव में भूमि के ऊपर और वाक्य रचना पसंद नहीं

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" 

हाँ, इतना आसान

संपादित करें: गुंजाइश ढीला नहीं करने के लिए आप define_singleton_method उपयोग कर सकते हैं (@freemanoid जवाब के रूप में):

prefix = "*" 

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

foo.bar 'baz' 
+1

ओह ठीक है, यह संभवतः बहुत आसान \ * चेहरे का * \ :) :) – kev

+0

हम्म था, मैंने स्थानीय चर के दायरे को खोला, यानी 'prefix = "*"; def foo.bar x; उपसर्ग + x.to_s डालता है; अंत 'काम नहीं करता है:/ – kev

+0

@ welldan97, मैं विशिष्ट वस्तु के लिए विधि "सेटर" को कैसे बदल सकता हूं? – 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 

यह रूबी में बिल्कुल सामान्य और सही है।