科技行者

行者学院 转型私董会 科技行者专题报道 网红大战科技行者

知识库

知识库 安全导航

至顶网软件频道应用软件向 Project Zero 应用程序中添加 Ruby 脚本

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

  • 扫一扫
    分享文章到微信

  • 扫一扫
    关注官方公众号
    至顶头条

本文为 Ruby 的喜爱者展示了如何通过向 Zero 平台添加对其所钟爱的语言的支持以在 Zero 平台中也能获得用武之地。

作者:佚名 来源:IBMDW 2007年12月26日

关键字: Project Zero 应用程序 RUBY 脚本 软件

  • 评论
  • 分享微博
  • 分享邮件

引言

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

理解 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 开发人员可以使用本文随带的代码并根据需要加以缩减。

查看本文来源

    • 评论
    • 分享微博
    • 分享邮件
    邮件订阅

    如果您非常迫切的想了解IT领域最新产品与技术信息,那么订阅至顶网技术邮件将是您的最佳途径之一。

    重磅专题
    往期文章
    最新文章