Reputation: 673
I am trying to figure out how to prevent inheritance of one method in all subclasses. Currently I am trying with such code:
class Mother
def phone
puts "#{self.class} phoned"
end
protected
def phone_kids
puts "phoned kids"
end
end
class Kid < Mother
end
But without any result, as I am getting such error: <top (required)>': protected method 'phone_kids' called for #<Mother:0x604da0> (NoMethodError)
. Could you please explain me briefly how inheritance in Ruby works?
Thanks in advance!
// EDIT:
I am getting this error with this code:
kid = Kid.new
mom = Mother.new
mom.phone_kids
Upvotes: 3
Views: 1776
Reputation: 73649
The difference between protected and private is subtle. If a method is protected, it may be called by any instance of the defining class or its subclasses. If a method is private, it may be called only within the context of the calling object---it is never possible to access another object instance's private methods directly, even if the object is of the same class as the caller. For protected methods, they are accessible from objects of the same class (or children).`
source: http://en.wikibooks.org/wiki/Ruby_Programming/Syntax/Classes#Declaring_Visibility
Upvotes: 1
Reputation: 376
In ruby, both private and protected methods can be use only in the class def. So you can't invoke a protected or private method outside:
class Mother
def phone
puts "#{self.class} phoned"
end
protected
def phone_kids
puts "phoned kids"
end
private
def anoter_phnoe_kids
puts "anoter phoned kids"
end
end
class Kid < Mother
def hey
phone_kids
anoter_phnoe_kids
end
end
Kid.new.phone #OK
Kid.new.phone_kids #protected method (NoMethodError)
Kid.new.anoter_phnoe_kids #private method (NoMethodError)
Kid.new.hey #OK
And here shows the difference between protected
and private
.
Upvotes: 1
Reputation: 87486
If you find yourself needing to do this, it probably means that you are not using inheritance correctly. If class C inherits from D, it should be an "is a" relationship: every C is a D. Since not every kid is a mother, your use of inheritance in this case is bad.
Here is how you might represent parents and kids in Ruby just using a single class:
class Person
attr_accessor :name
attr_accessor :children
def initialize(name)
@name = name
@children = []
end
def phone_kids
@children.each { |c| c.phone }
end
def phone
puts "#{@name} phoned"
end
end
Now, to answer the original question. If you want to prevent the Kid
class from inheriting the phone_kids
method, you could do something like this:
class Mother
def self.inherited(klass)
klass.send(:define_method, :phone_kids) do
raise NoMethodError
end
end
def phone_kids
puts "phoned kids"
end
end
class Kid < Mother
end
Mother.new.phone_kids # => phoned kids
Kid.new.phone_kids # => NoMethodError
Upvotes: 11