IBM®
跳转到主要内容
    中国 [选择]    使用条款
 
 
Select a scope:Search for:    
    首页    产品    服务与解决方案     支持与下载    个性化服务    
跳转到主要内容

developerWorks 中国  >  Web development  >

向 Project Zero 应用程序中添加 Ruby 脚本

Ruby 喜爱者也能添加对其所喜爱语言的支持

developerWorks
文档选项

未显示需要 JavaScript 的文档选项

样例代码


级别: 中级

Dan Jemiolo (danjemiolo@us.ibm.com), 顾问软件工程师, IBM 

2007 年 10 月 25 日

Project Zero 的目标之一就是鼓励将脚本用作创建 RESTful 资源和可重用组件的主要手段。Zero 默认支持 Groovy 和 PHP 脚本语言,但如果进一步研究一下其体系结构就会发现它完全可以支持其他语言。Ruby 语言(及其 Web 2.0 平台即 Ruby on Rails)在过去几年中取得了巨大的成功,现在也有很多 Ruby 开发人员都以创建某种面向 Zero 的应用程序为主业。本文为 Ruby 的喜爱者展示了如何通过向 Zero 平台添加对其所钟爱的语言的支持以在 Zero 平台中也能获得用武之地。

开始之前

本文假设您已经下载了 Project Zero 并且或者已经完成了 入门教程 的学习或者自己编写过简单的应用程序。您也应该对 Ruby 编程语言比较熟悉,我想这才是吸引您阅读本文的原因。

引言

Project Zero 支持在 Groovy 和 PHP 中编写脚本,而且开箱即用,这就让创建 RESTful 资源和实用工具脚本变得十分容易,再也无需执行 Java™ 程序员已经十分习惯处理的那些复杂性和配置工作。但即使 Zero 团队已经选择对 Groovy 和 PHP 提供支持,但这也并不意味着其他动态脚本语言没有前两者那么流行和有用;如果 Ruby 或 Python 开发人员也能加入到 Zero 大家庭中来岂不是很好,这样一来,他们就可以重用所掌握的技能,而同时又可以充分享用 Zero 的新技术。本文为 Ruby 喜爱者展示了如何向 Zero 平台添加对其所喜爱语言的支持,也解释了其他语言的用户如何能实现相同的目的。

Project Zero 社区
请查阅 Project Zero 网站 以了解 Project Zero 是如何为如今的 Web 应用程序提供了功能强大但却极为简单的开发和执行平台的。

理解 Zero 针对脚本语言的策略

Groovy 和 PHP 可能是面向 Zero 平台的主要脚本语言,但二者是以一种极为通用的方式集成到 Zero 运行时(称为 Zero Core)中去的。Zero Core 的体系结构被设计成允许执行全异脚本和模板,而编程模型中没有任何内容依赖于之前所提到的语言。本节解释了 Zero Core 是如何提供对 Groovy 和 PHP 的支持的,以及如何能利用相同的机制来添加对 Ruby 的支持。

Zero Core 和解释器 API

Zero Core API 包括一个名为 zero.core.interpreter.Interpreter 的接口,该接口对于执行用户脚本来说非常重要。 HTTP 请求处理程序会使用此接口基于脚本的文件扩展名调用不同类型的脚本。当收到新的 HTTP 请求时,请求处理程序会将所有的 HTTP 数据放入 Zero 的全局上下文中,使用目标脚本的文件扩展名来寻找合适的 Interpreter 对象,之后再将此脚本调用指派给该对象;被执行的脚本能通过全局上下文访问 HTTP 请求数据。Interpreter 类有一个方法,为 invoke(),将脚本的名称传递给该方法就可以执行,仅此而已,没有什么特别的。

Groovy 支持是在一个名为 zero.core.interpreter.GroovyInterpreter 的类中实现的。此类的 invoke() 方法会使用 Groovy 的编译器 API 解析和执行脚本。groovy 文件到 Groovy 编译器的映射在 Zero Core 自身的 zero.config 文件中建立,如清单 1 所示:


清单 1. 针对 Zero Core 配置 Groovy 解释器
                
[/app/interpreters]
.groovy=zero.core.interpreter.GroovyInterpreter
      

正如您所见,解释器可通过将文件扩展名映射到解释器类来在 zero.config 中配置。要添加对 Ruby 的支持,所需做的全部工作就是编写一个解释器类,然后向 zero.config 添加一个条目以将其与 Ruby (.rb) 文件关联起来。

创建 Ruby 解释器的策略

