ruby - 获取类定义之上的所有实例方法
问题描述
我试图在调用实例方法之前和之后TestClass
包装所有实例方法以执行代码。到目前为止,此代码正在运行:
module Wrapper
def wrap(*methods)
prependable_module = Module.new do
methods.each do |m|
define_method(m) do |*args, &block|
p 1
super(*args, &block)
p 3
end
end
end
prepend prependable_module
end
end
class TestClass
extend Wrapper
wrap :instance_method1
def instance_method1
p 2
end
end
TestClass.new.instance_method1 # => 1, 2, 3
我可以wrap
使用所有方法名称作为参数调用。如果我尝试包装所有方法而不单独列出它们,我需要instance_methods(false)
在类定义的底部使用它来调用它。
class TestClass
extend Wrapper
def instance_method1
p 2
end
wrap(*instance_methods(false))
end
在 Rails 中,所有的回调方法都像before_action
orafter_create
通常在类定义之上调用。我的目标是也调用wrap
类定义(不单独列出所有方法)。在这种情况下,我不能instance_methods(false)
在类定义之上调用,因为此时还没有定义任何方法。
谢谢你的帮助!
更新
感谢Kimmo Lehto 的方法,我可以使用method_added
钩子包装每个实例方法。我不想为每个定义的方法添加一个新模块,所以我将所有重写的方法添加到同一个模块中。
module Wrapper
def method_added(method_name)
tmp_module = find_or_initialize_module
return if tmp_module.instance_methods(false).include?(method_name)
tmp_module.define_method(method_name) do |*args, &block|
p 1
super(*args, &block)
p 3
end
end
def find_or_initialize_module
module_name = "#{name}Wrapper"
module_idx = ancestors.map(&:to_s).index(module_name)
unless module_idx
prepend Object.const_set(module_name, Module.new)
return find_or_initialize_module
end
ancestors[module_idx]
end
end
class TestClass
extend Wrapper
def instance_method1
p 2
end
end
tc = TestClass.new
tc.instance_method1 # => 1, 2, 3
解决方案
您可以使用Module#method_added钩子自动包装添加的任何方法。
你需要一些魔法才能避免无限循环中的堆栈溢出。
另一种选择是在定义类后使用TracePoint触发包装。您可以使用Module#extended
来设置跟踪点。就像是:
module Finalizer
def self.extended(obj)
TracePoint.trace(:end) do |t|
if obj == t.self
obj.finalize
t.disable
end
end
end
def finalize
wrap(*instance_methods(false))
end
end
类通常不是完全“关闭”的,除非你明确地说明.freeze
它们,所以它有点笨拙的解决方案,如果之后添加方法也不会触发。method_added
可能是你最好的选择。
推荐阅读
- python - 如何从终端运行 python 脚本?
- swift - 在 SwiftUI 中使用自定义文本字段时出现内存泄漏
- python - 无法在 django 中使用 update_or_create 方法将数据发布到数据库
- java - 在 Hibernate 中处理 Session 和 SessionFactory 的最佳实践是什么?
- spring-boot - 如何将 Zuul 配置为 Eureka Service Mesh 的代理
- angular - 控制组件模板内的 routerLink
- javascript - 如何多次添加具有不同内容的相同 XML 标记?
- postgresql - 通过 ScalikeJDBC 处理来自 postgres byteEA 类型列的数据
- java - 如何在 Spring @Service 和非 Spring 对象之间集成?
- javascript - 我如何操作这些数据以使 UI - React Native 可以接受?