Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion lib/rage/cable/cable.rb
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,11 @@ def self.application
end
end

Rage.with_middlewares(application, Rage.config.cable.middlewares)
chain = Rage.with_middlewares(application, Rage.config.cable.middlewares)
application.define_singleton_method(:__rage_app_name) { "Rage::Cable" }
chain.define_singleton_method(:__rage_root_app) { application }

chain
end

# @private
Expand Down
7 changes: 6 additions & 1 deletion lib/rage/cli.rb
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,12 @@ def routes
meta = route[:constraints]
meta.merge!(route[:defaults]) if route[:defaults]

handler = route[:meta][:raw_handler]
raw_handler = route[:meta][:raw_handler]
handler = if raw_handler.respond_to?(:__rage_app_name)
raw_handler.__rage_app_name
else
raw_handler
end
handler = "#{handler} #{meta}" unless meta&.empty?

puts format("%-#{longest_method}s%-#{longest_path}s%s", route[:method], route[:path], handler)
Expand Down
6 changes: 5 additions & 1 deletion lib/rage/openapi/openapi.rb
Original file line number Diff line number Diff line change
Expand Up @@ -67,13 +67,17 @@ def self.application(namespace: nil)
end
end

if Rage.config.middleware.include?(Rage::Reloader)
chain = if Rage.config.middleware.include?(Rage::Reloader)
Rage.with_middlewares(app, [Rage::Reloader])
elsif defined?(ActionDispatch::Reloader) && Rage.config.middleware.include?(ActionDispatch::Reloader)
Rage.with_middlewares(app, [ActionDispatch::Reloader])
else
app
end

chain.define_singleton_method(:__rage_app_name) { "Rage::OpenAPI" }

chain
end

# Build an OpenAPI specification for the application.
Expand Down
9 changes: 7 additions & 2 deletions lib/rage/router/backend.rb
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,13 @@ def reset_routes
def mount(path, handler, methods)
raise ArgumentError, "Mount handler should respond to `call`" unless handler.respond_to?(:call)

raw_handler = handler
handler = wrap_in_rack_session(handler) if handler.respond_to?(:name) && handler.name == "Sidekiq::Web"
raw_handler = handler.respond_to?(:__rage_root_app) ? handler.__rage_root_app : handler

handler = if handler.respond_to?(:name) && handler.name == "Sidekiq::Web"
wrap_in_rack_session(handler)
else
raw_handler
end

app = ->(env, _params) do
# rewind `rack.input` in case mounted application needs to access the request body;
Expand Down
172 changes: 172 additions & 0 deletions spec/rage/cli_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -601,4 +601,176 @@ def def_subscriber(name, subscribe_to:)
end
end
end

describe "#routes" do
subject { rage_cli.routes }

let(:router) { instance_double("Rage::Router::Backend") }

before do
allow(rage_cli).to receive(:environment)
allow(Rage).to receive(:__router).and_return(router)
allow(router).to receive(:routes).and_return(routes)
end

context "when there are no routes" do
let(:routes) { [] }

