2015-05-20 12 views
15

tôi có thể làm attr_reader (và attr_writerattr_accessor liên quan) phương pháp (s) tin bằng cách đặt các tuyên bố trong một phần private:Tại sao phương thức được ủy quyền là công khai khi được khai báo trong phần riêng tư?

class Foo 
private 
    attr_reader :b 
end 

Foo.new.b # => NoMethodError: private method `b' called for #<Foo:> 

Tuy nhiên, Rails' delegate và tiêu chuẩn thư viện của def_delegate của Ruby không làm việc này đường. Các phương thức được ủy quyền này luôn công khai.

class Foo 
    attr_reader :b 
    def initialize 
    @b = 'b' 
    end 
end 

require 'forwardable' 
class Bar 
    attr_reader :foo 
    def initialize 
    @foo = Foo.new 
    end 
    extend Forwardable 
private 
    def_delegator :foo, :b 
end 

Bar.new.b # => "b" 

Làm cho riêng phái đoàn có thể dễ dàng thực hiện bằng cách thay đổi nó để:

private def_delegator :foo, :b 

nhưng tôi mong đợi một lỗi NoMethodError cho Bar.new.b trên. Tại sao đoàn không phải là cá nhân?

Định nghĩa phương pháp def_delegator (bí danh cho def_instance_delegator) chỉ là rescue (khối loại bỏ):

def def_instance_delegator(accessor, method, ali = method) 
    line_no = __LINE__; str = %Q{ 
    def #{ali}(*args, &block) 
     #{accessor}.__send__(:#{method}, *args, &block) 
    end 
    } 
    module_eval(str, __FILE__, line_no) 
end 

Điều đó có nghĩa module_eval không tôn trọng điều đó nó được gọi trong một phần private. Tại sao?

Trả lời

4

Có, vấn đề là với module_eval vì nó đặt rõ ràng chế độ hiển thị công khai trước khi đánh giá chuỗi đã qua. Nó hoạt động theo cùng một cách trong CRuby và JRuby. Ví dụ: mã bị phân biệt đối với CRuby là ở hàm eval_under.

Như bạn đã tìm ra, khi bạn vượt qua def_delegate đến private, phương thức sẽ trở thành riêng tư. def_delegate đầu tiên định nghĩa phương thức đã được chuyển thành công khai (theo mô-đun cơ bản_eval), sau đó là đặt lại theo private để hiển thị riêng tư.

Không rõ 100% nếu hành vi hiện tại của Module.module_eval là đúng hoặc có lỗi trong Forwardable.def_instance_delegator. module_eval ví dụ trong hướng dẫn tài liệu để sử dụng nó bên ngoài lớp học có liên quan/mô-đun và nó không mong đợi đối số khả năng hiển thị vì vậy nó có vẻ hợp lý nó đặt khả năng hiển thị của phương thức công khai.

Các giải pháp sẽ là một trong hai Module.module_eval xử lý tùy chọn tham số tầm nhìn tôn trọng tầm nhìn hiện tại khi gửi đến ngầm hay rõ ràng self (nghi ngờ nếu có thể) hoặc sửa chữa Forwardable.def_instance_delegator thực hiện để xác định phương pháp thích hợp hơn với Module.define_method thay vì module_eval. Trong mọi trường hợp, đây là một ứng cử viên tốt để điền vào một báo cáo lỗi trên http://bugs.ruby-lang.org.

0

Tôi nghĩ rằng điều này là như nó là vụ phải làm việc. Tôi luôn xem xét rằng các công cụ sửa đổi hiển thị ảnh hưởng đến phạm vi mà chúng được viết và không phải bất kỳ cuộc gọi nào có nguồn gốc từ đó. Theo nghĩa này, lệnh gọi đến module_eval không biết rằng nó nằm trong phần riêng tư (có thể không?).

0

Dường như tùy chọn thứ hai hoạt động trong khi tùy chọn đầu tiên không phải do Rails đang nói "module_eval dòng cụ thể này". Vì vậy, khi bạn có riêng tư trên cùng một dòng nó hiểu rằng nó sẽ bắt đầu xử lý nó như là một định nghĩa phương pháp riêng. Điều này có vẻ giống như một cái gì đó nên được cố định bởi các nhà bảo trì Rails, tạo ra một vấn đề cho họ.

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