InfoQ

新闻

使用ParseTree进行LINQ风格查询和提取元数据

作者 Werner Schuster译者 李明(nasi) 发布于 2008年2月26日 下午7时57分

社区
Ruby
主题
语言,
代码分析,
领域特定语言
标签
Merb,
LINQ,
LISP,
元编程,
ParseTree

通过对.NET中LINQ的介绍和对LISP的重拾兴趣,一类元编程被重新关注起来。在LINQ中,可以使用表达式树,例如一棵由一段代码表示的树。

LISP(或者类似语言)中,这种方法被称为或者宏展开。宏看上去很像函数调用,但不同的是函数调用在编译期就被估值,例如当代码载入的时候。宏可以得到宏调用的抽象语法树(AST),但是在AST宏返回时宏调用会被替换掉。这也就是说,宏调用并不是一段被实际执行的代码,而是返回的AST宏被执行了,例如宏调用展开的实际的代码。

Ruby并不在语言级别支持AST,于是有一些库做到了。最流行的一个要数ParseTree了,可以将s表达式作为AST返回。例如,符号紧凑列表和字符常量。有很多有用的工具就是基于ParseTree而构建的,例如:

  • Ruby2Ruby
    此工具可以将ParseTree的AST转化为格式化的Ruby源代码。这使得我们可以解析Ruby代码,在AST级别(而非源代码的字符级别的修改)修改它并最终重新生成可以运行的Ruby代码。
  • Heckle
    Ryan Davis和Kevin Clark开发的工具,通过使用Ruby2Ruby在代码中引入随机修改来实现覆盖测试。

现在,一些新库采用了LINQ的方式来使用ParseTree。Ambition允许用户使用Ruby语法来编写查询,例如:

LDAP::User.select { |m| m.name == 'jon' && m.age == 21 } 
或者
SQL::User.select { |m| m.name == 'jon' && m.age == 21 } 

在块中的代码实际上永远都不会运行,相反会被ParseTree用来得到AST。它会被分析并转换成目标查询语言的查询语句。Ambition提供可扩展的适配器,可以允许用户为Ruby的AST到查询语言的转化来编写新的转换器。

另外一个采用了此类型查询的库是Sequel。作为一个ORM,Sequel同样允许用户使用Ruby来编写查询

old_nonruby_posts = posts.filter {:stamp > 1.month.ago && :category != 'ruby'} 

需要重点注意的是,和Ambition不同,这仅仅是Sequel编写查询的方法之一,它同样支持通过字符串常量来编写查询。

一种很不同的Ruby代码AST使用方法可以在Merb中找到。它被用在参数化Action中:

参数化Action:
如果你在你的action方法中指定了参数,收到的查询参数将会自动被正确的指定。示例如下:
class Foos < Merb::Controller
 def index(id, search_string = "%")
  @foo = Foo.find_with_search(id, search_string)
 end
end
访问/foos/index/12将会调用index方法并传入参数“12”和“%”(默认值)。访问/foos/index将 会抛出一个BadBehavior错误(状态码400),因为id是一个必须的参数,但是却没有被传入。访问/foos/index/5? search_string=hello将会调用index方法并传入参数“5”和“hello”。最后的示例说明你可以像是用一个真正的方法一般使用 action。
这个特性是通过查看处理action方法的AST并抽取默认参数来实现的。通过这种方法,可以实现一种通常并不可用的、类似于内视/反射的特性。

这些示例展示了此类内视特性的强大。然而,Sequel和Merb同时也显示出了此类方法的缺点:基于ParseTree的特性是非强制性的。例如,这些工具并不依赖它们。如果在系统中ParseTree不可用,则这些特性也不可用。这源自于ParseTree的本质就是原生Ruby扩展。一些原生扩展的部署问题已经被解决了,例如Windows上的ParseTree或者MacOS X上的ParseTree

但是问题依然存在。ParseTree并不支持Ruby 1.9,尽管可能的解决方案正在考虑当中。Ruby 1.9实际上通过Ripper实现了对AST的部分支持。关于Ripper的信息还非常少,但是已知可以将它用作一个SAX类型的解析器。例如:
require 'ripper'
 class MyRipper < Ripper
 def on_gvar(node)
 puts node
 end
 def on_int(node)
 puts node
 end
 # etc.
 # Handle each element of the AST with an on_* method
end
可以这样来使用:
f = MyRipper.new("$foo = 1") 
f.parse
除了Ruby 1.9以外,ParseTree还提供了对其他可选Ruby实现的支持。Rubinius大量的使用了ParseTree的AST表示。JRuby几乎完全移植了ParseTree,但是基于.NET的Ruby实现似乎目前还不支持。

查看原文链接Using ParseTree for LINQ-style queries and extracting metadata

没有回复

回复

独家内容

剖析短迭代

敏捷教练Dave Nicolette提出:我们应该如何设定迭代长度?是要根据发布周期的时间么?使用短迭代又有哪些好处?

应用JSF、Ajax和Seam开发Portlets(1/3)

本文主要讲述了如何用JBoss Portlet Container 和JBoss Portlet Bridge创建新项目,怎样配置一个JSF应用去使用JBoss Portlet Bridge,以及JBoss Portlet Bridge所具备的功能。

AtomServer:数据分发的发布动力(第二部分)

在这篇文章里,Bryon Jacob和Chris Berry将和我们继续探讨AtomServer,它是基于Apache Abdera的完整Atom存储实现。作者还创建了几个Atompub规范扩展,其中包括自动标记、批处理和Feeds聚合。

架构师(试刊第二期)

InfoQ中文站的电子杂志《架构师》试刊第二期出版了!相比于上期,我们在内容的选择安排和版式上都根据读者的意见重新做了修正。“细节决定成败”,我们希望基于InfoQ中文站的专业内容,《架构师》能逐渐成为大家喜欢的电子刊物!

一种正规的性能调优方法:基于等待的调优

在本文中,Steven Haines探讨了Web应用性能调优问题。该领域过去更像是一门艺术而不是一门科学。他提出了一种称为基于等待调优的方法,使整个调优过程更加可度量,也因此更具科学性。

Java程序员ActionScript 3入门

通常来说,改变技术路线时最艰难的部分是辨别语言语法之间的不同。这篇文章就为Java开发者提供了一份如何转向Flex基础语言ActionScript的指南。

浅谈如何创建Rails应用

本视频主要以财帮子为例,介绍了如何创建一个PV为百万级的Rails应用。其中包括:Rails应用的服务器架构、Rails Cache的优化、负载均衡的处理、Web服务器的调试、分布式解决方案、Open API的设计等等。

Alexandru Popescu谈InfoQ.com网站架构

InfoQ首席架构师Alexandru Popescu在采访中谈论了InfoQ架构、Webwork与DWR、Hibernate与JCR、Hibernate可扩展性、最新的InfoQ视频流系统和InfoQ的未来规划。