Search code examples
rubyaccess-specifier

Make instance methods private in runtime


I need to make some instance methods private after registering that object in another object.

I don't want to freeze the object because it must remain editable, only with less functionality. And I don't want to undef the methods since they are used internally.

What I need is something like:

class MyClass

  def my_method
    puts "Hello"
  end

end

a = MyClass.new
b = MyClass.new

a.my_method                            #=> "Hello"
a.private_instance_method(:my_method)
a.my_method                            #=> NoMethodError
b.my_method                            #=> "Hello"

Any ideas?


Solution

  • What's public and what's private is per class. But each object can have its own class:

    class Foo
    
      private
    
      def private_except_to_bar
        puts "foo"
      end
    
    end
    
    class Bar
    
      def initialize(foo)
        @foo = foo.dup
        class << @foo
          public :private_except_to_bar
        end
        @foo.private_except_to_bar
      end
    
    end
    
    foo = Foo.new
    Bar.new(foo)    # => "foo"
    
    foo.private_except_to_bar
    # => private method `private_except_to_bar' called for #<Foo:0xb7b7e550> (NoMethodError)
    

    But yuck. Consider these alternatives:

    • Just make the method public.
    • Explore alternative designs.