Search code examples
rubyvisibility

ruby - File-private methods


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.


Solution

  • 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.