Skip to content

Instantly share code, notes, and snippets.

@jackwillis
Last active April 18, 2024 01:07
Show Gist options
  • Save jackwillis/e9c096e5270687532cb8f47c8ffa8766 to your computer and use it in GitHub Desktop.
Save jackwillis/e9c096e5270687532cb8f47c8ffa8766 to your computer and use it in GitHub Desktop.
Sinatra scripts
require 'sinatra'
get '/' do
'Hello from root'
end
get '/foo' do
'Hello from GET /foo'
end
post '/foo' do
'Hello from POST /foo'
end
get '/bar' do
'Hello from GET /bar'
end
#!/usr/bin/env ruby
require 'pp'
require 'sinatra'
require_relative '../lib/route_source_location_tracker'
class Sinatra::Application
register RouteSourceLocationTracker
end
require_relative '../app'
# Compute the array of HTTP endpoints and source code locations
routes_data = RouteSourceLocationTracker.routes_with_locations(Sinatra::Application)
output_max_width = 999
PP.pp routes_data, $stdout, output_max_width
exit # before the web server starts
require_relative 'app'
run Sinatra::Application.run!
# This mixin overrides Sinatra's HTTP verb methods that define routes (+get+, +post+, +put+, etc.)
# If you register this mixin, then whenever you define a route (HTTP endpoint),
# it will store the method, path, and source location
# in +:route_source_locations+ in the Sinatra app settings.
module RouteSourceLocationTracker
def self.registered(app)
app.set :route_source_locations, {}
%w[get post put delete patch options].each do |method_name|
override_route_method(app, method_name)
end
end
def self.override_route_method(app, method_name)
upcase_http_method = method_name.upcase
app.define_singleton_method(method_name) do |path_templates, opts = {}, &block|
block_source_location = block.source_location.join(':')
# Sinatra uses Mustermann patterns when defining routes.
# Route definitions in Sinatra can have multiple patterns,
# each of which can expand to multiple paths.
path_pattern = Mustermann.new(path_templates)
paths = path_pattern.to_templates
paths.each do |path|
route_source_locations[path] ||= {}
route_source_locations[path][upcase_http_method] ||= []
route_source_locations[path][upcase_http_method] << block_source_location
end
super(path_templates, opts, &block)
end
end
# Join the arrays of routes and their source code locations
def self.routes_with_locations(app)
data = {}
app.routes.each do |(method_name, routes)|
upcase_http_method = method_name.upcase
next if upcase_http_method == 'HEAD'
routes.each do |route|
path_pattern = route[0]
paths = path_pattern.to_templates
paths.each do |path|
source_locations = app.settings.route_source_locations.dig(path, upcase_http_method) || []
data[path] ||= {}
data[path][upcase_http_method] = source_locations
end
end
end
data.sort.to_h
end
end
{"/"=>{"GET"=>["/private/tmp/sinatra/app.rb:3"]},
"/bar"=>{"GET"=>["/private/tmp/sinatra/app.rb:15"]},
"/foo"=>{"GET"=>["/private/tmp/sinatra/app.rb:7"],"POST"=>["/private/tmp/sinatra/app.rb:11"]}}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment