Chinaunix首页 | 论坛 | 博客
  • 博客访问: 4429617
  • 博文数量: 1214
  • 博客积分: 13195
  • 博客等级: 上将
  • 技术积分: 9105
  • 用 户 组: 普通用户
  • 注册时间: 2007-01-19 14:41
个人简介

C++,python,热爱算法和机器学习

文章分类

全部博文(1214)

文章存档

2021年(13)

2020年(49)

2019年(14)

2018年(27)

2017年(69)

2016年(100)

2015年(106)

2014年(240)

2013年(5)

2012年(193)

2011年(155)

2010年(93)

2009年(62)

2008年(51)

2007年(37)

分类: Python/Ruby

2014-12-28 00:35:33

原文地址:http://www.cnblogs.com/darkbaby123/archive/2011/06/11/ruby_metaprogramming_file_line.html

前言

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

正文

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

1
2
3
4
5
6
7
8
9
10
11
class A
  def self.my_attr_reader(*args)
    args.each do |method|
      class_eval <<-EOF, __FILE__, __LINE__
        def #{method}
          raise "#{method}"
        end
      EOF
    end
  end
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
2
class_eval <<-EOF
EOF


那加了它们有什么好处呢?

主要还是在测试方面。我们可以用如下代码测试一下:

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

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

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

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

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


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


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

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

阅读(1420) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~