Skip to content

Instantly share code, notes, and snippets.

@JoshCheek
Created September 13, 2019 16:32
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save JoshCheek/9e5b86a76803972e3314b25c3d873cca to your computer and use it in GitHub Desktop.
Save JoshCheek/9e5b86a76803972e3314b25c3d873cca to your computer and use it in GitHub Desktop.
Example of making a Rails inspired minimalist web framework for Rack
# ru means "rackup"
class Object
private def erb(text)
ERB.new(text).result(binding)
end
end
class MyRails
attr_accessor :routes
def call(env)
routes.each do |path, (controller, method)|
regex = Regexp.new "^#{path}$".gsub(/:\w+/) { |name| "(?<#{name}>[^/]+)" }
match = regex.match env['REQUEST_PATH']
next unless match
params = match.named_captures.transform_keys do |key|
key[1..-1].to_sym
end
return controller.new(env, params).call(method)
end
[404, {'Content-Type' => 'text/html'}, [erb(<<~HTML)]]
<h1>Not Found</h1>
<p>Could not find a route for #{env['REQUEST_PATH'].inspect}</p>
<h2>Known Routes</h2>
<ul>
<% routes.each do |path, _| %>
<li><%= path.inspect %></li>
<% end %>
</ul>
HTML
end
end
User = Struct.new :name
class ApplicationController
attr_reader :params
def initialize(env, params)
@env = env
@params = params
@status = 200
@headers = {'Content-Type' => 'text/html'}
end
def call(method)
[@status, @headers, [erb(send(method))]]
end
end
class UsersController < ApplicationController
def index
@users = [User.new("Josh"), User.new("Nurudeen")]
<<~HTML
<h1>users</h1>
<ul>
<% @users.each do |user| %>
<li><%= user.name %></li>
<% end %>
</ul>
HTML
end
def show
@user = User.new(params[:name])
<<~HTML
<h1><%= @user.name %></h1>
HTML
end
end
rails = MyRails.new
rails.routes = {
'/users' => [UsersController, :index],
'/users/:name' => [UsersController, :show],
}
class RemoveTrailingSlashesMiddleware
def initialize(app)
@app = app
end
def call(env)
env['REQUEST_PATH'].chomp! "/"
@app.call(env)
end
end
use RemoveTrailingSlashesMiddleware
run(rails)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment