RFactor 是一个 Ruby gem,旨在为人们最喜欢的文本编辑器提供自动化重构的支持。可我们不是有 IED 支持重构么?这倒没错,不过 RFactor 的开发者 Fabio Kung 坚信,“大多数 Ruby 开发人员都没用 IDE”,文本编辑器已经够好了。
自动化重构的工作量可不小,要做很多复杂的事情,例如通过源码分析来判断作用范围和使用情况。而且修改代码的时候也不能破坏用户自己的排版格式。
现在 RFactor 还很年幼,只能有限的支持提取方法(Extract Method)。我们与 Fabio Kung 进行了沟通。
RFactor 用的是 ruby_parser ,它可以把解析后的 Ruby AST 作为 s-expressions(sexp)返回。但是怎么样从 s-expressions 重新得到 Ruby 代码呢?
我的原意只是想用 sexp 来支持重构。我用它们来帮我决定如何重构。在提取方法的时候,哪些变量应该是局部变量,哪些应该是参数?而提取变量的时候,哪段代码又要进行修改呢? 我没有直接修改 sexp 来产生代码;我是直接修改源码的文本。Sexp 只是帮我决定在当前的作用范围中,哪些东西需要修改(也帮我找到当前的作用范围是什么)。
等我用 sexp 来决定哪些东西要修改以后,我就把行号和列号提取出来,然后就可以直接修改用户编写的代码了。
可是如果直接从 sexp 里面重新生成新的代码不是更简单么?
Ryan Davis 开发的 ruby2ruby 确实比较酷,它可以从 sexp 直接输出 ruby 源码。我先前也考虑过用它,不过那样就没法维护注释和用户的排版格式了。 所以那样我就得把注释和排版节点(例如换行,空格和 tab)全都放到解析树(Parse Tree)里面去。这确实是个解决办法,不过太复杂了。所以我决定用 sexp 找到行列号,然后自己直接修改源码文本。
到目前为止,这种方式对简单的重构(这也是我的目标)还挺实用。不过我可以确定,对某些复杂的重构来说(例如移动 / 重命名)就不适用了。这些重构需要其他办法。比如说移动和重命名,我就在考虑用 Ack (grep 的升级版)来寻找匹配。然后再用 heuristics 找到要变化的地方,然后询问用户是否接受变化。这个难度很大,不过有些不错的 IDE 已经提供这些实现。
不过尽管如此,我也不会太在意这些复杂的重构:他们不是我当前的目标。我不想把 TextMate 或者其他优秀的编辑器变成复杂的 IDE。我们当前在文本编辑器里面还没有任何的重构支持。所以,先集中精力添上一点再说。
那下一步的计划是什么?
目前 RFactor 还很简单,因为它只能从方法内部的代码中提取方法,也就是对方法外部的代码就没辙了。而且也没做到推断方法的参数和返回值。这个功能我是想要完成的。Sexp 可以告诉我哪些应该是局部变量,哪些不是。另外一个目标是用调用新创建的方法来代替雷同代码。 我也在学习其他类似的实现,例如 Python 的 Bicycle Repair Man 、Eclipse RDT、Smalltalk Refactoring Browser,不管是啥,只要有许可协议就行(Netbeans? RubyMine?)。Bicycle Repair Man 的 Phil Dawes 也给了我很多帮助。
计划中要支持的重构包括:
- 提取方法
- 提取变量
- 提取类
- 提取模块
- 用 Ack 做重命名和移动
不幸的是,现在只有我自己搞这个项目,而且纯粹为了兴趣在业余时间搞的。跟大多数开源项目一样,我也非常欢迎任何人的贡献。
在 GitHub 和 Fabio 的 blog 上可以了解到有关 RFactor 的更多信息,同时 GitHub 上还有一个 TextMate bundle 。
在用 Ruby 编写 Ruby 源码工具的路上,RFactor 又迈出了一步。此外就是那些用ParseTree 或者ruby_parser 来得到Ruby AST 的静态分析工具。
如果你是个文本编辑器的用户,那你希望有重构支持么?你还希望有哪些IDE 功能集成到编辑器里面去?
评论