2015-03-26 21 views
5

Refinements là một bổ sung thử nghiệm cho v2.0, sau đó được sửa đổi và được tạo vĩnh viễn trong phiên bản v2.1. Nó cung cấp một cách để tránh "khỉ vá" bằng cách cung cấp "một cách để mở rộng một lớp học tại địa phương".Sử dụng sàng lọc theo thứ bậc

Tôi đã cố gắng áp dụng Refinements-this recent question mà tôi sẽ đơn giản hóa như sau:

a = [[1, "a"], 
    [2, "b"], 
    [3, "c"], 
    [4, "d"]] 

b = [[1, "AA"], 
    [2, "B"], 
    [3, "C"], 
    [5, "D"]] 

Yếu tố tại offset i trong a phù hợp với phần tử ở bù đắp i trong b nếu:

a[i].first == b[i].first 

a[i].last.downcase == b[i].last.downcase 

Nói cách khác, sự phù hợp của các chuỗi là độc lập với trường hợp.

Vấn đề là xác định số phần tử của a khớp với phần tử tương ứng là b. Chúng tôi thấy rằng câu trả lời là hai, các phần tử ở các số offset 12.

Một cách để làm điều này là khỉ-vá String#==:

class String 
    alias :dbl_eql :== 
    def ==(other) 
    downcase.dbl_eql(other.downcase) 
    end 
end 

a.zip(b).count { |ae,be| ae.zip(be).all? { |aee,bee| aee==bee } } 
    #=> 2 

hoặc thay vì sử dụng Refinements:

module M 
    refine String do 
    alias :dbl_eql :== 
    def ==(other) 
     downcase.dbl_eql(other.downcase) 
    end 
    end 
end 

'a' == 'A' 
    #=> false (as expected) 
a.zip(b).count { |ae,be| ae.zip(be).all? { |aee,bee| aee==bee } } 
    #=> 0 (as expected) 

using M 
'a' == 'A' 
    #=> true 
a.zip(b).count { |ae,be| ae.zip(be).all? { |aee,bee| aee==bee } } 
    #=> 2 

Tuy nhiên, tôi muốn sử dụng Refinements như thế này:

using M 
a.zip(b).count { |ae,be| ae == be } 
    #=> 0 

nhưng, như bạn thấy, điều đó đưa ra câu trả lời sai. Đó là bởi vì tôi đang gọi Array#== và tinh chỉnh không áp dụng trong phạm vi Array.

tôi có thể làm điều này:

module N 
    refine Array do 
    def ==(other) 
     zip(other).all? do |ae,be| 
     case ae 
     when String 
      ae.downcase==be.downcase 
     else 
      ae==be 
     end 
     end 
    end 
    end 
end 

using N 
a.zip(b).count { |ae,be| ae == be } 
    #=> 2 

nhưng đó không phải là những gì tôi muốn. Tôi muốn làm một cái gì đó như thế này:

module N 
    refine Array do 
    using M 
    end 
end 

using N 
a.zip(b).count { |ae,be| ae == be } 
    #=> 0 

nhưng rõ ràng là không hoạt động.

Câu hỏi của tôi: có cách nào để tinh chỉnh String để sử dụng trong Array, sau đó tinh chỉnh Array để sử dụng trong phương pháp của tôi không?

Trả lời

1

Ồ, đây là thực sự thú vị để chơi cùng với! Cảm ơn bạn đã đặt câu hỏi này! Tôi đã tìm được cách hoạt động!

module M 
    refine String do 
    alias :dbl_eql :== 
     def ==(other) 
     downcase.dbl_eql(other.downcase) 
     end 
    end 

    refine Array do 
    def ==(other) 
     zip(other).all? {|x, y| x == y} 
    end 
    end 
end 

a = [[1, "a"], 
    [2, "b"], 
    [3, "c"], 
    [4, "d"]] 

b = [[1, "AA"], 
    [2, "B"], 
    [3, "C"], 
    [5, "D"]] 

using M 

a.zip(b).count { |ae,be| ae == be } # 2 

Không xác định lại == trong Array, sự tinh tế sẽ không được áp dụng.Thật thú vị, nó cũng không hoạt động nếu bạn làm điều đó trong hai mô-đun riêng biệt; này không làm việc, ví dụ:

module M 
    refine String do 
    alias :dbl_eql :== 
     def ==(other) 
     downcase.dbl_eql(other.downcase) 
     end 
    end 
end 

using M 

module N 
    refine Array do 
    def ==(other) 
     zip(other).all? {|x, y| x == y} 
    end 
    end 
end 

a = [[1, "a"], 
    [2, "b"], 
    [3, "c"], 
    [4, "d"]] 

b = [[1, "AA"], 
    [2, "B"], 
    [3, "C"], 
    [5, "D"]] 

using N 

a.zip(b).count { |ae,be| ae == be } # 0 

Tôi không đủ quen thuộc với các chi tiết thi hành refine để được hoàn toàn tự tin về việc tại sao hành vi này xảy ra. Tôi đoán là phần bên trong của một khối tinh chỉnh được xử lý như nhập một phạm vi cấp cao nhất, tương tự như cách các tinh chỉnh được xác định bên ngoài tệp hiện tại chỉ áp dụng nếu tệp được định nghĩa trong được phân tích cú pháp với require trong tệp hiện tại . Điều này cũng sẽ giải thích tại sao các cải tiến lồng nhau không hoạt động; nội thất tinh chỉnh đi ra khỏi phạm vi thời điểm nó thoát. Điều này sẽ cũng giải thích tại sao khỉ vá Array như sau tác phẩm:

class Array 
    using M 

    def ==(other) 
    zip(other).all? {|x, y| x == y} 
    end 
end 

này không rơi vào trạng thái các vấn đề Phạm vi mà refine tạo ra, vì vậy refine trên String trú trong phạm vi.

+0

Tuyệt vời! Một chi tiết: bạn có thể cân nhắc việc thay thế '! Self.zip (khác) .map {| x, y | x == y} .bao gồm? false' với 'zip (khác) .all? {| x, y | x == y} '. (Nhớ lại rằng 'self' là bộ thu mặc định.) –

+0

Ah, vâng, cảm ơn — Tôi đã có thói quen xấu khi sử dụng' self' ở mọi nơi có thể áp dụng. Điều này sẽ giúp tôi nhớ xem có sử dụng hay không. Nó trông đẹp hơn/dễ đọc hơn ở đây mà không có 'self' và sử dụng' tất cả? '. –

+0

Nhiều người Ruby sử dụng 'self' khi không cần thiết vì họ tin rằng sự thiếu sót của nó có thể gây nhầm lẫn cho người đọc. Tôi không ở trong trại đó, nhưng tôi không thể nói họ sai. –

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