Created
November 24, 2011 19:14
-
-
Save xaviershay/1392039 to your computer and use it in GitHub Desktop.
Simple rack app with routing. Is this possible with http_router?
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require 'rack/request' | |
require 'rack/response' | |
class App | |
attr_accessor :provider | |
# This constructor DI is not possible in Sinatra(?), since the framework | |
# creates the new instance for you. | |
def initialize(provider) | |
@provider = provider | |
end | |
def call(env) | |
request = Rack::Request.new(env) | |
router.process(request).finish | |
end | |
# Can't figure out how to re-use http_router in this case, | |
# it operates at the middleware level. Maybe I can extract | |
# the matched path out of rack.env? | |
def router | |
@router ||= Router.build do |b| | |
id = "([0-9a-z:_]+)" | |
b.get '/' do |_| | |
Rack::Response.new('Home Page') | |
end | |
b.put "/entity/#{id}" do |_, entity_id| | |
provider.create_entity(entity_id) | |
Rack::Response.new('Created') | |
end | |
end | |
end | |
end | |
class Router | |
METHODS = 1 | |
def initialize(routes) | |
@routes = compile(routes) | |
end | |
# Returns a `Rack::Response` | |
def process(request) | |
route, params = match_route(request.path_info) | |
if route | |
action = route[METHODS][request.request_method] | |
if action | |
action.call(request, *params) | |
else | |
respond(406, "NOT ACCEPTABLE") | |
end | |
else | |
respond(404, "NOT FOUND") | |
end | |
end | |
def self.build(&block) | |
builder = Builder.new | |
block.call(builder) | |
builder.build | |
end | |
class Builder | |
def initialize | |
@map = {} | |
end | |
def get(path, &block) | |
route_with_method('GET', path, &block) | |
end | |
def put(path, &block) | |
route_with_method('PUT', path, &block) | |
end | |
def post(path, &block) | |
route_with_method('POST', path, &block) | |
end | |
def route_with_method(method, path, &block) | |
@map[path] ||= {} | |
@map[path][method] = block | |
end | |
def build | |
Router.new(@map) | |
end | |
end | |
private | |
attr_reader :config, :routes | |
def respond(code, description) | |
Rack::Response.new([description], code).tap do |response| | |
response.headers['Content-Type'] = 'text/plain' | |
end | |
end | |
def match_route(path) | |
params = nil | |
[routes.detect {|regex, _| | |
params = path.match(regex) | |
}, params ? params.captures : nil] | |
end | |
def compile(routes) | |
Hash[routes.map {|path, mappings| | |
[Regexp.new("^%s$" % path), mappings] | |
}] | |
end | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require './app' | |
bogus_provider = Class.new do | |
def create_entity(id) | |
# derp | |
end | |
end | |
run App.new(bogus_provider) |
So I guess I'm not after routing then so much as "path interpretation" - I don't want to have to write the regex matching stuff. http_router
for instance can use a much more efficient hash lookup algorithm.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Router:
entity: