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

发布于 2024-11-29 19:17:11 字数 488 浏览 1 评论 0原文

可能的重复:
ruby:能给我一些东西吗就像 Class#inherited 一样,只有在类定义之后才会触发?

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

class B < A
  puts "YYY"
end

打印出来

XXX
YYY

我希望

YYY
XXX

如果我能以某种方式得到它。

Possible Duplicate:
ruby: can I have something like Class#inherited that's triggered only after the class definition?

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

class B < A
  puts "YYY"
end

prints out

XXX
YYY

I'd prefer

YYY
XXX

if I could get it somehow.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

爱的那么颓废 2024-12-06 19:17:11

您可以跟踪直到找到类定义的结尾。我用一个名为 after_inherited 的方法做到了这一点:

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

You can trace until you find the end of the class definition. I did it in a method which I called after_inherited:

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

Output:

YYY
XXX
懵少女 2024-12-06 19:17:11

这是不可能的。考虑一下:在 Ruby 中,什么时候应该将类定义视为“完成”?

我个人会创建一个名为 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

您可能可以通过创建一个包装函数来代替:

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

class B < A
  define_authors {
    author "Jason Harris"
    author "George Duncan"
  }
end

...或者确实考虑到在某些情况下可能不需要最终确定步骤。

This is not possible. Consider this: when should a class definition be considered "done" in Ruby?

Instead of self.inherited, I would personally make a class method called finalize! and put your post-class-creation routine in there.

# 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

You can probably get away with making a wrapper function instead:

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

class B < A
  define_authors {
    author "Jason Harris"
    author "George Duncan"
  }
end

...Or do consider that there may be ways where that finalizing step may not be needed.

丿*梦醉红颜 2024-12-06 19:17:11

AFAIK 没有这样的钩子。

解决方法可能是:

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

它看起来有点乱,但它的输出是:

YYY
XXX

这样你就可以保证 B 中的代码在 A 的 after_interited() 之前执行。所以它会执行你想要的操作,但不是按照你想要的方式执行。

There is no such hook AFAIK.

A workaround could be:

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

It looks a bit messy but its output is:

YYY
XXX

This way you guarantee that your code in B gets executed before the after_interited() of A. So it does what you want but not the way you want to it.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文