【问题标题】:How to call super on dynamicly defined methods in sub-classes in Ruby?ruby - 如何在Ruby子类中的动态定义方法上调用super?
【发布时间】:2014-04-12 22:15:15
【问题描述】:

我有这个元编程场景,它涉及到 Ruby 的一些更精细的特性,我不太确定如何解决。

每个人都可以轻松地编写下面的示例来完成它应该做的事情,但是我需要在超类和派生的子类中动态定义方法。

在示例中,基类有一个动态定义的方法 :foo 并且当然它暴露给子类 B。 但是,当我在子类 B 的实例上调用 :foo 时,我在动态定义的方法中检测到它似乎无法将它从 B 类实例传递到 A 类实例,这当然是我想要的.

有点奇怪的 ruby​​ 也在子类中定义了方法,但无论如何,这就是我想要解决的问题。

有什么线索吗?

class A
  def self.some_method method,*_params
    puts "#{name}: defining #{method}"
    define_method method do |*args|
      puts "#{self.class.name}: called #{method}"
      super *args unless self.class.instance_methods(false).include?(method)
    end
  end
end

class B < A
end

A.some_method :foo

B.new.foo

输出

A: defining foo
B: called foo
NoMethodError: super: no superclass method `foo' for #<B:0x007f9eab85bfa0>

【问题讨论】:

  • 顺便说一句:我试图避免 method_missing。

标签: ruby exception metaprogramming


【解决方案1】:

我认为你的逻辑有缺陷。

您为超类A 定义动态方法。调用B.new.fooB 中找不到任何方法,因此它上升到继承线。它在A 中找到foo 方法,所以它使用那个。
这意味着

super *args unless self.class.instance_methods(false).include?(method)
部分根本不需要。

在我看来,经典的方法继承就是你所需要的!

【讨论】:

  • 那么一点点输入就足以让我意识到我的需要是知道什么类定义了访问超类类变量的方法,这可以很容易地完成:current = self.class; current = current.superclass while !current.instance_methods(false).include?(method) 感谢您轻推我的弹珠!
  • 我明白了...您是否考虑过为共享方法添加一个特殊模块而不是类继承?它可能被证明是一种更灵活的做事方式。
  • 是的,但我有一个非常细粒度的需求。 (看看可可宝石就知道了)。正如我们所说,重新定义架构。
【解决方案2】:

确实存在缺陷的逻辑。当然需要在哪里访问已定义方法的类,而 super 无法帮助您。

以下是问题的解决方法:

class A
  def self.some_method method,*_params
    puts "#{name}: defining #{method}"
    define_method method do |*args|
      puts "#{self.class.name}: called #{method}"

      klass = self.class
      klass = klass.superclass while !klass.instance_methods(false).include?(method)

      # klass is now where the instance method is defined
      # and you can now access its class variables etc.
      puts "#{klass.name}: has method #{method}"
    end
  end
end

class B < A
end

A.some_method :foo

B.new.foo

输出

A: defining foo
B: called foo
A: has method foo

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2012-07-04
    • 2017-01-19
    • 2018-06-28
    • 2013-07-01
    • 1970-01-01
    • 2019-07-20
    • 1970-01-01
    相关资源
    最近更新 更多