问题
In ruby, is there a way to define a method that is visible by every class in the file (or in the module), but not by files that require the file ?
Related, but not quite the same: can we redefine a method (for instance a method from a class of the standard library) such that this redefinition is visible only in the current file ? All other files should view the original definition.
回答1:
No and no.
The only visibilities in Ruby are public, protected, and private. There is no concept of file-level visibility. You could maybe "cheat" and and do something like this:
# In some file foobar.rb
class Foo
def to_bar
Bar.new.file_private
end
end
class Bar
def file_private
raise unless caller[0].split(':')[0] == __FILE__
end
end
# In IRB or some other file
Foo.new.to_bar #=> nil
Bar.new.file_private #=> RuntimeError
But this is a bad idea. A file of the same name in a different directory might work. It also isn't true visibility, but rather enforces it in the method itself.
Really, though, you should mostly have your classes each in their own file. It makes organization better. Further, you should not depend on public/protected/private. You can always just use send
to call a private method, but the above breaks that expectation. If user of your code really wants to do something with your code, there's next to nothing from letting them do it, that's the nature of dynamic languages. If you don't document a method, most users will never even know it's there anyway :P
.
As for your second question, there is no way to have two methods of the same name in the same class with different visibility, the second method will always overwrite the original. You could do something similar to what I've done above, and run different code depending on the condition instead of raising, but as above I don't really think this is a good idea.
回答2:
Define a new method in Object class(like an attribute). If you do not want to mess up the Object class, you can use another name, and Foo should inherit that class.
class Object @@file_only_methods = [] def file_only(method_name) method_name = method_name.to_sym new_method_name = "file_only_#{method_name}".to_sym self.send(:alias_method, new_method_name, method_name) self.send(:undef_method, method_name) self.send(:private, new_method_name) @@file_only_methods << method_name end def method_missing(method_name, *arg, &block) if @@file_only_methods.include? method_name if __FILE__ == $0 self.send("file_only_#{method_name}".to_sym,*arg,&block) else raise "Method #{method_name} is called outside the definition file." end else raise "Method #{method_name} does not exist." end end end class Foo def bar puts 'bar method' end file_only :bar end Foo.new.bar #output:bar method Foo.new.x #output:no method
In file2.rb,
require_relative 'file1' Foo.new.bar #output: Method bar is called outside the definition file.
来源:https://stackoverflow.com/questions/10535319/ruby-file-private-methods