我尝试编写一个元编程来执行一个方法,然后才能掌握'方法。为什么?因为,我有几个课程,并且在method
案例:
class MyClass
include MySuperModule
before :method, call: before_method
def before_method
puts "Before.."
end
end
class SomeClass < MyClass
def method
puts "Method.."
end
end
module MySuperModule
# the awesome code
end
输出:
SomeClass.new.method => "Before.. Method.."
因此,我尝试使用ClassMethods
或method_missing
编写模块但未成功。
答案 0 :(得分:5)
你不需要像这样的简单元编程宝石。你可以做的是重新定义&#34;&#34;&#34; &#34;之前调用&#34;的方法方法然后原来&#34;之后&#34;方法
即使在同一方法上多次使用before
或创建一系列before
来电时,此功能仍然有用。
module MySuperModule
def before meth, opts
old_method = instance_method(meth)
define_method(meth) do
send opts[:call]
old_method.bind(self).call
end
end
end
class MyClass
extend MySuperModule
def foo
puts "foo"
end
def bar
puts "bar"
end
def baz
puts "baz"
end
before :foo, call: :bar
before :bar, call: :baz
end
MyClass.new.foo
# baz
# bar
# foo
答案 1 :(得分:1)
如果仅用于子类化,您可以利用Module#prepend
:
class Superclass
def self.inherited(subclass)
# subclass.send :prepend, Module.new { on Ruby < 2.1
subclass.prepend Module.new {
def method
before_method
super
end
}
end
def before_method
puts 'Before'
end
end
class Subclass < Superclass
def method
puts 'Method'
end
end
Subclass.new.method
#=> Before
#=> Method
答案 2 :(得分:0)
您正在寻找的是Aspect oriented programming对红宝石的支持。有几个宝石实现了这一点,比如aquarium。
答案 3 :(得分:0)
另一种方法是使用rcapture gem。 非常棒。
例如:
require 'rcapture'
class A
# Makes the class intercept able
include RCapture::Interceptable
def first
puts 'first'
end
def second
puts 'second'
end
end
# injects methods to be called before each specified instance method.
A.capture_pre :methods => [:first, :second] do
puts "hello"
end
n = A.new
n.first
n.second
产生
hello
first
hello
second
答案 4 :(得分:0)
也许你可以使用装饰器。在红宝石中有一种叫做“褶皱”的漂亮宝石。见Drapper Link
答案 5 :(得分:-1)
ruby中的每个调用都会运行set_trace_func
,因此您可以挂钩并调用您想要的内容。不是最漂亮的解决方案,有更好的方法,但它确实有效。另一种选择是Hooks gem,虽然我自己没有尝试过,看起来它应该让你有能力做你想做的事。
module MySuperModule
# the awesome code
end
class MyClass
include MySuperModule
def before_method
puts "Before.."
end
end
class SomeClass < MyClass
def method
puts "Method.."
end
end
set_trace_func proc { |event, file, line, id, binding, class_name|
if event == "call" && class_name == SomeClass && id == :method
caller = binding.eval("self")
caller.send(:before_method)
end
}
SomeClass.new.method
#=> Before..
#=> Method..