it "outputs only the header" do
expect { subject }.to output(/Verb\s+Path\s+Controller#Action/).to_stdout
end
end

context "when there is a single route" do
let(:routes) do
[
{ method: "GET", path: "/", meta: { raw_handler: "application#index" }, constraints: {}, defaults: nil }
]
end

it "outputs the route" do
expect { subject }.to output(/GET\s+\/\s+application#index/).to_stdout
end
end

context "when there are multiple routes" do
let(:routes) do
[
{ method: "GET", path: "/users", meta: { raw_handler: "users#index" }, constraints: {}, defaults: nil },
{ method: "POST", path: "/users", meta: { raw_handler: "users#create" }, constraints: {}, defaults: nil },
{ method: "GET", path: "/users/:id", meta: { raw_handler: "users#show" }, constraints: {}, defaults: nil }
]
end

it "outputs all routes" do
output = capture_stdout { subject }

expect(output).to match(/GET\s+\/users\s+users#index/)
expect(output).to match(/POST\s+\/users\s+users#create/)
expect(output).to match(/GET\s+\/users\/:id\s+users#show/)
end
end

context "when routes have the same path and handler" do
let(:routes) do
[
{ method: "GET", path: "/resource", meta: { raw_handler: "resource#action" }, constraints: {}, defaults: nil },
{ method: "POST", path: "/resource", meta: { raw_handler: "resource#action" }, constraints: {}, defaults: nil }
]
end

it "groups the methods with a pipe" do
expect { subject }.to output(/GET\|POST\s+\/resource\s+resource#action/).to_stdout
end
end

context "when a route has constraints" do
let(:routes) do
[
{ method: "GET", path: "/users/:id", meta: { raw_handler: "users#show" }, constraints: { id: /\d+/ }, defaults: nil }
]
end

it "outputs the route with constraints" do
expect { subject }.to output(/GET\s+\/users\/:id\s+users#show \{:?id(:|=>)/).to_stdout
end
end

context "when a route has defaults" do
let(:routes) do
[
{ method: "GET", path: "/users", meta: { raw_handler: "users#index" }, constraints: {}, defaults: { format: :json } }
]
end

it "outputs the route with defaults" do
expect { subject }.to output(/GET\s+\/users\s+users#index \{:?format(:|=>)\s?:json\}/).to_stdout
end
end

context "when filtering routes with --grep option" do
subject { rage_cli.routes }

let(:routes) do
[
{ method: "GET", path: "/users", meta: { raw_handler: "users#index" }, constraints: {}, defaults: nil },
{ method: "GET", path: "/posts", meta: { raw_handler: "posts#index" }, constraints: {}, defaults: nil },
{ method: "POST", path: "/users", meta: { raw_handler: "users#create" }, constraints: {}, defaults: nil }
]
end

let(:rage_cli) { described_class.new([], grep: "users") }

it "only outputs matching routes" do
output = capture_stdout { subject }

expect(output).to match(/users#index/)
expect(output).to match(/users#create/)
expect(output).not_to match(/posts#index/)
end
end

context "when filtering routes by method" do
subject { rage_cli.routes }

let(:routes) do
[
{ method: "GET", path: "/users", meta: { raw_handler: "users#index" }, constraints: {}, defaults: nil },
{ method: "POST", path: "/users", meta: { raw_handler: "users#create" }, constraints: {}, defaults: nil }
]
end

let(:rage_cli) { described_class.new([], grep: "POST") }

it "only outputs routes matching the method" do
output = capture_stdout { subject }

expect(output).to match(/POST\s+\/users\s+users#create/)
expect(output).not_to match(/GET\s+\/users\s+users#index/)
end
end

context "when a route is a mounted app" do
let(:mounted_app) do
Class.new do
def self.__rage_app_name
"Sidekiq::Web"
end
end
end

let(:routes) do
[
{ method: "GET", path: "/sidekiq", meta: { raw_handler: mounted_app, mount: true }, constraints: {}, defaults: nil }
]
end

it "outputs the mounted app name" do
expect { subject }.to output(/\s+\/sidekiq\s+Sidekiq::Web/).to_stdout
end
end

context "when a mounted route ends with *" do
let(:routes) do
[
{ method: "GET", path: "/sidekiq/*", meta: { raw_handler: "SidekiqWeb", mount: true }, constraints: {}, defaults: nil }
]
end

it "does not output the route" do
output = capture_stdout { subject }

expect(output).not_to match(/\/sidekiq\/\*/)
end
end

def capture_stdout
original_stdout = $stdout
$stdout = StringIO.new
yield
$stdout.string
ensure
$stdout = original_stdout
end
end
end
30 changes: 30 additions & 0 deletions spec/router/mount_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -102,4 +102,34 @@ def call(env)
end
end
end

context "with root app" do
let(:app) do
Class.new do
def self.call(_)
:app_response
end
end
end

let(:middleware) do
Class.new do
def self.call(_)
:middleware_response
end
end
end

before do
root_app = app
middleware.define_singleton_method(:__rage_root_app) { root_app }
end

it "delegates to root app" do
router.mount("/test", middleware, %w(GET))

result, _ = perform_get_request("/test")
expect(result).to eq(:app_response)
end
end
end
Loading