2011-12-26 28 views
6

Sau khi đọc bài viết http://jeffkreeftmeijer.com/2011/method-chaining-and-lazy-evaluation-in-ruby/, tôi bắt đầu tìm kiếm giải pháp tốt hơn cho phương pháp chuỗi và đánh giá lười biếng.Ruby Challenge - Phương pháp chuỗi và đánh giá lười biếng

Tôi nghĩ rằng tôi đã đóng gói vấn đề cốt lõi với năm thông số kỹ thuật bên dưới; bất cứ ai có thể có được tất cả đi qua?

Mọi thứ đều diễn ra: phân lớp, ủy quyền, lập trình meta, nhưng không được khuyến khích.

Nó sẽ là thuận lợi để giữ phụ thuộc ở mức tối thiểu:

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

Tại sao trên trái đất sẽ lập trình meta nản lòng? –

+0

Cách ngôn ngữ Ruby được thiết kế, tôi chắc chắn không có lớp nào vượt qua các thông số kỹ thuật trong khối 'it' đầu tiên của bạn và không thực hiện các phép thử trong khối' it' thứ hai trừ khi nó thực sự kỳ quái và sử dụng C mở rộng với một số móc thông dịch viên. Khối thứ hai là dư thừa. –

+0

Lý do duy nhất của tôi để ngăn cản MP là tôi không phải là một fan hâm mộ của nó, mặc dù một hạn chế phần nào tùy ý. Tôi không muốn sử dụng nó nếu có một giải pháp thực dụng mà không cần nó. – Chris

Trả lời

3

Trivial, phải không?

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 

Các tiêu chí to_s không thành công vì 1,9 đã thay đổi cách Array#to_s hoạt động. Thay đổi điều này để tương thích:

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

Tôi muốn bánh.

BTW - Lập trình meta đây sẽ cắt giảm kích thước mã và tăng tính linh hoạt rất nhiều:

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

Trong 'self.method_missing', bạn có thể thay thế tất cả ba dòng đơn giản bằng' new 1, message.to_s'. –

+0

Tôi đã thêm thông số bổ sung làm cho vấn đề chung quyết định hơn việc triển khai ban đầu của bạn. Sau này vẫn hoạt động, nhưng bạn có thể nhận được thông số kỹ thuật bổ sung đi qua (phương pháp còn thiếu)? – Chris

+1

@ChristopherPatuzzo: Tôi chắc chắn rằng bạn không thể làm một giải pháp chung mà không sử dụng 'method_missing', vì không có cơ chế nào khác mà tôi biết sẽ nắm bắt các thông điệp tùy ý. Bạn không thích điều này, đây chính là thứ 'method_missing' được tạo ra. – Amadan

5

này được lấy cảm hứng từ câu trả lời Amadan nhưng sử dụng ít dòng mã:

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

Tốt đẹp! Học điều mới mỗi ngày... – Amadan

Các vấn đề liên quan