3
votes

Hey guys. How do I know the methods that a child class overrided in my super class? I have this:


class Test
  def self.inherited(child)
    # child.overrided_methods???
  end

  def self.foo
  end

  def self.bar
  end
end

def Child < Test
  def self.bar
    puts "bar"
  end
end

The method self.inherited is called when a subclass of Test is loaded. So I get the reference to this subclass in child, but I don't know how to get the methods that were overrided by this subclass.

Any ideas?

--

Arsen suggested the use of self.method_added(name) instead of self.inherited(child), but this method catches only instance methods and I want to catch class methods. Does anyone know another methods that does the same thing but with class methods? In the last case I'll consider using a singleton and convert all this class methods to instance methods then the problem is solved.

3
To clarify: are you trying to call Child's methods from Test?Reese Moore
Yes. I want to know what methods Child overrided. They are all class methods and child variable is a reference to the class Child.Rodrigo Souto
How about the simplest approach: "Child.methods(false) & Test.methods(false)"? The problem is: when do you want to call it? 'Inherited' is called too early.Arsen7
Ok, I have found the solution. My answer is undeleted and updated. I hope I didn't mess anything this time ;-)Arsen7

3 Answers

2
votes

For instance methods there is an Object::method_added(name) method you can override, similar to 'inherited' you have used:

class test
  def self.method_added(name)
    puts "method_added(#{name.inspect})"
    super
  end
end

irb(main):002:0> class Child < Test; def foo; end; end
method_added(:foo)
=> nil

You can then compare a received name to a list of your methods:

Test.instance_methods.include?(name.to_s)

With class methods this approach does not work (even if you do things like class << self magic), but a helpful fellow knew the answer: http://www.ruby-forum.com/topic/120416 :

class Test
  def self.singleton_method_added(name)
    puts "Class method added #{name.inspect}"
  end
end

This is only the first part of the problem, because you need to know which class defined the method (it will be self) and whether the method is a new one, or overridden one. Experiment with this code:

class Test
  def self.singleton_method_added(name)
    if self == Test
      puts "My own class method added: #{self.name}.#{name.inspect}"
    elsif Test.methods(false).include?(name.to_s)
      puts "Class method overriden: #{self.name}.#{name.inspect}"
    elsif Test.methods(true).include?(name.to_s)
      puts "My parent's class method overriden: #{self.name}.#{name.inspect}"
    else
      puts "New class method added: #{self.name}.#{name.inspect}"
    end
  end
end
0
votes

Maybe a first step to the solution:

By calling child.instance_method(:bar) (if child refers to the class) or child.method(:bar) (if it refers to an instance of Child) you can get an UnboundMethod or Method object representing your method:

a = Test.instance_method(:foo)
b = Child.instance_method(:foo)

Unfortunately, a == b evaluates to false, although both refer to the same method.

0
votes
def overridden_methods
  klass = self.class
  klass.instance_methods.select {|m| klass.instance_method(m).owner == klass}
end

Change according to your needs.