2011-12-26 4 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

왜 메타 프로그래밍 것을 낙담 할까? –

+0

Ruby 언어가 설계된 방식으로, 첫 번째'it' 블록에 스펙을 전달할 클래스가없고 두 번째'it' 블록에서 테스트를 실패하는 클래스가 없다는 것을 확신합니다. 실제로는 정말 이상하고 C 일부 인터프리터 후크가있는 확장. 두 번째 블록은 중복됩니다. –

+0

MP를 낙담시키는 유일한 이유는 다소 임의적 인 제한 임에도 불구하고 나는 그 팬이 아닙니다. 나는 그것을 필요로하지 않는 실용적인 해결책이 있다면 그것을 사용하지 않을 것입니다. – Chris

답변

3

사소한를, 그렇지? 1.9 방법 Array#to_s 작품 변경 되었기 때문에

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 기준은 실패한다. 호환성을 위해 다음으로 변경하십시오.

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

케이크를 원합니다.

BTW - 여기 메타 프로그래밍은 코드 크기를 줄일 것이며 엄청난 유연성을 증가 :이 Amadan의 대답에 의해 영감을

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'에서 세 줄을 모두'new 1, message.to_s'로 바꿀 수 있습니다. –

+0

추가 사양을 추가하여 문제를보다 일반적으로 초기 구현을 배제했습니다. 후자는 여전히 작동하지만 추가 사양을 전달할 수 있습니까 (메서드 누락)? – Chris

+1

@ChristopherPatuzzo : 나는'method_missing'을 사용하지 않고 일반적인 해결책을 찾을 수 없다는 것을 확신합니다. 왜냐하면 임의의 메시지를 잡아낼 수있는 다른 메커니즘이 없기 때문입니다. 당신의 싫어하는 점은, 이것은 정확히'method_missing'이 만들어 낸 것입니다. – Amadan

5

을하지만 적은 코드 사용

지구에
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