试图了解Journey :: Path :: Pattern#spec(Rails路由的内部)

问题描述 投票:0回答:1

上下文:我正在解决一个问题,我需要一个外部审计程序才能理解和“应用”Rails路由。编写这个外部程序的一个选择可能是解析rake routes的输出,但这会不必要地最终复制解析这些路由并将它们转换为结构良好的Journey::Route对象的代码。

因此,我的计划是将Rails.application.routes输出为外部程序可以理解的通用格式(YAML或JSON),并且可以基于此数据构建路由器。

问题:鉴于此背景,我试图理解Journey::Path::Paternet#spec属性的结构,该属性发生在Journey::Route对象内部,恰好是所有动作的中心。

例如,以下路线 - /posts/:id - 转换为以下“规范” -

 #<Journey::Nodes::Cat:0x00007ff193327ee0
 @left=
  #<Journey::Nodes::Cat:0x00007ff193308630
   @left=
    #<Journey::Nodes::Cat:0x00007ff1933087e8
     @left=
      #<Journey::Nodes::Cat:0x00007ff193308bf8
       @left=#<Journey::Nodes::Slash:0x00007ff193308d38 @left="/", @memo=nil>,
       @memo=nil,
       @right=#<Journey::Nodes::Literal:0x00007ff193308c48 @left="posts", @memo=nil>>,
     @memo=nil,
     @right=#<Journey::Nodes::Slash:0x00007ff193308a40 @left="/", @memo=nil>>,
   @memo=nil,
   @right=#<Journey::Nodes::Symbol:0x00007ff1933086d0 @left=":id", @memo=nil, @regexp=/[^\.\/\?]+/>>,
 @memo=nil,
 @right=
  #<Journey::Nodes::Group:0x00007ff193309c10
   @left=
    #<Journey::Nodes::Cat:0x00007ff193308220
     @left=#<Journey::Nodes::Dot:0x00007ff1933084f0 @left=".", @memo=nil>,
     @memo=nil,
     @right=#<Journey::Nodes::Symbol:0x00007ff193308338 @left=":format", @memo=nil, @regexp=/[^\.\/\?]+/>>,
   @memo=nil>>
  • Journey::Nodes::Cat对象中的左/右属性是什么?是什么决定哪个令牌将“离开”哪个令牌将“正确”
  • 这看起来很像二叉树,但为什么是第一个令牌(即第一个/),“最里面的”(或叶子节点)?它不应该是“最外层”(或根节点)吗?
  • 在执行路由匹配时,有效的方法是走下这个数据结构?
ruby-on-rails routes internals journey
1个回答
0
投票

Journey基于匹配路线的有限状态机,内置可视化器(需要graphviz):

File.open('routes.html', 'wt'){|f| f.write Rails.application.routes.router.visualizer }

Journey::Nodes::Cat只是你可以遇到的节点类型之一,它是与路径expressions中的grammar, see parser.y规则匹配的二进制节点,左边是第一个expressionright是所有其他,这产生了消耗所有表达式的循环。

关于外部路由分析的其他想法:路由不能转储到通用情况下的静态文件中,因为它们可以包含:

  • 使用非纯函数的动态约束(例如 - get :r, constraints: ->{rand(2)>0},想法是结果可以取决于请求,时间或状态之外的东西等)当这些存在时 - 偶数路由器本身可以在第二次运行时产生不同的结果同样的要求。
  • 安装的机架应用程序 - 可以有硬编码或非轨道路由器
  • rails引擎 - 拥有rails路由器,比通用机架应用程序更容易,但是具有挂载点并融入主应用范围的技巧

但是对于简单的情况,你可以使用rails用于ActionDispatch::Routing::RoutesInspectorrake routes并获得更好的结构化路由信息,只需解析后一个输出。

在宝石routes_coverage我这样做:

class Inspector < ActionDispatch::Routing::RoutesInspector
  def collect_all_routes
    res = collect_routes(@routes)
    @engines.each do |engine_name, engine_routes|
      res += engine_routes.map{|er|
        er.merge({ engine_name: engine_name })
      }
    end
    res
  end

  def collect_routes(routes)
    routes.collect do |route|
      ActionDispatch::Routing::RouteWrapper.new(route)
    end.reject do |route|
      route.internal?
    end.collect do |route|
      collect_engine_routes(route)

      { name:   route.name,
        verb:   route.verb,
        path:   route.path,
        reqs:   route.reqs,
        original: route,
      }
    end
  end

res = Inspector.new(Rails.application.routes.routes.routes).collect_all_routes
© www.soinside.com 2019 - 2024. All rights reserved.