Ruby 分子的 IronRuby
IronRuby 是微软的 Ruby 实现,它以.NET 架构良好的互动性闻名于世。Iron 这个名字实际上是“Implementation running on .NET”的首字母缩写。.NET 的公共语言运行时和 Mono(非官方的)均能够支持 IronRuby。你可以不必弄清楚某些关于动态语言运行的问题(例如在 CLR 之上的 Ruby),这就是 DLR(动态语言运行时)将要帮你解决的。DLR 是微软作为在 CLR 之上提供动态语言支持能力的一种技术手段。
作为微软对开源软件做出的承诺中的一部分, IronRuby 和 DLR 可以在遵循微软公用许可证(Microsoft Public License)的前提下分别从 GitHub 和 CodePlex 中获得。从设计之初,IronRuby 的目标就是成为 Windows 平台上 Ruby 实现的首选,而它自然也提供了良好的兼容性和优异的性能。在撰写本文的时候,IronRuby 在 RubySpec 的通过率已经能够达到 86%。反过来让我们看看 MRI,它的通过率是 98%。虽然通过率尚有不足,但是从测试上来看,IronRuby 的性能要比 MRI 1.8 优异许多(高出四倍以上),这个测试结果是 Antonia Cangiano 运行他的 Ruby 测试套件之后给出的。
不仅仅拥有良好的兼容性和优异的性能,IronRuby 的杀手锏是它和.NET 标准库以及.NET 程序集(assembly)之间良好的互动能力。仅仅只需一条‘require’语句,你就可以在 Ruby 代码中使用.NET 架构和类。这个重要的功能就这样“自动”地在 Ruby 标准库的基础上被引入到 IronRuby 代码中。require 后面可以跟任何.NET 程序集的名字。让我们在 Ruby 中创建一个 Windows Form,来看看 Ruby 和.NET 是如何无缝集成的:
require 'System.Windows.Forms' System::Windows::Forms::Form.new.show
运行 ir(IronRuby 解释器),你将会在屏幕上看到一个标准的 Windows Form!虽然只是一个空的 Form,但是仅仅两行代码你又能期望多少呢?这里的代码之美就在于它需要比 C#或者 VB 用更少的代码完成相同的事情。可以想象得到,你还能够程式化地向这个新的 Form 中加入一些控制逻辑:
require 'System.Windows.Forms' form = System::Windows::Forms::Form.new lbl = System::Windows::Forms::Label.new lbl.text = "foo" form.controls.add(lbl) form.show
比较静态语言和动态语言的代码是非常困难的事情,但是,我们可以先看看上面的代码在 C#中应该是什么样子的:
using System; using System.Windows.Forms; namespace MyWinFormsApplication { static class Program { static void Main() { Form form = new Form(); Label lbl = new Label(); lbl.Text = "foo"; form.Controls.Add(lbl); form.Show(); } } }
有一些.NET 框架经验的开发者将会意识到,C#或者 VB 程序中的对象一旦编译之后就是作为 CLR 对象存在。也就是说,任何能够和.NET CLI(公共语言基础架构)良好互动的程序都可以访问这些对象。这个特点允许开发者能够应付在 VB、C++ 或者甚至是 PowerShell 中的 C#类和方法(反之亦然)。.NET 代码不会被编译成本地代码,而是转换成为一种可以称为 CIL(公共中间语言)中间语言。不幸的是,CIL 是静态类型语言,不过,正如我之前在介绍中提及的那样,这就是 DLR 如何能够提供 CLR 和例如 Ruby 这样动态语言交互能力的关键所在。
.NET 程序集的方法可以以两种形式在 IronRuby 中表示:熟悉的 ruby 小写形式(例如 controls.add)和传统的 C#驼峰形式(例如 ToString)。由于 Ruby 并没有大多数.NET 语言中的属性概念(CLR 中是字段),所以在 IronRuby 中属性是以访问方法和存取方法(例如 foo.bar() 和 foo.bar=(x))的形式存在。假设我们将以下 C#命名空间和 Person 类编译成了一个 MyClassLibrary.dll 文件:
namespace MyClassLibrary { public class Person { public string Name { get; set; } public string Introduce() { return String.Format("Hi, I'm {0}", Name); } } }
下面将会演示如何在 IronRuby 中使用这个 dll。
require 'MyClassLibrary.dll' me = MyClassLibrary::Person.new me # => MyClassLibrary.Person me.name = "Edd" me.name #=> 'Edd' me.introduce # => 'Hi, I'm Edd'
这种纯正的互动能力能够帮助开发者在一些元程序设计场合复用 Ruby 代码。
注意:注意大小写!如果你希望在 IronRuby 中使用你自己的.NET 程序集,请保证你的.NET 代码中的命名空间和类名使用的是正确的大写驼峰表示法。.NET 类可以直接转换成 Ruby 类,而命名空间是以 Ruby 模块的形式表示,在 Ruby 中两者都会使用大写驼峰表示法。如果你的.NET 代码中的名字不是使用的这种表示法,那么就无法将两者联系起来,从而不能在 Ruby 代码中使用。
IronRuby 元编程
元编程(Metaprogramming)的科学和艺术可以写一篇很长的文章,尤其是在 Ruby 中,我们可以充分享受到元编程的乐趣。就像你希望的那样,在 IronRuby 中,你也可以尽情地发挥自己的想象力,使用一切可以在动态语言中能够使用的东西。让我们看看如何在 Ruby 使用可信赖的 class_eval 来处理之前例子的 Person 类的:
require 'MyClassLibrary.dll' me = MyClassLibrary::Person.new me.name = "Edd" MyClassLibrary::Person.class_eval do define_method(:shout) do |text| "#{name} shouts: #{text.upcase}!" end end puts me.shout("Hello, world") #=> "Edd shouts: HELLO, WORLD!"
如之前例子所示,ir(IronRuby 解释器)将会执行这段代码。如果你希望能够有更多证据证明 IronRuby 是一种“只有想不到,没有做不到”的语言,那么我们使用典型的 Rails-esque 作为 mixin。请记住我们在这里一直使用的是使用 C#编写的类。
require 'MyClassLibrary.dll' me = MyClassLibrary::Person.new module ActsAsHungry def self.included(base) puts "I'm hungry..." end def tummy_contents @tummy_contents ||= [] end def eat(foodstuff) tummy_contents << foodstuff puts "*Burp*" end end MyClassLibrary::Person.class_eval do include ActsAsHungry end me.eat("cheeseburger")
如何驾驭 irails?
让我们回到正题。我敢打赌大部分的 Ruby 开发者都熟悉 Rails 框架,也许假设大多数都是被 Rails 吸引才会使用 Ruby 语言应该会更好些。
长话短说,IronRuby 的兼容性非常优秀,你可以完美地运行你的 Rails 程序。但是,有些事情我不得不交代一下,否则含糊不清的语句可能会让开发者一头雾水,这是与我的初衷相违背的。我知道,当了解这些知识后,也许你会想立刻在你的 Ruby 应用中大量尝试这些.NET 互动功能,所以我要声明,这里有些事项需要引起你的注意:
- IronRuby 有自己的用于替代 irb、gem、rake 和 rails 的脚本,叫做 iirb、igen、irake 和 irails。如果你需要安装官方 Ruby 的话,你可能需要记住这些来分辨它们。
- 不过 IronRuby 官网声明,这些脚本将会被废弃掉,你可以通过 _-_S
标识来调用 ir。
- 不过 IronRuby 官网声明,这些脚本将会被废弃掉,你可以通过 _-_S
- 由于它和其他的 Ruby 安装程序是隔离的,IronRuby 不会和它们共享 RubyGems(也可以通过调用 igem 列表反映出来),尽管它其实也可以实现。
- SQLite 迅速成为了开发中最受欢迎的数据库。在 IronRuby 下,sqlite3-ruby 不能正常工作。请确保安装的是 sqlite3-ironruby gem。
注意:MSI IronRuby 安装包将会释放 IronRuby 到“C:/Program Files/IronRuby x.x” 下。如果你是这样安装的 IronRuby,我建议最好安装到一个不会影响其他目录(不过也需要更新 PATH 变量),来避免脚本出现不能够解析路径名字的问题。
如上所述,IronRuby 现在和 Ruby 1.8.6 的兼容性非常好。因此在 IronRuby 下运行已有的 Rails 应用不会有太多问题(使用 ir 运行你的脚本或者服务器脚本来亲自观察一下)。
如果你已经在 Windows 上部署相应软件,IronRuby 可以通过 ironruby-sqlserver gem 来利用良好的.NET 互动性提供 SQL Server 支持(也能够得到 Windows 集成安全机制的支持),这个 gem 需要一个不同于 Rails 自带库的 DBI 库,叫做 ironruby-dbi,不过值得欣慰的是,ironruby-sqlserver 将会检查这个库是否存在。在 database.yml 中的这个适配器的配置如下所示:
development: mode: ADONET adapter: sqlserver host: HOSTNAME\INSTANCE database: application_development integrated_security: true
稍稍多说一点,这其实只是在 Ruby on Rails 中使用 IronRuby 的众多优点中的冰山一角。在工业生产环境中运行这些应用是一个巨大的课题,因为选择众多:可以部署到 IIS 或者Windows Azure,后者是一个云平台,你可以在上面运行你的任意基于.NET 的 Web 应用或者服务。
希望现在你已经意识到了将这些语言糅合成一门清晰的动态语言的好处,例如.NET 框架下的 Ruby 语言。也许,你还希望知道“我可以在 IronRuby 中编写 ASP.NET MVC 应用程序吗?”或者“IronRuby 和其他的技术兼容性如何?例如 Silverlight 或者其上层技术为浏览器外应用服务的 WPF?”。如果希望寻找这些问题的答案,或者只是弄清楚你对 IronRuby 的一些理解,可以从 IronRuby 官方网站找到更多资料。
查看英文原文: What’s IronRuby, and How Do I Put It on Rails?
感谢李明对本文的审校。
给InfoQ 中文站投稿或者参与内容翻译工作,请邮件至 editors@cn.infoq.com 。也欢迎大家加入到 InfoQ 中文站用户讨论组中与我们的编辑和其他读者朋友交流。
评论