Как обнаружить переопределенные методы в Ruby / Rails? - PullRequest
2 голосов
/ 17 ноября 2010

Привет, ребята. Как узнать методы, которые дочерний класс переопределил в моем суперклассе? У меня есть это:


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

Метод self.inherited вызывается при загрузке подкласса Test. Поэтому я получаю ссылку на этот подкласс в child, но я не знаю, как получить методы, которые были переопределены этим подклассом.

Есть идеи?

-

Арсен предложил использовать self.method_added (name) вместо self.inherited (child), но этот метод перехватывает только методы экземпляра, и я хочу перехватить методы класса. Кто-нибудь знает другие методы, которые делают то же самое, но с методами класса? В последнем случае я рассмотрю возможность использования синглтона и преобразования всех методов этого класса в методы экземпляра, после чего проблема решена.

Ответы [ 3 ]

2 голосов
/ 17 ноября 2010

Для методов экземпляра существует метод Object::method_added(name), который вы можете переопределить, аналогично используемому вами «унаследованному»:

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

Затем вы можете сравнить полученное имя со списком ваших методов:

Test.instance_methods.include?(name.to_s)

При использовании методов класса этот подход не работает (даже если вы делаете такие вещи, как class << self магия), но помощник знал ответ: http://www.ruby -forum.com / topic /120416 :

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

Это только первая часть проблемы, потому что вам нужно знать, какой класс определил метод (он будет сам) и является ли метод новым, илипереопределенныйЭксперимент с этим кодом:

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 голосов
/ 17 ноября 2010
def overridden_methods
  klass = self.class
  klass.instance_methods.select {|m| klass.instance_method(m).owner == klass}
end

Изменение в соответствии с вашими потребностями.

0 голосов
/ 17 ноября 2010

Может быть, первый шаг к решению:

Вызвав child.instance_method(:bar) (если child относится к классу) или child.method(:bar) (если он относится к экземпляру Child), вы можете получить объект UnboundMethod или Method, представляющий ваш метод:

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

К сожалению, a == b оценивается как ложное, хотя оба ссылаются на один и тот же метод.

...