在Ruby中class_eval<< - “end_eval”,__ FILE __,_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

时间:2010-03-22 22:01:54

标签: ruby

我正在学习如何在模块中使用class_eval(我对class_eval有点熟悉)并遇到了this helpful class in resource_controller。在那里,他们有这样的事情:

class_eval <<-"end_eval", __FILE__, __LINE__

  def #{block_accessor}(*args, &block)
    unless args.empty? && block.nil?
      args.push block if block_given?
      @#{block_accessor} = [args].flatten
    end

    @#{block_accessor}
  end

end_eval

__FILE____LINE__在这种情况下做了什么?我知道__FILE__引用了当前文件,但整件事究竟做了什么?真的不知道如何搜索:)。

3 个答案:

答案 0 :(得分:53)

__FILE____LINE__是一种动态常量,用于保存当前正在执行的文件和行。将它们传递到此处可以使错误正确报告其位置。

instance_eval <<-end_eval, __FILE__, __LINE__
  def foo
    a = 123
    b = :abc
    a.send b
  end
end_eval

foo

当你运行这个

$ ruby foo.rb 
foo.rb:5:in `send': undefined method `abc' for 123:Fixnum (NoMethodError)
    from foo.rb:5:in `foo'
    from foo.rb:11

注意它表示文件和第5行,即使这只是eval中的文本。没有那些文件/行技巧,输出将如下所示:

$ ruby foo.rb 
(eval):5:in `send': undefined method `abc' for 123:Fixnum (NoMethodError)
    from (eval):5:in `foo'
    from foo.rb:11

堆栈跟踪只显示(eval),这没有用处。

答案 1 :(得分:4)

<<heredoc的开头。该行是多行字符串的开头。该字符串被唤醒以创建该函数。 class_eval函数使用__FILE__和__LINE__添加调试信息。

答案 2 :(得分:2)

我们还要注意,应尽可能避免eval - 字符串。在您的特定情况下,可以将#class_eval替换为#class_exec,并且应该首选:

class_exec do
  define_method block_accessor do |*args, &block|
    unless args.empty? && block.nil?
      args.push block if block_given?
      instance_variable_set "@#{block_accessor}", [args].flatten
    end
    instance_variable_get "@#{block_accessor}"
  end
end