le_me
le_me

Reputation: 3419

Can method visibility be inherited in ruby?

Consider the following example in Ruby:

class ParentClass
  private def method
    puts "private method"
  end
end

class ChildClass < ParentClass
  def method
    puts "overridden, but should be private too"
  end
end

ParentClass.new.method #=> raises exception
ChildClass.new.method  #=> produces "overridden, but should be private too"

If I have no control over the code of ChildClass, is it possible to make it inherit method visibility from ParentClass?

Upvotes: 2

Views: 317

Answers (2)

sawa
sawa

Reputation: 168081

Your question has nothing to do with inheritance. What is relevant here is the timing of the class method private. See the simplified example below. When called, this method turns the relavant method existing at that point into a private method.

class A
  def foo; "foo1" end
  private :foo
  new.foo # => NoMethodError: private method `foo' called for #<A:0x007f321204fec0>
end

When you alter the method after private has applied, then a new method is defined with the same name, and the effect of private that applied to the previous definition is gone.

class A
  def foo; "foo2" end
  new.foo # => "foo2"
end

When you call private again on it, then it becomes private:

class A
  private :foo
  new.foo # => NoMethodError: private method `foo' called for #<A:0x007f3211ff6de8>
end

To illustrate this using your original example...

class ChildClass 
  private :method
end

... can be done after the initial definition of ChildClass and will make the method method private.

To summarize, visibility is a property of a (defined) method, not a property of a method name. So you cannot redefine a method but have the private status of a previous method with the same name but you can change the private status of the current method.

Upvotes: 4

Arup Rakshit
Arup Rakshit

Reputation: 118261

All objects, first prefer to their own defined methods, even if their parent classes has also the same named method. But if you really want in some ocaasion, to call the parent class method, then you can take a help from #class_eval for the same :

class ParentClass
  private
  def biz
    puts "private method"
  end
end

class ChildClass < ParentClass
  def biz
    puts "overridden, but should be private too"
  end
end

ChildClass.class_eval do
  remove_method :biz
  self.new.biz
end
# private method `biz' called for #<ChildClass:0x8c3532c> (NoMethodError)

Now, see ChildClass object is calling the private method from the ParentClass. Now to make the call successful, you need to use #send.

ChildClass.class_eval do
  remove_method :biz
  self.new.send :biz # => private method
end

Another way, I used in most cases is :-

unbind = ParentClass.instance_method(:biz)
unbind.bind(ChildClass.new).call # => private method

Really, when you do inherit or mixin, whatever methods are not physically don't come in to the child or mixed in class respectively. They(parent class or mixed in module) are actually added to the method lookup chain of the class ChildClass.

Upvotes: 1

Related Questions