2011-12-26 13 views
6

आलेख http://jeffkreeftmeijer.com/2011/method-chaining-and-lazy-evaluation-in-ruby/ लेख पढ़ने के बाद, मैंने विधि श्रृंखला और आलसी मूल्यांकन के लिए एक बेहतर समाधान की तलाश शुरू कर दी।रूबी चैलेंज - विधि चेनिंग और आलसी मूल्यांकन

मुझे लगता है कि मैंने नीचे पांच चश्मा के साथ मूल समस्या को समाहित किया है; क्या कोई उन्हें सब गुजर सकता है?

कुछ भी जाता है: सबक्लासिंग, प्रतिनिधिमंडल, मेटा प्रोग्रामिंग, लेकिन उत्तरार्द्ध के लिए निराश।

यह कम से कम निर्भरता रखने के लिए अनुकूल होगा:

require 'rspec' 

class Foo 
    # Epic code here 
end 

describe Foo do 

    it 'should return an array corresponding to the reverse of the method chain' do 
    # Why the reverse? So that we're forced to evaluate something 
    Foo.bar.baz.should == ['baz', 'bar'] 
    Foo.baz.bar.should == ['bar', 'baz'] 
    end 

    it 'should be able to chain a new method after initial evaluation' do 
    foobar = Foo.bar 
    foobar.baz.should == ['baz', 'bar'] 

    foobaz = Foo.baz 
    foobaz.bar.should == ['bar', 'baz'] 
    end 

    it 'should not mutate instance data on method calls' do 
    foobar = Foo.bar 
    foobar.baz 
    foobar.baz.should == ['baz', 'bar'] 
    end 

    it 'should behave as an array as much as possible' do 
    Foo.bar.baz.map(&:upcase).should == ['BAZ', 'BAR'] 

    Foo.baz.bar.join.should == 'barbaz' 

    Foo.bar.baz.inject do |acc, str| 
     acc << acc << str 
    end.should == 'bazbazbar' 

    # === There will be cake! === 
    # Foo.ancestors.should include Array 
    # Foo.new.should == [] 
    # Foo.new.methods.should_not include 'method_missing' 
    end 

    it "should be a general solution to the problem I'm hoping to solve" do 
    Foo.bar.baz.quux.rab.zab.xuuq.should == ['xuuq', 'zab', 'rab', 'quux', 'baz', 'bar'] 
    Foo.xuuq.zab.rab.quux.baz.bar.should == ['bar', 'baz', 'quux', 'rab', 'zab', 'xuuq'] 
    foobarbaz = Foo.bar.baz 
    foobarbazquux = foobarbaz.quux 
    foobarbazquuxxuuq = foobarbazquux.xuuq 
    foobarbazquuxzab = foobarbazquux.zab 

    foobarbaz.should == ['baz', 'bar'] 
    foobarbazquux.should == ['quux', 'baz', 'bar'] 
    foobarbazquuxxuuq.should == ['xuuq', 'quux', 'baz', 'bar'] 
    foobarbazquuxzab.should == ['zab', 'quux', 'baz', 'bar'] 
    end 

end 
+3

क्यों पृथ्वी पर metaprogramming हैं निराश हो जाओ? –

+0

जिस तरह से रूबी भाषा डिज़ाइन की गई है, मुझे पूरा यकीन है कि कोई कक्षा नहीं है जो आपके पहले 'इसे' ब्लॉक में चश्मा पास करेगी और आपके दूसरे 'यह' ब्लॉक में परीक्षण विफल करेगी जब तक यह वास्तव में अजीब न हो और सी का उपयोग न करे कुछ दुभाषिया हुक के साथ विस्तार। दूसरा ब्लॉक अनावश्यक है। –

+0

एमपी को हतोत्साहित करने का मेरा एकमात्र कारण यह है कि मैं कुछ प्रशंसनीय प्रतिबंध के बावजूद इसका प्रशंसक नहीं हूं। यदि कोई व्यावहारिक समाधान है तो इसकी आवश्यकता नहीं है, तो मैं इसका उपयोग नहीं करना चाहूंगा। – Chris

उत्तर

3

तुच्छ, है ना?

class Foo < Array 
    def self.bar 
    other = new 
    other << 'bar' 
    other 
    end 
    def self.baz 
    other = new 
    other << 'baz' 
    other 
    end 
    def bar 
    other = clone 
    other.unshift 'bar' 
    other 
    end 
    def baz 
    other = clone 
    other.unshift 'baz' 
    other 
    end 
end 

to_s कसौटी में विफल रहता है क्योंकि 1.9 रास्ता Array#to_s काम करता है बदल गया है। संगतता के लिए इसे बदलें:

Foo.baz.bar.to_s.should == ['bar', 'baz'].to_s 

मुझे केक चाहिए।

Btw - यहाँ metaprogramming कोड आकार में कटौती और काफी लचीलापन बढ़ जाएगी:

class Foo < Array 
    def self.method_missing(message, *args) 
    other = new 
    other << message.to_s 
    other 
    end 
    def method_missing(message, *args) 
    other = clone 
    other.unshift message.to_s 
    other 
    end 
end 
+0

'self.method_missing' में, आप बस तीन नई लाइनों को' नया 1, message.to_s' के साथ बदल सकते हैं। –

+0

मैंने एक अतिरिक्त स्पेस जोड़ा जो समस्या को आपके प्रारंभिक कार्यान्वयन से अधिक सामान्य निर्णय लेता है। उत्तरार्द्ध अभी भी काम करता है, लेकिन क्या आप अतिरिक्त चश्मा पास कर सकते हैं (विधि गायब हो)? – Chris

+1

@ क्रिस्टोफरपाटज़ो: मैं निश्चित रूप से निश्चित हूं कि आप 'method_missing' का उपयोग किए बिना एक सामान्य समाधान नहीं कर सकते हैं, क्योंकि कोई अन्य तंत्र नहीं है जिसके बारे में मुझे पता है कि मनमाने ढंग से संदेश प्राप्त होंगे। आपका नापसंद एक तरफ, यह वही बात है जो 'method_missing' के लिए बनाई गई है। – Amadan

5

यह Amadan के जवाब से प्रेरित है लेकिन कोड के कम लाइनों का उपयोग करता है:

class Foo < Array 
    def self.method_missing(message, *args) 
     new 1, message.to_s 
    end 
    def method_missing(message, *args) 
     dup.unshift message.to_s 
    end 
end 
+0

अच्छा! प्रति दिन कुछ नया सीखें... – Amadan