在ruby中,如何在定义子类之后而不是之前触发继承的回调

在ruby中,如何在定义子类之后而不是之前触发继承的回调,ruby,metaprogramming,Ruby,Metaprogramming,可能重复: 我更喜欢 YYY XXX 如果我能设法得到它。没有这样的钩子 解决办法可以是: class A @@my_lambda = nil def self.inherited(child) @@my_lambda = lambda { puts "XXX" } end def self.after_inherited @@my_lambda.yield end end class B < A puts "YYY" # other d

可能重复:

我更喜欢

YYY
XXX

如果我能设法得到它。

没有这样的钩子

解决办法可以是:

class A
  @@my_lambda = nil
  def self.inherited(child)
    @@my_lambda = lambda { puts "XXX" }
  end

  def self.after_inherited
    @@my_lambda.yield
  end
end

class B < A
  puts "YYY"
  # other definitions
  self.superclass.after_inherited
end

通过这种方式,您可以保证B中的代码在A的after_interited()之前执行。因此,它可以执行您想要的操作,但不能按您想要的方式执行。

这是不可能的。考虑一下:在Ruby中什么时候应该定义一个类定义?< /P> 我将亲自创建一个名为
finalize!的类方法,而不是
self.inherited
并将您的类后创建例程放在其中

# A silly, contrived example

class A
  def self.author(person)
    @@authors ||= Array.new
    @@authors << person
  end

  def self.finalize!
    @@authors.map! { |a| Author[a] }
  end
end

class B < A
  author "Jason Harris"
  author "George Duncan"

  finalize!
end
#一个愚蠢、做作的例子
甲级
定义自我作者(个人)
@@authors | |=Array.new

@@作者您可以跟踪,直到找到类定义的结尾。我是用一种方法来做的,我在继承后调用了

class Class
  def after_inherited child = nil, &blk
    line_class = nil
    set_trace_func(lambda do |event, file, line, id, binding, classname|
      unless line_class
        # save the line of the inherited class entry
        line_class = line if event == 'class'
      else
        # check the end of inherited class
        if line == line_class && event == 'end'
          # if so, turn off the trace and call the block
          set_trace_func nil
          blk.call child
        end
      end
    end)
  end
end

# testing...

class A
  def self.inherited(child)
    after_inherited do
      puts "XXX"
    end
  end
end

class B < A
  puts "YYY"
  # .... code here can include class << self, etc.
end

问题特别是如何触发后继承回调。从子类显式调用回调实际上根本不是回调。您无法触发不存在的回调,但是…@mchl“这不可能”是一个有效答案。如果你创造了它,那么如果没有人能想出一个聪明的方法来解决这个问题,我会把它标记为正确的。上面的解决方案只是在B的类主体中写“puts'YYY';puts'XXX'”的一种迂回的方式。没有那么大的指导意义。@bradgonesurfing:我的解决方案只是一种变通方法。我以为你需要工作代码。你的问题是误导性的,你应该发布“是否有继承的…?”不,这不是误导性的。您刚刚将答案集中在将输出与示例进行匹配上,而实际上。。好吧,举个例子来说明什么之后会发生什么。刚才回答了同样的问题:。现在看看。看起来很有趣。明天早上我会详细检查的。我的特定用例是强制Subglass实现特定的方法。如果方法不存在,那么检查将导致类定义提前失败。我上面的例子没有详细说明这一点,但是define gem可能会提供我需要的钩子。谢谢。现在可以在Ruby中使用
TracePoint
来实现这一点。请看我对上述同一问题的回答。实际上,我对另一个类似问题()的回答可能更适合您的特定用例。看起来这是可能的。现在可以通过使用
TracePoint
在不安装任何gems的情况下完成。请看,这个解决方案在现代版本的Ruby中不再有效。使用
跟踪点
。看见
YYY
XXX
# A silly, contrived example

class A
  def self.author(person)
    @@authors ||= Array.new
    @@authors << person
  end

  def self.finalize!
    @@authors.map! { |a| Author[a] }
  end
end

class B < A
  author "Jason Harris"
  author "George Duncan"

  finalize!
end
class A
  def self.define_authors(&blk)
    yield
    # (...finalize here)
  end
  ...
end

class B < A
  define_authors {
    author "Jason Harris"
    author "George Duncan"
  }
end
class Class
  def after_inherited child = nil, &blk
    line_class = nil
    set_trace_func(lambda do |event, file, line, id, binding, classname|
      unless line_class
        # save the line of the inherited class entry
        line_class = line if event == 'class'
      else
        # check the end of inherited class
        if line == line_class && event == 'end'
          # if so, turn off the trace and call the block
          set_trace_func nil
          blk.call child
        end
      end
    end)
  end
end

# testing...

class A
  def self.inherited(child)
    after_inherited do
      puts "XXX"
    end
  end
end

class B < A
  puts "YYY"
  # .... code here can include class << self, etc.
end
YYY
XXX