ruby - 堆栈级别太深,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_added 实际上是在某种无限循环中使用 method :generate 作为参数调用的。我不明白为什么 method_added 会陷入这个无限循环。你知道这段代码有什么问题吗?这是完整代码的 链接:github上的代码链接
解决方案
你已经引起了无限递归,因为你在define_method
里面打电话method_added
。堆栈跟踪(很遗憾您没有提供)应该显示这一点。
解决此问题的一个稍微难看的解决方法可能是显式设置一个变量(例如@_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
在大多数情况下,使此类变通办法变得多余。
推荐阅读
- node.js - 在nodejs中限制对cassandra db的并行请求数量
- python - 如何将列转换为日期时间忽略晦涩的字符串值
- r - 确定非平稳时间序列的 ARIMA 频率
- shell - 在csv的特定列中用空字符串替换连字符
- laravel-5 - 在 Laravel 5.7 中保存后从数据透视表中获取数据
- elasticsearch - 我正试图将头绕在elasticsearch dsl下方。有人能告诉我下面是如何使用“must”子句的吗
- node.js - 如何将变量从一个ejs传递到节点js中的另一个ejs
- java - 如何在android studio中更改图像文件名?
- php - 如何使用 google-api-php-client 获取 Android 应用程序的评论
- php - Laravel composer.json 完全安装