Ruby [分享] ast-grep:一个基于抽象语法树的代码搜索工具

hd_nvim · 2023年07月24日 · 最后由 hd_nvim 回复于 2023年07月27日 · 1324 次阅读
本帖已被管理员设置为精华贴

大家好,今天我想给大家介绍一个很有用的代码搜索工具,叫做 ast-grep。官网在 https://ast-grep.github.io/https://github.com/ast-grep/ast-grep 在这里

它可以让你用抽象语法树(AST)的模式来搜索代码,而不是用正则表达式或者字符串匹配。这样可以让你更精确地找到你想要的代码片段,而不会受到变量名、空格、注释等无关因素的干扰。

ast-grep 支持多种编程语言,包括 Ruby。

因为是在 Ruby China 发帖,所以这次主要想给大家展示一下 ast-grep 的 Ruby 例子,以及它的 Web Playground 中可以调试 Ruby 代码。

同时,我也想和大家比较一下 ast-grep 和论坛坛友的Synvert的区别和优劣。Synvert 是一个可以自动修改 Ruby 代码的工具,它也是基于 AST 的,但是它的目标和方法和 ast-grep 不同。

Hello World 例子

假设我们有一段 Idol 的 class,要去替换其初始化的语句。(改编自 Ruby 官网 hello world)

# The Idol class
class Idol
  def initialize(name)
    @name = name.capitalize
  end
  def debut
    puts "苺プロ所属 #{@name}です!"
  end
end

# Create a new Idol!
oshi = Idol.new("瑠美衣")

# Output "苺プロ所属 瑠美衣です!"
oshi.debut

在 ast-grep 里只要写一句就可以找到 Idol.new

Idol.new($OSHI_NO_KO)

可以在线看 Playground 执行结果。

官网和 Playground

ast-grep 的官网有详细的文档和例子。对于 Ruby 而言,Ruby Example Catalog 收集了一些例子。也包括了 migrate Rails API 的实用例子。

除了查看文档和例子,你还可以在 ast-grep 的Web Playground中在线调试 Ruby 代码。 Web Playground 是一个网页版的交互式环境,你可以在左边输入 Ruby 代码,然后在右边输入 AST 模式,就可以看到匹配结果。你匹配结果还会在左边的代码中高亮显示对应的位置。这样,你就可以很方便地测试和调整你的 AST 模式,直到达到你想要的效果。

除了模式以外,ast-grep 也有更高级的YAML功能,可以更准确匹配代码。也可以当 linter 来使用。

和 Synvert 的比较

Ruby 论坛里已经有 Synvert 的介绍啦。相比 Synvert,ast-grep 是基于 tree-sitter 实现的,支持的语言也更多一点。此外,默认的接口形式上,ast-grep 的模式匹配也简单一点。

比如 把 map + flatten 转成 flat_map 的转换,

[1, 2, 3, 4].map { |e| [e, e] }.flatten
# => 
[1, 2, 3, 4].flat_map { |e| [e, e] }

Synvert 的核心逻辑是这样的:

find_node '.send
            [receiver=.block
              [caller=.send[message=map]]]
            [message=flatten]
            [arguments.size=0]' do
  delete :message, :dot
  replace 'receiver.caller.message', with: 'flat_map'
end

这段代码还不能直接跑,需要加入 Synvert 的一些 boilerplate 代码

而 ast-grep 的规则可以这么写,在命令行可以做完代码转换

sg --pattern '$LIST.map {|$V| $E }.flatten ' --rewrite '$LIST.flat_map { |$V| $E }'

ast-grep 代码重写在线 Demo

以上 Ruby 例子可以看到,ast-grep 的 pattern 更简洁而且直观。你只需要用$符号来表示变量,就可以构造出各种各样的 AST 模式。

以上就是 ast-grep 的介绍,希望能帮助大家在工作或项目中用到。谢谢支持!

这个有点难度 感谢楼主分享知识

jicheng1014 回复

感谢评论感谢支持!

搜了一下还看到了楼主的另外一篇,的确有难度。

hooopo 将本帖设为了精华贴。 07月25日 14:48

此类工具会不会被 ai 替代?

zhongsheng 回复

目前还不会,如果以后 transformer 的 context 能扩大(比如 RetNet),或者能生成 graph 的话可能还能代替一部分

从实用性角度上来讲,我不会觉得 AI 工具写一句 prompt 比写 pattern 简单。

👍 终于支持 Ruby 了

ericguo 回复

感谢反馈!如果有可能的话,能否告诉我哪里比较复杂吗?我尽量修改产品或者多写点教程

numbcoder 回复

感谢关注!感谢支持!

话说 Ruby 社区的群友有会日文的吗😂 ,例子里的梗有木有人接

需要 登录 后方可回复, 如果你还没有账号请 注册新账号