2010-03-22 75 views
40

我正在學習如何在模塊中使用class_eval(我對class_eval有點熟悉),並且遇到了this helpful class in resource_controller。在那裏,他們有這樣的事情:在Ruby中,class_eval << - 「end_eval」,__FILE__,__LINE__是什麼意思?

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__引用當前文件,但是整個事情究竟做了什麼?真的不知道如何搜索:)。

回答

50

__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

這可能是很好的一提的是使用'define_method'反而不會需要這種招數,加它不會打開漏洞(請參閱http://stackoverflow.com/questions/3003328/how-do-i-use-class-eval/3003509#3003509) – 2013-01-31 19:49:20

3

<<heredoc的開始。該行是多行字符串的開頭。字符串被刪除以創建函數。 class_eval函數使用__FILE__和__LINE__添加調試信息。

+1

但但但......你不是從無政府狀態高爾夫高爾夫精靈?你應該知道Ruby就像你的手背一樣! :-D(這是你對'class_eval'行爲是什麼樣的陳述所表現出來的渴望的一種評論。如果你的意圖不是不確定的話,我會回過頭來看看我的評論。) – 2010-03-22 22:09:52

+0

哈哈...我從來沒有需要這個功能,因爲它的字符太多了。 – 2010-03-22 22:11:36

+0

什麼樣的調試信息?我如何使用它? – 2010-03-22 22:21:12

2

我們還要注意,eval -ling字符串應儘可能避免。在您的特定情況下,#class_exec更換#class_eval是可能的,而且應該是首選:

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