Ruby 在运行时将一行代码注入现有方法

Ruby 在运行时将一行代码注入现有方法,ruby,Ruby,在运行时,我想在Ruby v2.0之前的-中注入一行代码,在对原始的a#some_方法进行别名处理后,重新定义a#some_方法 class A def some_method(a, b, c) puts a puts b puts c end end A.prepend M 但是,更好的方法是在模块中定义新方法A#some_方法,然后将该模块定义到类Aprepend在Ruby v2.0中首次亮相 module M def some_method(a,b,

在运行时,我想在Ruby v2.0之前的-
中注入一行代码,在对原始的
a#some_方法
进行别名处理后,重新定义
a#some_方法

class A
  def some_method(a, b, c)
    puts a
    puts b
    puts c
  end
end
A.prepend M
但是,更好的方法是在模块中定义新方法
A#some_方法
,然后将该模块定义到类
A
prepend
在Ruby v2.0中首次亮相

module M
  def some_method(a,b,c)
    puts "a=#{a}, b=#{b}, c=#{c}"
    super
  end
end
A.prepend M
A.prepend M
给出了
M
优先于
A
的方法

A.prepend M
A.ancestors
  #=> [M, A, Object, Kernel, BasicObject]
说明了这种情况,并解释了
super
在方法
M#some_方法中的作用

class A
  def some_method(a, b, c)
    puts a
    puts b
    puts c
  end
end
A.prepend M
我之所以需要它,是因为我可以使用Ruby Tracepoint类来提取有关方法签名的一些运行时信息

特别是b=1和d:1中的默认参数值

TracePoint
允许您在不修补方法的情况下获取信息。您只需设置一个
:调用
钩子,然后调用该方法:

A.prepend M
TracePoint.trace(:call) do |tp|
  tp.parameters.each do |type, name|
    value = tp.binding.local_variable_get(name)
    puts format('%8s: %s = %s', type, name, value.inspect)
  end
end

A.new.some_method(123)
输出:(省略方法的输出)

req:a=123
A.prepend M
选项:b=1 rest:c=[] 关键字:d=1 keyrest:e={}
您是否能够在模块中定义这些方法?如果是这样,那么您也可以在类中简单地重新定义它们,并且可以对它们调用super,这样您就可以:(i)添加注入,然后保留方法在模型中要执行的功能。或者,你可以重命名这些方法,然后添加注入吗?再次感谢Stefan(连续两天),这正是我所需要的。我刚刚添加了
下一步,除非tp.self.is_a?(a)
,以消除噪音。感谢Cary提供的信息,不幸的是,这对我的用例不起作用,因为我无法访问代码进行更改,其想法是反向工程来自GEMs和其他我可能无法轻松访问的代码的签名。
A.prepend M