Class: RailsAiContext::Introspectors::RouteIntrospector

Inherits:
Object
  • Object
show all
Defined in:
lib/rails_ai_context/introspectors/route_introspector.rb

Overview

Extracts route information from the Rails router including HTTP verb, path, controller#action, and route constraints.

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(app) ⇒ RouteIntrospector

Returns a new instance of RouteIntrospector.



10
11
12
# File 'lib/rails_ai_context/introspectors/route_introspector.rb', line 10

def initialize(app)
  @app = app
end

Instance Attribute Details

#appObject (readonly)

Returns the value of attribute app.



8
9
10
# File 'lib/rails_ai_context/introspectors/route_introspector.rb', line 8

def app
  @app
end

Instance Method Details

#callHash

Returns routes grouped by controller.

Returns:

  • (Hash)

    routes grouped by controller



15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
# File 'lib/rails_ai_context/introspectors/route_introspector.rb', line 15

def call
  routes = extract_routes
  root = routes.find { |r| r[:path] == "/" && r[:verb]&.include?("GET") }

  {
    total_routes: routes.size,
    by_controller: group_by_controller(routes),
    api_namespaces: detect_api_namespaces(routes),
    mounted_engines: detect_mounted_engines,
    # Everything routable that has no controller#action: Engine mounts
    # AND bare rack apps (propshaft's /assets mounts a Server instance,
    # which detect_mounted_engines' Class check can't see).
    unrouted_mounts: count_unrouted_mounts,
    root_route: root ? "#{root[:controller]}##{root[:action]}" : nil
  }
rescue => e
  { error: e.message }
end

#static_callObject

Static tier: answer route questions from config/routes.rb alone. Output mirrors the runtime shape exactly so tools, resources, and serializers need no static-awareness of their own. Routes behind dynamic constructs (devise_for, draw, concerns) are counted in :dynamic_routes rather than fabricated.



39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
# File 'lib/rails_ai_context/introspectors/route_introspector.rb', line 39

def static_call
  routes_path = File.join(app.root.to_s, "config", "routes.rb")
  return { error: "config/routes.rb not found in #{app.root}" } unless File.exist?(routes_path)

  ast = SourceIntrospector.walk(routes_path, {
    routes: -> { Listeners::RoutesDslListener.new },
    mounts: -> { Listeners::MountListener.new }
  })
  records = ast[:routes] || []
  entries = records.select { |r| r[:type] == :route }
  dynamic = records.count { |r| r[:type] == :dynamic }

  result = {
    total_routes: entries.size,
    by_controller: group_by_controller(entries),
    api_namespaces: static_api_namespaces(entries),
    mounted_engines: (ast[:mounts] || []).map { |m| { engine: m[:engine], path: m[:path] } },
    root_route: static_root_route(entries),
    note: "Parsed statically from config/routes.rb (app not booted)",
    confidence: Confidence::STATIC
  }
  result[:dynamic_routes] = dynamic if dynamic.positive?
  result
rescue => e
  { error: e.message }
end