Skip to content

Commit

Permalink
Introducing routes inspector
Browse files Browse the repository at this point in the history
  • Loading branch information
jodosha committed Nov 6, 2014
1 parent 61722b8 commit 60c4529
Show file tree
Hide file tree
Showing 5 changed files with 356 additions and 1 deletion.
26 changes: 26 additions & 0 deletions lib/lotus/router.rb
Expand Up @@ -934,5 +934,31 @@ def path(route, *args)
def url(route, *args)
@router.url(route, *args)
end

# Returns an routes inspector
#
# @since x.x.x
#
# @see Lotus::Routing::RoutesInspector
#
# @example
# require 'lotus/router'
#
# router = Lotus::Router.new do
# get '/', to: 'home#index'
# get '/login', to: 'sessions#new', as: :login
# post '/login', to: 'sessions#create'
# delete '/logout', to: 'sessions#destroy', as: :logout
# end
#
# puts router.inspector
# # => GET, HEAD / Home::Index
# login GET, HEAD /login Sessions::New
# POST /login Sessions::Create
# logout GET, HEAD /logout Sessions::Destroy
def inspector
require 'lotus/routing/routes_inspector'
Routing::RoutesInspector.new(@router.routes)
end
end
end
38 changes: 37 additions & 1 deletion lib/lotus/routing/endpoint.rb
Expand Up @@ -30,6 +30,20 @@ class EndpointNotFound < ::StandardError
# get '/rack-app', to: RackApp.new
# end
class Endpoint < SimpleDelegator
# @since x.x.x
def inspect
case __getobj__
when Proc
source, line = __getobj__.source_location
lambda_inspector = " (lambda)" if __getobj__.lambda?

"#<Proc@#{ source }:#{ line }#{ lambda_inspector }>"
when Class
__getobj__
else
"#<#{ __getobj__.class }>"
end
end
end

# Routing endpoint
Expand Down Expand Up @@ -103,9 +117,31 @@ def call(env)
obj.call(env)
end

# @since x.x.x
def inspect
# TODO review this implementation once the namespace feature will be
# cleaned up.
result = klass rescue nil

if result.nil?
result = @name
result = "#{ @namespace }::#{ result }" if @namespace != Object
end

result
end

private
# @since 0.1.0
# @api private
def obj
Utils::Class.load!(@name, @namespace).new
klass.new
end

# @since x.x.x
# @api private
def klass
Utils::Class.load!(@name, @namespace)
rescue NameError => e
raise EndpointNotFound.new(e.message)
end
Expand Down
96 changes: 96 additions & 0 deletions lib/lotus/routing/routes_inspector.rb
@@ -0,0 +1,96 @@
module Lotus
module Routing
# Routes inspector
#
# @since x.x.x
class RoutesInspector
# Default route formatter
#
# @since x.x.x
# @api private
FORMATTER = "%<name>20s %<methods>-10s %<path>-30s %<endpoint>-30s\n".freeze

# Instantiate a new inspector
#
# @return [Lotus::Routing::RoutesInspector] the new instance
#
# @since x.x.x
# @api private
def initialize(routes)
@routes = routes
end

# Return a formatted string that describes all the routes
#
# @param formatter [String] the optional formatter for a route
#
# @return [String] routes pretty print
#
# @since x.x.x
#
# @see Lotus::Routing::RoutesInspector::FORMATTER
#
# @example Default formatter
# require 'lotus/router'
#
# router = Lotus::Router.new do
# get '/', to: 'home#index'
# get '/login', to: 'sessions#new', as: :login
# post '/login', to: 'sessions#create'
# delete '/logout', to: 'sessions#destroy', as: :logout
# end
#
# puts router.inspector.to_s
# # => GET, HEAD / Home::Index
# login GET, HEAD /login Sessions::New
# POST /login Sessions::Create
# logout GET, HEAD /logout Sessions::Destroy
#
# @example Custom formatter
# require 'lotus/router'
#
# router = Lotus::Router.new do
# get '/', to: 'home#index'
# get '/login', to: 'sessions#new', as: :login
# post '/login', to: 'sessions#create'
# delete '/logout', to: 'sessions#destroy', as: :logout
# end
#
# formatter = "| %{methods} | %{name} | %{path} | %{endpoint} |\n"
#
# puts router.inspector.to_s(formatter)
# # => | GET, HEAD | | / | Home::Index |
# | GET, HEAD | login | /login | Sessions::New |
# | POST | | /login | Sessions::Create |
# | GET, HEAD | logout | /logout | Sessions::Destroy |
def to_s(formatter = FORMATTER)
result = ""

@routes.each do |route|
result << formatter % inspect_route(route)
end

result
end

private
# Return a Hash compatible with formatter
#
# @return [Hash] serialized route
#
# @since x.x.x
# @api private
#
# @see Lotus::Routing::RoutesInspector#FORMATTER
# @see Lotus::Routing::RoutesInspector#to_s
def inspect_route(route)
Hash[
name: route.name,
methods: route.request_methods.to_a.join(", "),
path: route.original_path,
endpoint: route.dest.inspect
]
end
end
end
end
182 changes: 182 additions & 0 deletions test/routing/routes_inspector_test.rb
@@ -0,0 +1,182 @@
require 'test_helper'
require 'lotus/routing/routes_inspector'

