# Influenced by ActionDispatch::Routing::RoutesInspector require 'delegate' module Caliper class RouteWrapper < SimpleDelegator def endpoint unless rack_app "#{controller}##{action}" end # ignore rack apps for now (don't want to know about redirects) #rack_app ? rack_app.inspect : "#{controller}##{action}" end def constraints requirements.except(:controller, :action) end def rack_app(app = self.app) @rack_app ||= begin class_name = app.class.name.to_s if class_name == "ActionDispatch::Routing::Mapper::Constraints" rack_app(app.app) elsif ActionDispatch::Routing::Redirect === app || class_name !~ /^ActionDispatch::Routing/ app end end end def verb super.source.gsub(/[$^]/, '') end def path super.spec.to_s end def name super.to_s end def reqs @reqs ||= begin reqs = endpoint # commenting out for now until tested and really required #reqs += " #{constraints.to_s}" unless constraints.empty? reqs end end def controller requirements[:controller] || ':controller' end def action requirements[:action] || ':action' end def internal? path =~ %r{/rails/info.*|^#{::Rails.application.config.assets.prefix}} end def engine? rack_app && rack_app.respond_to?(:routes) end end class RouteInspector def initialize @engines = Hash.new end def routes(all_routes) routes = collect_routes(all_routes) routes + routes_for_engines end def collect_routes(routes) routes = routes.collect do |route| 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 } unless route.reqs.nil? end.compact end def collect_engine_routes(route) name = route.endpoint return unless route.engine? return if @engines[name] routes = route.rack_app.routes if routes.is_a?(ActionDispatch::Routing::RouteSet) @engines[name] = collect_routes(routes.routes) end end def routes_for_engines @engines.map do |name, routes| formatted_routes(routes) end.flatten end end end