如何动态轻松地将代码插入到类和子类的每个方法的开头,而无需实际插入它?我想要像宏一样的东西。
class C1
def m1
@i_am = __method__
end
def m2
@i_am = __method__
end
end
这是我想避免重复的例子之一。
答案 0 :(得分:1)
我最初误解了这个问题(但在下面的水平线之后留下了原来的答案)。我相信以下可能就是你要找的东西。
class C1
[:m1, :m2].each do |m|
define_method(m) do |name|
@i_am = __method__
puts "I'm #{name} from method #{@i_am}"
end
end
end
C1.instance_methods(false)
#=> [:m1, :m2]
c1 = C1.new
#=> #<C1:0x007f94a10c0b60>
c1.m1 "Bob"
# I'm Bob from method m1
c1.m2 "Lucy"
# I'm Lucy from method m2
我的原始解决方案如下。
class C1
def add_code_to_beginning(meth)
meth = meth.to_sym
self.class.send(:alias_method, "old_#{meth}".to_sym, meth)
self.class.send(:define_method, meth) do
yield
send("old_#{meth}".to_sym)
end
end
end
Module#alias_method
Module#define_method是私人的;因此需要使用send
。
c = C1.new
#=> #<C1:0x007ff5e3023650>
C1.instance_methods(false)
#=> [:m1, :m2, :add_code_to_beginning]
c.add_code_to_beginning(:m1) do
puts "hiya"
end
C1.instance_methods(false)
#=> [:m1, :m2, :add_code_to_beginning, :old_m1]
c.m1
# hiya
#=> :m1
答案 1 :(得分:0)
你可以使用像类装饰器这样的轨道。下面的代码段是渲染一个名为before_action
的方法,该方法在ActiveRecord模块的Base类中定义。 Test类继承自ActiveRecord。如果我们想要从Base类中显式调用某些内容,则使用define_method
。
module ActiveRecord
class Base
def self.before_action(name)
puts "#{name}"
puts "inside before_action of class Base"
define_method(name) do
puts "Base: rendering code from Base class"
end
end
end
end
class Test < ActiveRecord::Base
before_action :hola
def render()
puts "inside render of class Test"
end
end
test = Test.new
test.render
test.hola
它有输出
hola
inside before_action of class Base
inside render of class Test
Base: rendering code from Base class
因此,在运行render
方法之前,它会在before_action
类中运行Base
方法。它可以应用于Test
类中的所有其他方法。这是一种在ruby中表示宏的方法。
答案 2 :(得分:-1)
假设函数相同,您可以创建一个模块并将其包含在您的类中。
示例:
module MyModule
def test_method
puts "abc"
end
end
class MyClass
include MyModule
def my_method
puts "my method"
end
end
inst = MyClass.new
inst.test_method # => should print "abc"
inst.my_method # => should print "my method"