首先,必须用 Java 编写 Ruby 解释器类以便与 Zero Core 集成,这意味着执行 Ruby 脚本将有两个选项可以选择:一是使用 JDK 的 Runtime.exec() API 来以单独的进程运行 Ruby,二是使用 JRuby 在同一个进程中处理脚本,JRuby 是 Ruby 基于 Java 的实现。后者更具吸引力,原因有三个:

  • 创建单独的进程会妨碍对全局上下文数据结构的共享,而这正是所有 Zero 脚本的核心所在。
  • JRuby 允许从 Ruby 代码中调用 Java API,因此所有的 Zero Core API 都将是可访问的。
  • 向 Zero 应用程序中添加 JRuby 就如同向 /lib 目录中添加几个 JAR 文件一样简单 —— 无需环境变量。

本文所使用的是 JRuby 1.0。(要获得到 JRuby 1.0 下载页面的链接,可以参阅 参考资料 部分。)

要创建面向 Ruby 的解释器类,需要使用 JRuby 的 org.jruby.Main 类,利用该类不仅可以执行 Ruby 脚本,还可以重定向标准 I/O 和处理由于开发人员的失误而引起的异常。下一节将展示如何将传递到 Interpreter.invoke() 的数据转换成 org.jruby.Main 上的 API 调用。

用 JRuby 实现解释器

在使用基于 JRuby 的解释器扩展 Zero Core 之前,需要通过一个示例应用程序进行开发和测试。如果想跟随本文学习,先要创建一个新的 Zero 应用程序,名为 zero.scripting;如果现在就想知道最后的结果,请参看 参考资料 部分,其中有一个 .zip 文件,内有完整的项目。

创建了 zero.scripting 项目后,需要从 JRuby 发布版向 /lib 目录中添加一些 .jar 文件。特别地,需要将 jruby.jar 和 asm-2.2.3.jar 文件复制过来。如果想要在 Eclipse 中为解释器类编辑代码,还需要将这些 .jar 文件添加到 Eclipse 项目的类路径中。

JRubyInterpreter 类

要创建 JRubyInterpreter 类,需要先创建一个新的源代码文件,其中带有空的类骨架,再向此定义中添加 Interpreter 接口。然后需要为 invoke() 添加方法声明以便类进行编译。这之后,所需做的就只是将赋给 invoke() 的数据以合适的格式传递到 org.jruby.Main清单 2 所给出的实现执行了如下任务:

  • 将 JRuby 的标准输出重定向到当前 HTTP 请求的输出流。这就让 Ruby 开发人员能够将 HTTP 请求数据以与 Groovy 开发人员相同的方式发送回客户机。
  • 为 JRuby 运行时创建参数数组。这些参数包括目标脚本的名称,而且这些参数的格式与从命令行调用 JRuby 时参数的格式相同。
  • 通过调用 Main.run(),执行脚本。


清单 2. JRubyInterpreter 类
                
     
package zero.scripting.ruby;

import java.io.File;
import java.io.OutputStream;
import java.io.PrintStream;
import java.io.PrintWriter;

import org.jruby.Main;
import org.jruby.RubyInstanceConfig;

import zero.core.context.GlobalContext;
import zero.core.events.HandlerInfo;
import zero.core.interpreter.Interpreter;

public class JRubyInterpreter implements Interpreter 
{        
    public void invoke(HandlerInfo handlerInfo)
    {
        final PrintWriter writer = GlobalContext.get("/request/writer");
            
        //
        // JRuby's API uses the deprecated PrintStream class, so we 
        // have to wrap the response writer in a PrintStream
        //
        PrintStream stream = new PrintStream(new OutputStream(){
            public void write(int b) {
                writer.write(b);
            }
        });
            
        //
        // Map stdout/stderr to HTTP response writer
        //
        RubyInstanceConfig jrubyConfig = new RubyInstanceConfig();
        jrubyConfig.setOutput(stream);
        jrubyConfig.setError(stream);
            
        File scriptFile = new File(handlerInfo.handler);
        String[] jrubyArgs = new String[]{ scriptFile.getPath() };
            
        //
        // Execute Ruby script!
        //
        Main jruby = new Main(jrubyConfig);
        jruby.run(jrubyArgs);
            
    }
}

      

可以将这些代码添加到应用程序的 /java 目录并使用 zero make 命令对其进行编译。结果类文件会复制到应用程序的 /classes 目录并在运行时被加载。

更新 Zero 配置文件

