使用method_added ruby的堆栈级别太深



我已经创建了一个模块,在类中的方法调用之前挂接方法:

module Hooks
def self.included(base)
base.send :extend, ClassMethods
end

module ClassMethods
# everytime we add a method to the class we check if we must redifine it
def method_added(method)
if @hooker_before.present? && @methods_to_hook_before.include?(method)
hooked_method = instance_method(@hooker_before)
@methods_to_hook_before.each do |method_name|
begin
method_to_hook = instance_method(method_name)
rescue NameError => e
return
end
define_method(method_name) do |*args, &block|
hooked_method.bind(self).call
method_to_hook.bind(self).(*args, &block) ## your old code in the method of the class
end
end
end
end
def before(*methods_to_hooks, hookers)
@methods_to_hook_before = methods_to_hooks
@hooker_before = hookers[:call]
end
end
end

我把这个模块包括在我的一个班级里:

require_relative 'hooks'
class Block
include Indentation
include Hooks
attr_accessor :file, :indent
before :generate, call: :indent
# after  :generate, call: :write_end
def initialize(file, indent=nil)
self.file = file
self.indent = indent
end
def generate
yield
end
end

这个Block类是另一个类的父类,该类正在实现自己版本的generate方法,并且实际实现了该方法。

当我的代码运行时,method_add实际上是用method:generate作为某种无限循环中的参数调用的。我不明白为什么method_add会陷入这个无限循环。你知道这个代码出了什么问题吗?以下是完整代码的链接:github 上的代码链接

由于在method_added内部调用define_method,因此导致了无限递归。堆栈跟踪(不幸的是,您没有提供(应该显示这一点。

解决这个问题的一个有点难看的解决方法可能是显式地设置一个变量(例如@_adding_a_method(,并将其用作method_added:的保护子句

module ClassMethods
def method_added(method)
return if @_adding_a_method
if @hooker_before.present? && @methods_to_hook_before.include?(method)
# ...
@_adding_a_method = true
define_method(method_name) do |*args, &block|
# ...
end
@_adding_a_method = false
# ...
end
end
end

然而退一步说,我真的不确定这个模块想要实现什么。难道你不能用Module#prepend而不是这种元编程来实现这一点吗?

这段代码让我想起了您可能在旧的Ruby 1.8/1.9教程中找到的关于高级元编程技术的内容;Module#prepend在很大程度上使这种变通方法变得多余。

相关内容

  • 没有找到相关文章

最新更新