Ruby学习八 ->元编程 - __FILE__ 和 __LINE__ 的作用

Ruby 元编程 - __FILE__ 和 __LINE__ 的作用

http://www.cnblogs.com/darkbaby123/archive/2011/06/11/ruby_metaprogramming_file_line.html

前言

Ruby 元编程中,经常可以看到各种 eval 和 heredoc 的结合。其中很多用 heredoc 的位置都会出现 __FILE__ 和 __LINE__ 这两个变量。本文介绍一下它们的作用,以及为什么要这样做。

正文

先看一个用 class_eval 动态生成实例方法的例子:

01 class A
02    def self .my_attr_reader(*args)
03      args. each do |method|
04        class_eval <<- EOF , __FILE__ , __LINE__
05          def #{method}
06            raise "#{method}"
07          end
08        EOF
09      end
10    end
11 end

这是模仿 Ruby 的 attr_reader 的代码,当然实现简化过了,关键是,它会抛出异常。我们待会再解释为什么这样做。现在先大概解释下代码。class_eval 是 Ruby 中 eval 的一种,它的上下文是调用它的对象,也就是类 A 。它通常用来为类生成实例方法,用法就像上面代码中的那样。你可以传把一段 Ruby 代码写在一个字符串中传过去,class_eval 就会动态解释 Ruby 代码。这和 Javascript 中的 eval 十分类似。

heredoc 就是被 EOF 包起来的那部分。它实际上是一个多行的字符串,EOF 只是一个标识,代表 heredoc 的开始和结束,你可以随意换成其他玩意。用 heredoc 的好处之一是可以不用操心单引号和双引号的问题,还有就是把代码写在多行看得比较清楚。喜欢深挖的可以看看 这个链接

第4行 EOF 后面的 __FILE__ 和 __LINE__ 是两个特殊变量,它们保存了当前文件的名字和当前代码的行数。其实 heredoc 后面不加这两个变量也可以。比如这样也是合法的:

1 class_eval <<- EOF
2 EOF

那加了它们有什么好处呢?主要还是在测试方面。我们可以用如下代码测试一下:

1 A .class_eval do
2    my_attr_reader :name
3 end
4  
5 a = A . new
6 a.name      # 会抛出异常,异常信息为 name

把这段代码和上面第一段放在一起,保存成 Ruby 文件(我保存成 test.rb),再用解释器执行,会看到如下的错误:

1 # test.rb:5:in `raise': exception object expected (TypeError)
2 #     from test.rb:5:in `name'
3 #     from test.rb:18

可以看到,异常信息会提示你错误出在 test.rb 第5行的 name 方法内。即使 name 方法是用元编程手段动态产生的。

现在我们把 EOF 后面的 __FILE__ 和 __LINE__ 去掉。再运行下代码,会看到如下的结果:

1 # (eval):2:in `raise': exception object expected (TypeError)
2 #     from (eval):2:in `name'
3 #     from test.rb:18

可以看到,异常信息最后是从 eval 中抛出来的,最多只能看到18行调用 name 的那一行出错了,但看不到 name 方法在哪定义的。这样对 debug 几乎没有帮助,尤其是当程序复杂的时候。比如 Rails 就使用了大量元编程技巧。

所以,__FILE__ 和 __LINE__ 在这里就是为了方便 debug 的。它们并不会对元编程动态创建的方法有任何影响。

相关推荐