继续为 Swift 节点添砖加瓦...
项目地址:https://github.com/jasl/RouterX
最终下决定造这个轮子主要有几个动机:
我发现这几个场景的需求都是一致的并且和我们熟知的 Web 框架中的路由层相似。
利用双休日分析了下C#的ASP.net MVC、PHP 的 Laravel、Symphony,Go 的 HttpRouter 还有若干小型的 Web 框架和 iOS 的 Router 库,首先先给一个结论:
Rails 是 Web 开发最强框架绝对不是偶然的,Journey(tenderlove 为 Rails 设计的路由规则解析库)的原理是为路由设计了一门表达式语言(使用 RACC 定义),然后构造出 AST 进行匹配,没有任何一个语言的同类库把这个问题上升到如此高度去解决。
这并不是炫技,通过这个方式可以实现很多其他途径很难做到的功能并且保持在匹配时的高性能,比如:/articles/(/page/:page)(/sort/:sort)
这种双可选的情况,除了 Rails 没有任何一家可以支持。
另外,Journey 可以把定义好的路由导出成状态迁移图,进行可视化浏览,在 Rails Console 下输入 File.write 'fsm.html', app._routes.router.visualizer
然后去项目目录打开 fsm.html
即可 tenderlove 的示例
不过,Journey 的 Parser 因为是用 RACC 生成的,Swift 下没有类似工具,此外代码没有文档,写得也比较绕(我是没读懂...),所以 RouterX 是基于我的思路实现的,目前功能已经完成。
一个典型的复杂路由:/articles(/page/:page(/per_page/:per_page))(/sort/:sort)(.:format)
可以正确的生成 AST 匹配如下模式
/articles
/articles/sort/:sort
/articles/sort/:sort.:format
/articles/page/:page
/articles/page/:page/sort/:sort
/articles/page/:page/sort/:sort.:format
/articles/page/:page/per_page/:per_page
/articles/page/:page/per_page/:per_page/sort/:sort
/articles/page/:page/per_page/:per_page/sort/:sort.:format
/articles/page/:page/per_page/:per_page.:format
/articles/page/:page.:format
/articles.:format
也可以正确的进行匹配,主要代码都已经用单元测试覆盖好。
我没学过编译原理,之前有请教过 @luikore 大神一些问题,消化一下看看如何重构让代码质量和性能更好。
PS:对 Rails 的路由原理感兴趣的同学可以读一下 Journey into Rails Routing -- an under the hood look at how routing works Rex, Rexical and Rails routing 这两篇文章(这个 Blog 的文章都挺不错的),不过作者后来也是坑掉了...
Go 的 HttpRouter 是利用 Trie 数据结构实现的,在 README 里有讲原理,比较有意思。