2008-08-21 39 views
14

Ngoài tất cả self.class.send :method, args..., tất nhiên. Tôi muốn tạo ra một phương thức khá phức tạp có sẵn ở cả cấp độ lớp và thể hiện mà không cần sao chép mã.Có cách nào để gọi một phương thức Class riêng tư từ một cá thể trong Ruby không?


UPDATE:

@ Jonathan Branam: đó là giả định của tôi, nhưng tôi muốn chắc chắn rằng không ai khác đã tìm thấy một con đường xung quanh. Khả năng hiển thị trong Ruby rất khác so với trong Java. Bạn cũng có hoàn toàn đúng rằng private không hoạt động trên phương pháp lớp học, mặc dù điều này sẽ khai báo một phương thức lớp riêng:

class Foo 
    class <<self 
    private 
    def bar 
     puts 'bar' 
    end 
    end 
end 

Foo.bar 
# => NoMethodError: private method 'bar' called for Foo:Class 

Trả lời

11

Dưới đây là một đoạn mã để đi cùng với câu hỏi này. Sử dụng "private" trong một định nghĩa lớp không áp dụng cho các phương thức lớp. Bạn cần sử dụng "private_class_method" như trong ví dụ sau.

class Foo 
    def self.private_bar 
    # Complex logic goes here 
    puts "hi" 
    end 
    private_class_method :private_bar 
    class <<self 
    private 
    def another_private_bar 
     puts "bar" 
    end 
    end 
    public 
    def instance_bar 
    self.class.private_bar 
    end 
    def instance_bar2 
    self.class.another_private_bar 
    end 
end 

f=Foo.new 
f=instance_bar # NoMethodError: private method `private_bar' called for Foo:Class 
f=instance_bar2 # NoMethodError: private method `another_private_bar' called for Foo:Class 

Tôi không thấy cách nào để giải quyết vấn đề này. Tài liệu nói rằng bạn không thể chỉ định việc nhận một phương thức riêng. Ngoài ra, bạn chỉ có thể truy cập một phương thức riêng tư từ cùng một cá thể. Lớp Foo là một đối tượng khác với một thể hiện của Foo.

Đừng trả lời câu trả lời cuối cùng. Tôi chắc chắn không phải là một chuyên gia, nhưng tôi muốn cung cấp một đoạn mã để những người khác cố gắng trả lời sẽ có phương pháp lớp riêng tư đúng cách.

-1

Trừ khi tôi là sự hiểu lầm, bạn không chỉ cần một cái gì đó như thế này:

class Foo 
    private 
    def Foo.bar 
     # Complex logic goes here 
     puts "hi" 
    end 

    public 
    def bar 
     Foo.bar 
    end 
end 

Tất nhiên bạn có thể thay đổi định nghĩa thứ hai để sử dụng phương pháp self.class.send của bạn nếu bạn muốn tránh hardcoding tên lớp ...

0

Nếu phương pháp của bạn chỉ đơn thuần là utility function (nghĩa là, nó không dựa trên bất kỳ biến mẫu) nào, bạn có thể đặt phương thức vào mô-đun và includeextend lớp để nó có sẵn dưới dạng phương thức lớp riêng và một phương thức cá thể riêng.

0

Đây là cách để chơi bằng phương pháp lớp riêng "thực".

class Foo 
    def self.private_bar 
    # Complex logic goes here 
    puts "hi" 
    end 
    private_class_method :private_bar 
    class <<self 
    private 
    def another_private_bar 
     puts "bar" 
    end 
    end 
    public 
    def instance_bar 
    self.class.private_bar 
    end 
    def instance_bar2 
    self.class.another_private_bar 
    end 
    def calling_private_method 
    Foo.send :another_private_bar 
    self.class.send :private_bar 
    end 
end 
f=Foo.new 
f.send :calling_private_method 
# "bar" 
# "hi" 
Foo.send :another_private_bar 
# "bar" 

cổ vũ

+0

Nhận lỗi cho ví dụ đầu tiên: '1.9.3p327: 078> f = Foo.new => # 1.9.3p327: 079> f.class.send: calling_private_method NoMethodError: phương thức chưa xác định \ call_private_method 'cho Foo: Class từ (irb) : 79 từ ~/.rvm/rubies/ruby-1.9.3-p327/bin/irb: 16: in \ '

'' – TrinitronX

+0

Vâng, tính năng này không hoạt động (hoặc có thể không còn hoạt động). –

+0

Đã có lỗi đánh máy - cập nhật mã của tôi @JacobCrofts – metakungfu

3

Hãy để tôi đóng góp vào danh sách này của nhiều hay ít lạ giải pháp và phi giải pháp:

puts RUBY_VERSION # => 2.1.2 

class C 
    class << self 
    private def foo 
     'Je suis foo' 
    end 
    end 

    private define_method :foo, &method(:foo) 

    def bar 
    foo 
    end 
end 

puts C.new.bar # => Je suis foo 
puts C.new.foo # => NoMethodError 
+1

Khi yêu cầu bài đăng gốc, nó sẽ * gọi * phương thức lớp. Điều này không tốt vì nó sao chép phương thức vào tập các phương thức thể hiện của lớp. Nếu bạn, ví dụ, khỉ vá phương thức lớp C :: foo, bạn bỗng nhiên có hành vi không khớp giữa cấp độ lớp :: foo và cấp độ cá thể #foo. –

+0

Tôi nghĩ bạn đúng, cảm ơn. – Alexey

0

Ngày nay bạn không cần các phương pháp helper nữa. Bạn có thể chỉ đơn giản là nội tuyến chúng với định nghĩa phương thức của bạn. Điều này sẽ cảm thấy rất quen thuộc đối với những người Java:

class MyClass 

    private_class_method def self.my_private_method 
    puts "private class method" 
    end 

    private def my_private_method 
    puts "private instance method" 
    end 

end 

Và không, bạn không thể gọi phương thức lớp riêng tư từ phương pháp thể hiện. Tuy nhiên, thay vào đó, bạn có thể triển khai phương thức lớp riêng lẻ công khai phương thức lớp học trong một riêng lớp thay thế bằng cách sử dụng phương thức trợ giúp private_constant. Xem this blogpost để biết thêm chi tiết.

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