describe Lotus::Routing::RoutesInspector do
describe '#to_s' do
before do
@path = ::File.expand_path(__FILE__)
end

describe 'named routes with procs' do
before do
@router = Lotus::Router.new do
get '/login', to: ->(env) { }, as: :login
get '/logout', to: Proc.new {|env| }, as: :logout
end
end

it 'inspects routes' do
expected = <<-ROUTES
login GET, HEAD /login #<Proc@#{ @path }:13 (lambda)>
logout GET, HEAD /logout #<Proc@#{ @path }:14>
ROUTES

@router.inspector.to_s.must_equal(expected)
end
end

describe 'controller action syntax' do
before do
@router = Lotus::Router.new do
get '/controller/action', to: 'welcome#index'
end
end

it 'inspects routes'
# it 'inspects routes' do
# expected = <<-ROUTES
# GET, HEAD /controller/action WelcomeController::Index
# ROUTES

# @router.inspector.to_s.must_equal(expected)
# end
end

describe 'lazy controller and action' do
before do
@router = Lotus::Router.new do
get '/lazy', to: 'sleepy#index'
end

module SleepyController
class Index
end
end
end

after do
Object.__send__(:remove_const, :SleepyController)
end

it 'inspects routes'
# it 'inspects routes' do
# expected = <<-ROUTES
# GET, HEAD /lazy LazyController::Index
# ROUTES

# @router.inspector.to_s.must_equal(expected)
# end
end

describe 'missing controller and action' do
before do
@router = Lotus::Router.new do
get '/missing', to: 'missing#index'
end
end

it 'inspects routes' do
expected = <<-ROUTES
GET, HEAD /missing Missing(::Controller::|Controller::)Index
ROUTES

@router.inspector.to_s.must_equal(expected)
end
end

describe 'class' do
before do
@router = Lotus::Router.new do
get '/class', to: RackMiddleware
end
end

it 'inspects routes'
# it 'inspects routes' do
# expected = <<-ROUTES
# GET, HEAD /class RackMiddleware
# ROUTES

# @router.inspector.to_s.must_equal(expected)
# end
end

describe 'object' do
before do
@router = Lotus::Router.new do
get '/class', to: RackMiddlewareInstanceMethod
get '/object', to: RackMiddlewareInstanceMethod.new
end
end

it 'inspects routes' do
expected = <<-ROUTES
GET, HEAD /class #<RackMiddlewareInstanceMethod>
GET, HEAD /object #<RackMiddlewareInstanceMethod>
ROUTES

@router.inspector.to_s.must_equal(expected)
end
end

describe 'resource' do
before do
@router = Lotus::Router.new do
resource 'identity'
end
end

it 'inspects routes' do
expected = <<-ROUTES
new_identity GET, HEAD /identity/new Identity(::Controller::|Controller::)New
identity POST /identity Identity(::Controller::|Controller::)Create
identity GET, HEAD /identity Identity(::Controller::|Controller::)Show
edit_identity GET, HEAD /identity/edit Identity(::Controller::|Controller::)Edit
identity PATCH /identity Identity(::Controller::|Controller::)Update
identity DELETE /identity Identity(::Controller::|Controller::)Destroy
ROUTES

@router.inspector.to_s.must_equal(expected)
end
end

describe 'resources' do
before do
@router = Lotus::Router.new do
resources 'books'
end
end

it 'inspects routes' do
expected = <<-ROUTES
books GET, HEAD /books Books(::Controller::|Controller::)Index
new_books GET, HEAD /books/new Books(::Controller::|Controller::)New
books POST /books Books(::Controller::|Controller::)Create
books GET, HEAD /books/:id Books(::Controller::|Controller::)Show
edit_books GET, HEAD /books/:id/edit Books(::Controller::|Controller::)Edit
books PATCH /books/:id Books(::Controller::|Controller::)Update
books DELETE /books/:id Books(::Controller::|Controller::)Destroy
ROUTES

@router.inspector.to_s.must_equal(expected)
end
end

describe 'with custom formatter' do
before do
@router = Lotus::Router.new do
get '/login', to: ->(env) { }, as: :login
end
end

it 'inspects routes' do
formatter = "| %{methods} | %{name} | %{path} | %{endpoint} |\n"
expected = <<-ROUTES
| GET, HEAD | login | /login | #<Proc@#{ @path }:168 (lambda)> |
ROUTES

@router.inspector.to_s(formatter).must_equal(expected)
end
end
end
end
15 changes: 15 additions & 0 deletions test/support/fixtures.rb
Expand Up @@ -225,3 +225,18 @@ def parse(body)
result
end
end

class RackMiddleware
def self.call(env)
end
end

class RackMiddlewareInstanceMethod
def call(env)
end
end

module WelcomeController
class Index
end
end

0 comments on commit 60c4529

Please sign in to comment.