Tôi đã viết giải pháp thống nhất hơn, nó có thể tìm ra phạm vi hiển thị của bất kỳ người gọi nào.
ý tưởng chính của tôi là xác định 2 điều:
- đối tượng người gọi (
self
ràng buộc của người gọi) tên
- phương pháp của đối tượng gọi
tôi đã sử dụng binding_of_caller đá quý để đạt được điều này.
class Foo
class << self
def visibility_scope
binding_of_caller = binding.of_caller(1)
caller_method = binding_of_caller.eval('__method__')
caller_object = binding_of_caller.eval('self')
# It's asking if caller is a module, since Class is inherited from Module
if caller_object.is_a?(Module)
return visibility_scope_for(caller_object.singleton_class, caller_method)
end
# First we should check object.singleton_class, since methods from there are called before
# class instance methods from object.class
visibility = visibility_scope_for(caller_object.singleton_class, caller_method)
return visibility if visibility
# Then we check instance methods, that are stored in object.class
visibility = visibility_scope_for(caller_object.class, caller_method)
return visibility if visibility
fail 'Visibility is undefined'
end
private
def visibility_scope_for(object, method_name)
%w(public protected private).each do |scope|
if object.send("#{scope}_method_defined?", method_name)
return scope
end
end
nil
end
end
end
Thêm một số phương pháp để kiểm tra:
class Foo
class << self
# This method is private in instance and public in class
def twin_method
visibility_scope
end
def class_public_method
visibility_scope
end
protected
def class_protected_method
visibility_scope
end
private
def class_private_method
visibility_scope
end
end
def instance_public_method
self.class.visibility_scope
end
protected
def instance_protected_method
self.class.visibility_scope
end
private
def twin_method
self.class.visibility_scope
end
def instance_private_method
self.class.visibility_scope
end
end
# singleton methods
foo = Foo.new
foo.singleton_class.class_eval do
def public_singleton_method
Foo.visibility_scope
end
protected
def protected_singleton_method
Foo.visibility_scope
end
private
def private_singleton_method
Foo.visibility_scope
end
end
class Bar
class << self
private
def class_private_method
Foo.visibility_scope
end
end
protected
def instance_protected_method
Foo.visibility_scope
end
end
thử nghiệm
# check ordinary method
Foo.class_public_method
=> "public"
Foo.send(:class_protected_method)
=> "protected"
Foo.send(:class_private_method)
=> "private"
Foo.new.instance_public_method
=> "public"
Foo.new.send(:instance_protected_method)
=> "protected"
Foo.new.send(:instance_private_method)
=> "private"
# check class and instance methods with the same name
Foo.twin_method
=> "public"
Foo.new.send(:twin_method)
=> "private"
# check methods from different objects
Bar.send(:class_private_method)
=> "private"
Bar.new.send(:instance_protected_method)
=> "protected"
# check singleton methods
foo.public_singleton_method
=> "public"
foo.send(:protected_singleton_method)
=> "protected"
foo.send(:private_singleton_method)
=> "private"
Nguồn
2015-04-19 19:56:00
Cuối cùng tôi tìm ra cách để thực hiện và thay đổi câu trả lời của mình –