简介 本文介绍如何在Eclipse中使用Ruby开发工具(RDT)插件进行Ruby开发。本文将有益于那些想学习如何使用Eclipse基础架构来进行Ruby开发的Ruby开发者,也有益于对Ruby开发感兴趣的Java开发者。
一、 为什么使用Ruby?
现在,为什么众多的Java开发者都关注Ruby?Ruby,是10年以前在日本创建的一种通用目的脚本语言,这是一种纯面向对象的语言。不同于Java技术,Ruby中的一切都是对象。Ruby的语法主要来源于Smalltalk,Python和Ada。象Java编程语言一样,Ruby是一种单继承的语言,但是它提供了一些Java技术所没有实现的高级特征,例如闭合(可以认为是一种匿名的内部类)和mix-in(类似于接口,但是较松地绑定于类上)。Ruby也是高度可移植的,能够运行在所有主流的操作系统之上。
现在,Ruby正十分热门。人们正在开始把它应用于各种类型的应用程序。因为它是解释型并且使用动态类型化,所以你可以在运行时刻实现在Java中很难实现的技巧。由动态类型化和富于表达的语法所实现的令人吃惊的能力之一是它能够用Ruby创建域特定的语言(DSL)-它们允许你在更高级别的抽象层上工作,从而远离最原始的语言语法。Ruby on Rails是一种创建基于数据库支持的Web应用程序的框架,这也展示了Ruby的力量。Rake,作为Ruby的Make和Ant合二为一的版本,是这种语言强有力的应用的又一个证明。
使用Ruby的另一个原因是,所有的编程发烧友都在使用它。现在,许多Java高手(如Glenn Vanderburg,Bruce Tate和Martin Fowler)都在使用Ruby。即使你不打算把你的所有开发转向Ruby,这种语言也值得你浏览一番。
限制Ruby发展的主要因素之一是,它缺乏一个良好的开发环境(对于那些不想学习Emacs的用户来说)。如今,RDT改变了这一切,而使用Eclipse对此进行试验则最好不过。
二、 安装
在使用Ruby之前,你必须安装Ruby解释器,相应的库和Ruby开发环境。
三、 取得Ruby
Ruby可用于所有主要的平台上。事实上,你的Linux或Cygwin分发包中可能已经包含了它。请打开一个命令提示符,然后输入"Ruby-v"。
如果你得到一个版本号,那么你已经准备好。否则,你需要检查你所选择的平台的分发包。
如果你正在运行Windows,则选择更容易。RubyForge,作为SourceForge上的Ruby特定的等价物,有一个工程称为One-Click Ruby Installer,这个程序用于在Windows平台上搭建Ruby环境。它还包括另外一些工具,如一个称为FreeRide的IDE;但是如果你使用RDT的话,你在安装过程中可以跳过这些这项。
四、 取得文档
当你开始使用一种新语言时,文档及有关参考材料是至关重要的。你可以在主Ruby网站得到Ruby文档的在线参考材料,但是你会发现这些文档有点过时(它们是针对于Ruby 1.6版本的,而当前版本是1.8.2)。问题是,更新的文档目前还没有从日语翻译过来。然而,你可以在Ruby-doc.org上找到最新的帮助文档。它包括API级的文档(Javadoc的等价物),还有其它一些教程和书籍。
如果你是一位严肃的Ruby开发者,那么你应该阅读一下《Programming Ruby:The Pragmatic Programmer's Guide》(作者是Dave Thomas和Andy Hunt)一书以取得最佳编程效果。这是一本有关Ruby及Ruby库编程的经典指南。如果你得到此书,那么你还可以参考也是Dave Thomas编写的《Agile Development with Ruby on Rails》一书。这是一本有关Ruby on Rails的入门性书籍。
五、 得到RDT
现在,既然你在自己的计算机上安装了一个可工作的具有良好帮助文档的Ruby,那么接下来你需要安装RDT了。这是一个Eclipse插件,它提供了许多你可能在编辑代码时已习惯的特征。RDT是一个标准的Eclipse插件;因此,你可以直接把压缩文件解压到Eclipse文件夹下,由文档中的路径来处理其它一切。
现在,你已经准备好创建一个Ruby工程了(见图1)。
图1.创建一个新的Ruby工程
与Java相比,Ruby在命名和目录结构方面要求并不严格。在Ruby中创建一个工程实际上只创建一个目录和一个工程文件(不需要.classpath文件,因为Ruby没有classpath)。另外一个与Java技术的显著区别是,Ruby工程向导并不创建显式的src和bin目录。Ruby是解释型的,因此没有输出文件夹。如果你有一个小工程,那么你可以把Ruby源文件放在与工程文件相同的文件夹下。作为选择,你还可以创建你自己的目录层次。你会发现,与Java相比,Ruby很少关心这些。
接下来,你将创建一个Ruby源文件。没有特定的向导用于创建一个Ruby源文件。与Java技术相比,Ruby源文件中仅需要较少的结构,所以,为了创建一个Ruby文件,你需要右击工程来创建一个新文件(见下图2)。
图2.创建一个Ruby源文件
别忘记把标准扩展名.rb添加到该文件(它是正常的Ruby扩展名)。创建一个Ruby文件应该会打开如图3所示的Ruby视图。
图3.创建一个Ruby文件将启动Ruby视图
Ruby还提供了一个Outline视图(类似于Java提供的那种)。就象它的Java对应物一样,它允许你在Ruby源文件的元素之间进行导航。在图4中,raise_salary_by方法在Outline和源码视图中都被加亮。
图4.这个Outline视图实现在源文件中的导航
就象其它复杂的插件一样,RDT也允许通过"Window>Preferences"对话框增加定制特征。这个定制对话框见图5。
图5.RDT安装"Preferences"以便实现定制
参数选择"Preferences"菜单项允许你改变语法加亮,格式化(Ruby世界中的标准缩进是两个空格,而不是四个空格,所以请准备好作一些调整),等等。它还允许你定制编辑器模板并选择你自己的解释器。
六、 RDT编辑器
在Java世界中,我们已习惯于高级编辑器特征-这使得在转到其它不提供同样支持的其它环境时比较困难。Ruby IDE中所缺乏的特征之一是没有提供内容助手(它能够提供上下文相关的标识符查找功能)。幸好,RDT编辑器中含有针对Ruby代码的内容助手,见下图6。
图6.RDT编辑器提供了内容助手
在Ruby中,你不能把一种类型赋值给一个变量或一个方法的返回,而由标识符上下文确定在运行时刻的类型。Ruby中引入了一种被亲切地称为"duck typing"的方法。这种方法的思想是,如果它接受一个假(quack)消息,那么它必须是一个"duck"。这看起来似乎妨碍了那些已经习惯了强类型化语言的用户,这种松散类型耦合能够支持Ruby语言中一些更强有力的特征。例如,你可以用Ruby编写一个异常处理器-当你调用一个并不存在的方法时激活它,然后由该异常处理处理器来自由分析这个方法,然后再调用它。这种元编程级在强类型化语言中是很难实现的。
针对内容助手的一个挽回特征是,Ruby在使用标识符时使用特定的命名惯例。例如,在Ruby中,所有的成员变量在第一次使用它们时就存在,并且全部由一个@符号所标识,作为其名字的第一个字符。如果你使用内容助手查找成员变量,那么你可以输入@,这样以来你就只能看见成员变量了。
图7.在Ruby帮助内容助手中的命名惯例
动态类型化仍然妨碍在Ruby中的上下文敏感问题。在图7中,唯一有效的成员变量是正好出现在方法声明上面的那些,也就是@name,@salary和@hire_year。内容助手所提供的另外一些成员来自于另一个类(后面定义)。目前,RDT编辑器还不足够复杂以过滤所有的正确语法但语义上不正确的入口。
七、 运行与调试
IDE的特色之一是在同一个环境下运行和调试你构建的应用程序。RDT能够启用这两项功能。
八、 指定一个解释器
这一任务的实现位于Ruby上部和"Installed Interpreters"入口的"Windows>Preferences"对话框中。
Ruby是一种解释性的语言,因此,在RDT能够运行或调试你的应用程序之前,你必须把一个解释器与你的环境关联。这种关联位于Ruby顶部的"Windows>Preferences"对话框中的"Installed Interpreters"入口处。
图8.把一个Ruby解释器与环境相关联
对于你正在使用的Ruby版本,你要把"Location"文本域指向bin目录,之后由RDT来选取所有其它所需要的信息。一旦你关联了解释器,那么你就为运行应用程序作好了准备。
九、 运行Ruby应用程序
运行一个Ruby应用程序实际上类似于运行一个Java应用程序。你可以使用Run菜单来创建一个Run配置,见下图9。
图9.在RDT中建立一个Run配置
当你运行应用程序时,RDT将把控制切换到Ruby解释器,然后在Eclipse工作区底部的控制台窗口内运行应用程序,见下图10。
图10.在RDT内运行一个Ruby应用程序
这个实例显示了运行一个控制台应用程序,但是运行其它类型的应用程序(如GUI程序)的方式与此相同。
十、 用RDT调试
一个IDE要求实现的最关键的特征之一是有效地调试你的应用程序的能力。Ruby解释器包括一个命令行调试器,但是,在如今的图形工具时代有谁会使用一个命令行调试器?幸好,Ruby解释器还通过一特定(可配置)端口来广播其调试信息,而就象RDT这样的工具能够听取该端口并且提供开发者们期望的调试支持类型。
为了在RDT中调试一个Ruby应用程序,我们要象上面创建的Run配置一样创建一个Debug配置。然后,你可以通过点击左边的沟槽设置一个断点并使用调试器来启动应用程序。就象在Java技术中一样,IDE将询问你,是否你想要切换到调试视图下。如果你愿意,则你将看见类似下面图11所示的内容:
图11.在RDT中调试Ruby应用程序
RDT中支持与Java技术调试相同的调试级别。左上边的格子显示出当前执行的线程,右上面的格子显示出变量的值。就象在Java编程语言中一样,你可以进一步分析对象以观看它们内在的成员变量值。中间左边的格子显示当前正运行的应用程序的源代码,中间右边的格子显示Outline视图-它在这里担当编辑器的作用,允许你通过点按一个标识符来进行导航。Debug窗口的底部显示出Ruby解释器在端口1098上广播的调试信息,而由RDT在该端口上听取调试信息。
调试器支持是RDT的特色。就算你有一个具有优秀的Ruby支持的编辑器,你仍然必须依靠命令行调试器来调试你的应用程序。拥有一个具有全面功能的调试器将会大大提高软件的生产效率。
十一、 测试
作为Java开发者最难实现的Ruby特征之一是动态类型化。如果你习惯于一种强类型化语言,那么动态类型化看上去似乎有点混乱。DT允许各种高级元编程技巧-这在一种强类型化语言中是很难或不可能实现的。当然,你可以放弃编译时刻类型检查的安全设置。那么,是否有一个方法能够实现两种世界的最佳结合呢?
单元测试应该是每一种语言必须实现的,但是它在动态语言中特别关键。单元测试比编译揭示了更多的内容。事实上,你应该改变在单元测试和编译之间的关系上的观点。最近,一位高级软件开发专家认为,"在今后的五年内,我们会把编译作为单元测试的一种弱的实现形式"。单元测试能够提供证实(verification)-编码将如期实现,而不是仅仅进行你输入内容的语法检查。
考虑到单元测试在Ruby世界中的极端重要性,你一定会希望RDT能够使得单元测试易于运行。的确如此!单元测试被包括在Ruby内,因此你不必下载任何其它的扩展。Ruby库中包括了一个TestCase类和一个TestSuite的概念。你可以象创建任何另外的Ruby类一样来创建你的单元测试,从Test::Unit::TestCase中子类化你的测试。列表1是一个Employee类的实例。
列表1.Employee类
class Employee
def initialize(name, salary, hire_year)
@name = name
@salary = salary
@hire_year = hire_year
end
attr_reader :name, :salary, :hire_year
def raise_salary_by(perc)
@salary += (@salary * (perc * 0.01))
end
def to_s
"Name is #{@name}, salary is #{@salary}, " + "hire year is #{@hire_year}"
end
end
相应的单元测试如下:
列表2.相应于Employee类的单元测试
require 'test/unit/testcase'
require 'test/unit/autorunner'
require 'hr'
class TestEmployee < Test::Unit::TestCase
@@Test_Salary = 2500
def setup
@emp = Employee.new("Homer", @@Test_Salary, 2003)
end
def test_raise_salary
@emp.raise_salary_by(10)
expected = (@@Test_Salary * 0.10) + @@Test_Salary
assert( expected == @emp.salary)
end
end
为了运行这个单元测试,你可以为该单元测试类创建一个Run配置-作为一个Test::Unit类型,见图12。
图12.RDT包括一个Test::Unit Run配置
当你运行这个测试时,你会得到与Java单元测试相同的支持元素,包括在左下角的类JUnit格子。
图13.运行于IDE中的一个单元测试的例子
你还可以在Ruby中创建TestSuites。TestSuites是Ruby类,它定义一个返回TestSuite的suite方法。这个TestSuite由自动地在每个TestCases中定义的suite组成。列表3是针对几个类的一个示例TestSuite。
列表3.一些类的示例TestSuite
require 'test/unit/testsuite'
require 'test/unit/ui/tk/testrunner'
require 'test/unit/ui/console/testrunner'
require 'TestEmployee'
require 'TestManager'
class TestSuite_AllTests
def self.suite
suite = Test::Unit::TestSuite.new("HR Tests")
suite << TestEmployee.suite
suite << TestManager.suite
return suite
end
end
#Test::Unit::UI::Tk::TestRunner.run(TestSuite_AllTests)
Test::Unit::UI::Console::TestRunner.run(TestSuite_AllTests)
不同于前面运行单个TestCase的实例,这里的suite作为一独立的应用程序运行。Ruby有两个方法可以显示TestSuite的结果。第一个是"Console Test Runner"-它在控制台输出它的结果。第二个是"Tk TestRunner",它创建一个熟悉的对话框来显示测试的结果。图14显示了一个Tk TestSuite对话框。
图14.图形式的TestSuite对话框
十二、 新版本中的改进
RDT的当前版本是0.50。目前,其开发者正在开发0.60版本。下一个版本中将改进的方面包括:
· 代码折叠功能-提供针对类和方法的代码折叠功能。
· Outline视图-提供更详细的信息,包括对局部变量的支持。
· RI视图-从一个RDT视图中使用Ruby的ri工具。
· 任务标签-以Ruby注释形式为可配置的关键字(如TODO,FIXME)创建任务。
· 编辑器方面的改进-自动添加大括号,圆括号和单/双引号;还有更好的代码助手。
· 检查器快捷方式-在一个调试会话期间,针对经常使用的检查器提供可配置的快捷方式,如显示一个对象的所有方法,全局常量,等等。
接下来的版本将更好地使用JRuby字节码编译器。JRuby是一项工程,它允许把Ruby代码编译为Java字节码。这意味着,RDT的以后版本将更容易地加入到Eclipse世界中,甚至提供更好的支持。
十三、 总结
Ruby最终为业界人士所广泛认可和应用。其中,部分原因应该归功于Ruby on Rails工程的成功的驱动。如今,已经到了考虑如何把Ruby加入到你的"竞争工具箱"中的时候了。当然,RDT也是吸引你加入这一领域的一个重要因素。