元编程:输出方法体作为文本

时间:2010-07-10 19:50:26

标签: ruby metaprogramming

我正在动态定义一个模块中的方法,并且我想检查一旦该方法绑定到一个类实例,该方法的主体就是我所期望的。有没有办法输出(作为文本)方法的主体?

模块controller_mixins.rb

module ControllerMixin

  instance_eval "def search_by_vendor (*args) \n" \
    " @#{self.class.name.sub(/Controller/, '').tableize} = #{self.class.name.sub(/Controller/, '')}.find_all_by_vendor_id(params[:vendor_id])  \n"\
    "respond_to do |format| \n" \
    " format.html { render :template=>'/#{self.class.name.sub(/Controller/, '').tableize}/index',  :layout=>'vendor_info'} \n" \
    " format.xml  { render :xml => @#{self.class.name.sub(/Controller/, '').tableize} } \n" \
    "end \n"\
  "end \n"

end

课程与:

混合
class VendorOrdersController < ApplicationController
  # GET /vendor_orders
  # GET /vendor_orders.xml
  require 'controller_mixins'
  include ControllerMixin
 <rest of class>

因此,我希望在应用于VendorOrdersController时看到mixin的实现 为方便起见,可能是通过script/console

更新:Per @~ /我将字符串保存到变量puts'。这非常有效。这揭示了我的代码中的错误(我想首先看到代码的原因)。下面的代码要好得多,并按预期工作。

module ControllerMixin

  def self.included(mod)
     method_body = "def search_by_vendor \n" \
      " @#{mod.name.sub(/Controller/, '').tableize} = #{mod.name.sub(/Controller/, '')}.find_all_by_vendor_id(params[:vendor_id])  \n"\
      "respond_to do |format| \n" \
      " format.html { render :template=>'/#{mod.name.sub(/Controller/, '').tableize}/index',  :layout=>'vendor_info'} \n" \
      " format.xml  { render :xml => @#{mod.name.sub(/Controller/, '').tableize} } \n" \
      "end \n"\
    "end \n" 

    puts method_body
    mod.class_eval(method_body)
  end

end

4 个答案:

答案 0 :(得分:5)

不,你无法获得方法背后的源代码。

您可以做的最好的事情是使用Method获取代表该方法的Object#method对象。例如:

m = VendorOrdersController.method(:search_by_vendor)

但你会发现只有Method#nameMethod#arityMethod#source_location等等。

但是,在您的情况下,为什么不在使用instance_eval之前将字符串存储在变量中,打印它?

无论如何,您的instance_eval将在模块声明时执行。您可能希望将其包装在included回调中,以便在包含时执行它。

module ControllerMixin
  def self.included(mod)
    mod.instance_eval([...])
  end
end

答案 1 :(得分:2)

确保您获得预期输出的最佳方法是编写测试。

另外 - 我不赞成像这样使用instance_eval。如果你必须使用这样的元编程,使用define_method,或者你可以通过从路径传递一个参数而不做任何操作就可以逃脱,当然,这是一个更多的打字,但是那么多的元编程只是icky。 / p>

答案 2 :(得分:2)

在instance_eval运行之前,是否无法将字符串分配给变量并将其输出到控制台?

由于您的字符串定义了整个方法,因此您基本上已经拥有了源代码。

答案 3 :(得分:0)

如上面的答案所说,做你想做的最好的方法是使用define_method。

如果有人在寻找“元编程:输出方法体作为文本”,请尝试:

如果您想获取课程或方法的代码,请查看ParseTreeruby2ruby

ParseTree可以抓取类或方法的抽象语法树并生成“符号表达式”,如lisp,它看起来像是符号列表的列表,并且非常有趣。

ruby​​2ruby将这些s-exps变成普通的红宝石。

警告,ParseTree目前不适用于ruby 1.9。