现在代码已经准备好,还有一个步骤要完成:如同 Groovy 解释器一样,必须向 Zero Core 注册 Ruby 解释器以便它能知道如何处理对 .rb 文件的请求。最后,将清单 3 的代码添加到应用程序的 /config/zero.config 文件:


清单 3. 向 Zero Core 注册 Ruby 解释器
                
[/app/interpreters]
.rb=zero.scripting.ruby.JRubyInterpreter
      

测试 Ruby 脚本

Ruby 支持已经就绪,现在就可以通过将一个 Ruby 脚本添加到应用程序并从 Web 浏览器进行调用来对其进行测试。要展示 Ruby 与 Zero 的完整集成,测试用的这个脚本应该使用 Zero 的 GlobalContext API 来读取请求数据并创建响应。清单 4 中所示的 Ruby 代码通过在 HTML 响应中对此全局上下文进行序列化展示了其完整内容。注意即使它使用的是 Zero Core 的 Java API,语法仍然是纯 Ruby 的。


清单 4. 测试代码所用的 Ruby 脚本
                
    
    require "java"

    include_class "zero.core.context.GlobalContext"
    include_class "zero.core.context.SimpleFormatter"

    print "<p>The current contents of the global context are:<pre>"

    formatter = SimpleFormatter.new
    GlobalContext.dump formatter
    print formatter

    print "</pre></p>"
      

将清单 4 中的代码添加到应用程序的 /public 目录中名为 test-ruby.rb 的文件内。之后,应该用 zero run 命令启动 Zero 应用程序,再将 Web 浏览器指向 http://localhost:8080/test-ruby.rb 以进行测试。结果应该是一个简单的 HTML 页面,其中显示了此全局上下文的全部内容。图 1 中所示的是 Mozilla Firefox 中该页面的一个屏幕截图。


图 1. 此 Ruby 脚本创建的 HTML 页面
图 1. 此 Ruby 脚本创建的 HTML 页面的屏幕截图

结束语

在默认情况下,Project Zero 并不包括对 Ruby 的支持,但这并不意味着 Ruby 程序员就必须要放弃自己喜爱的语言才能使用这个新平台。有 Ruby on Rails 的使用经验并希望使用 Zero 的开发人员可以通过借助本文中所介绍的技巧来简化转换以使自己的 Ruby 技能仍能派上用场,同时又能利用 Zero 的新模式。Ruby 开发人员可以使用本文随带的代码并根据需要加以缩减。






回页首


下载

描述名字大小下载方法
本文的源代码wa-pz-rscript.zip4KBHTTP
关于下载方法的信息


参考资料

学习
  • 您可以参阅本文在 developerWorks 全球站点上的 英文原文

  • 浏览 developerWorks Web 开发专区 以查找工具、代码或资源以便立即开始进行 Web 2.0 应用程序的开发。

  • developerWorks Ajax 资源中心 中富含面向所有技能水平读者的信息,可帮助您将 Ajax 构建到自己的应用程序中并极大提高用户的 Web 体验。


获得产品和技术
  • 下载 Project Zero 并开始应用本文所涵盖的最佳实践。

  • 下载 JRuby 1.0 以构建和运行本文所包括的代码。

  • 下载本文所创建的 示例项目,包括 JRuby 集成代码和测试文件。


讨论


关于作者

Dan Jemiolo 是 IBM 位于美国北卡罗来纳州 Research Triangle Park 的 Autonomic Computing 团队中的一名顾问软件工程师。他负责 Apache Muse 2.0 的设计和开发而且现在还在为此项目工作。Dan 还参与过 WS-RF TC,担任 WS-ResourceMetadataDescriptor 规范的编辑,他亦参与制订过 IBM 在更多地采用 Web 服务标准方面的策略。从 Rensselaer Polytechnic Institute 获得了理学硕士学位之后,他加入 IBM 刚刚两年。




对本文的评价

太差! (1)
需提高 (2)
一般;尚可 (3)
好文章 (4)
真棒!(5)

建议?




回页首


Java 和所有基于 Java 的商标是 Sun Microsystems, Inc. 在美国和/或其他国家的商标。 其他公司、产品或服务的名称可能是其他公司的商标或服务标志。

IBM 公司保留在 developerWorks 网站上发表的内容的著作权。未经IBM公司或原始作者的书面明确许可,请勿转载。如果您希望转载,请通过 提交转载请求表单 联系我们的编辑团队。
    关于 IBM 隐私条约 联系 IBM 使用条款