Ruby 在类的每个方法的开头插入代码

Ruby 在类的每个方法的开头插入代码,ruby,metaprogramming,Ruby,Metaprogramming,如何在不手动插入代码的情况下,动态地、轻松地将代码插入类和子类的每个方法的开头?我想要宏之类的东西 class C1 def m1 @i_am = __method__ end def m2 @i_am = __method__ end end 这是我希望避免重复的示例之一。假设函数相同,您可以创建一个模块并将其包含在类中 例如: module MyModule def test_method puts "abc" end en

如何在不手动插入代码的情况下,动态地、轻松地将代码插入类和子类的每个方法的开头?我想要宏之类的东西

class C1
   def m1
     @i_am = __method__
   end

   def m2
      @i_am = __method__
   end
 end

这是我希望避免重复的示例之一。

假设函数相同,您可以创建一个模块并将其包含在类中

例如:

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"

您可以使用类似于类装饰器的rails来实现这一点。下面的代码段正在呈现ActiveRecord模块基类中定义的一个名为
before\u action
的方法。测试类是从ActiveRecord继承的。如果我们想从基类显式调用某个对象,则使用
define\u方法

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

因此,在运行
render
方法之前,它会在
Base
类中运行
before\u action
方法。它可以应用于
测试
类中的所有其他方法。这是一种用ruby表示宏的方法

我最初误解了这个问题(但在下面的横线后面留下了我的原始答案)。我相信下面可能就是你想要的

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
而且是私人的;因此需要使用
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 
c=C1.new
#=> # 
C1.实例_方法(错误)
#=>[:m1,:m2,:将代码添加到\u开头]
c、 将代码添加到开头(:m1)do
“你好”
结束
C1.实例_方法(错误)
#=>[:m1,:m2,:将代码添加到开头,:旧代码\u m1]
c、 m1
#你好
#=>:m1

你的例子的意图不清楚。@sawa,不,不清楚。Ramano,提问者不适合确定读者是否清楚他们的问题。在这件事上,我和@sawa是一致的。@CarySwoveland,你错误地认为SO是唯一可以得到答案的地方。我完全不在乎你站在哪一边,不管是不是萨瓦。请在提问之前再复习一些问题。人们只会被标题误导,这比手动将相同的代码插入每个方法容易吗?这会在类中创建一个新的公共方法,我不希望这样。您希望“动态地…将代码插入每个方法的开头…”。在Ruby中,“动态”意味着在运行时做一些像C这样的静态语言只能在编译时做的事情,比如创建一个方法。这只能通过一种方法来实现,这就是我在回答中给你们的。我现在认为您只需要一种(非动态)方法来避免重复键入类似方法的繁琐(这也可能减少错误)。明天早上我会做一个编辑来解决这个问题。我修改了代码以解决我目前对你的问题的理解。
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
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