Your Ad Here
首页 | 编程语言 | 网站建设 | 游戏天堂 | 冲浪宝典 | 网络安全 | 操作系统 | 软件时空 | 硬件指南 | 病毒相关 | IT 认证
软讯网络 > 网站建设 > 网页制作 > 吃了大力丸的Ruby
【标  题】:吃了大力丸的Ruby
【关键字】:Ruby
【来  源】:http://blog.csdn.net/g9yuayon/archive/2006/07/07/889411.aspx

吃了大力丸的Ruby

Your Ad Here 嗯,我们的功能测试代码常有个小小的需求:当测试代码里的某一个函数抛出异常,系统自动弹出一个调试窗口。调试窗口应该已经包含异常抛出时的上下文信息,以便测试员进行调试。"靠,还以为什么新鲜玩意儿,原来不过是Ruby On Rails玩儿得不爱的breakpoint!“,看贴的老大们开始不屑地评论。呵呵,老大们的话自然不会错,的确是RoR里常用的 breakpoint。但在俺讨论新东西前,先让小的稍稍介绍一下这个牛X的breakpoint。比如说下面这段代码:
02: class T3
03: def test_1
04: a = 0
05: 1/a
06: end
07:
08: def test_2
09: p 'test_2'
10: end
11:
12: end
13:
14: t = T3.new
15: begin
16: t.test_1
17: rescue
18: breakpoint
19: end
20: t.test_2

因为test_1用零除,第18行会被执行,导致如下的irb窗口被弹出。弹出的irb已经包含了执行中断时的所用信息,包括当时的变量,t。我们可以用local_variables查看变量。我们可以用source_lines查看中断前后的代码。我们甚至可以修改test3.rb,然后load 'test3.rb',然后恢复执行。 

为什么要在测试代码里做这些?呵呵。想象一下我们用Watir测试一个复杂的网络应用。在执行20分钟后的第30步时Watir找不到网页上一个按钮了。如果这时这个irb窗口出现,我们通过查看中断时的上下文,发现原来是用来搜索按钮的字串错了。我们于是在测试代码里改动这字串,"reload"改动后的代码或者顺手替Watir点击那个按钮,然后"exit"这个irb窗口,让测试代码继续执行。也就是说,代码出错 -》中断执行 -》调试 -》继续执行。我们都知道,出错时立刻排错的效率可比重头再来高多了。谁都不想重复前29步,等上20分钟。

听上去不错吧?不过俺们是程序员,岂能满足与此。于是新要求来了:如果等到出错时再加begin...rescue breakpoint..end就太晚了。如果没行都加就太麻烦了。能不能在写测试代码时不加任何额外代码,只在一个地方控制一下就行了嗫?比如说,上面的代码改成这样:

 02: class T3
03: def test_1
04: a = 0 05: 1/a
06: end 07:
08: def test_2
09: p 'test_2' 10: end 11:
12: monitor /test/ 13: end 14:
15: t = T3.new
16: t.test_1
17: t.test_2
注意第12行。我们添加一个新函数,凡是名字匹配/test/的函数都会在出错的时候自动弹出breakpoint的irb窗口。
这样就非常方便了。当然,我们也允许monitor :test_1这样粒度更细的语法。这样我们不用多加代码,还可以控制
到底什么时候允许breakpoint生效(比如说,在一个全局配置关闭时让monitor什么都不做)。嗯,AOP的老大们笑
了。用惯Lisp Macro的老大们也笑了。让我们看看Ruby怎么实现吧。同样非常简单。下面是一段基本的代码。我去掉了
许多无关的细节。
我们打开内置的类Module,加入一个关键的instance method, monitor。这个函数,monitor, 把传给它的函数用begin..rescue..breakpoint..end
包装起来。于是,我们的函数自动拥有了breakpoint的功能。简单得令人发指啊。
require 'breakpoint'  class Module
def match?(element, array) array.each do |e| e = e.to_s if e.instance_of?(Symbol) return true if element.match(e) end return false end

def monitored_method_ids(*method_names) return self.instance_methods(false).inject([]) do |result, method| result.push(method.to_sym) if match?(method, method_names) result end end

def monitor(*args)
monitored_method_ids(*args).each do |method| puts "starting to eval: #{method.to_i} to #{method.to_s} " module_eval <<-EVAL_END
alias_method :__#{method.to_i}__, :#{method.to_s} puts '===> #{__FILE__}' def #{method.to_s} begin puts "before running __#{method.to_s}__" __#{method.to_i}__ rescue => e
breakpoint
end
end EVAL_END end
end
end
思考题:
  1. 如果我想把上面的monitor实现到测试代码的类里,应该怎么做?提示:class << self
  2. 上面这段代码还有什么重大缺陷?提示:比如说什么信息还不正确?什么已有的功能被破坏?
  3. 那些缺陷怎么修正?提示:breakpoint.rb
  4. 如果我们想把一个函数里的每一行都加上breakpoint功能该怎么做?提示:无损语法树
prototype:【上一篇】
实现小数据量和海量数据的通用分页显示存储过程:【下一篇】
【相关文章】
  • 理解Ruby中的标志(Understanding Ruby Symbols)
  • 要是没有Ruby能产生出Rails吗? (Could Rails have been built without Ruby? )
  • Martin上海演讲实录1:Ruby是一个非常好的开发工具
  • Martin上海演讲实录2:现场演示Ruby编程
  • Martin上海演讲实录3:细数Ruby语言优缺点
  • ruby安装
  • Ruby 和 .NET
  • Ruby和Rails
  • 转:受Ruby on Rails影响的PHP开发框架
  • 受Ruby on Rails影响的PHP开发框架
  • 【随机文章】
  • Microsoft SQL Server 查询处理器的内部机制与结构(1)
  • 浅谈内存泄漏(一)
  • 用C++Builder打造网上聊天软件-MyNetMeeting(2)
  • How C Programming Works
  • 思科Cisco2800路由器型号参数及模块
  • explore2fs v1.0.0.14 (Win系统下读写Ext2的代码)
  • Spring 简单配置
  • linux必备笔记
  • 动画就是透明的可以看到html文件中起做用的部
  • 基于CMM的软件项目合同范围定义的扩充
  • 【相关评论】
    没有相关评论
    【发表评论】
    姓名:
    邮件:
    随机码*
    评论*
          
    |  首 页  |  版权声明  |  联系我们   |  网站地图  |
    CopyRight © 2004-2007 bbb软讯网络 All Rigths Reserved.