Skip to content

Commit

Permalink
Reorganize frankie a bit.
Browse files Browse the repository at this point in the history
  • Loading branch information
josevalim committed Jun 26, 2011
1 parent 50f0341 commit 821e5fa
Show file tree
Hide file tree
Showing 4 changed files with 104 additions and 102 deletions.
2 changes: 1 addition & 1 deletion lib/frankie.ex
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ module Frankie
% Frankie-#{APP_NAME}).
def run(server, app, options := {})
options = options.set_new 'name, "Frankie-#{self.__module_name__}".to_atom
wrapper = #Frankie::App::Wrapper(app)
wrapper = #Frankie::Routes::Wrapper(app)
ExBridge.start server, wrapper, options
end
end
111 changes: 10 additions & 101 deletions lib/frankie/app.ex
Original file line number Diff line number Diff line change
@@ -1,134 +1,43 @@
module Frankie::App
% An instance of the wrapper object is given to ExBridge when
% MyApp.run is invoked. The wrapper is initialized with the MyApp object.
%
% On each request, the handle_http method is invoked which then tries to
% find a matching route. If a matching route is found, we call it, otherwise
% we eventually call the error route with 404 status code. The wrapper is
% responsible to manage the result given and finally dispatch the response
% object.
module Wrapper
def __bound__(app)
@('routes: app.routes, 'app: #app())
end

def handle_http(request, response)
verb = request.request_method
path = request.path_chars
route = find_route(@routes, verb, path, request)
result = route.call(@app, request, response)

if result.__module_name__ == 'String::Behavior
result = response.body(result)
end
result.dispatch!
end
private
def find_route([h|t], verb, path, request)
result =
if h.__module_name__ == 'Frankie::App::Route
h.match?(verb, path) % Optimize the most common case.
else
h.match?(request)
end

if result
h
else
find_route(t, verb, path, request)
end
end

def find_route([], _, _, _)
#Frankie::App::ErrorRoute(404)
end
end

% Main route object that asserts for the verb,
% route and dispatches the stored method/callback.
module Route
attr_reader ['verb, 'path, 'method]
def __bound__(verb, path, method)
@('verb: verb, 'path: path.to_char_list, 'method: method)
end

def match?(verb, path)
@verb == verb andalso @path == path
end

def call(app, request, response)
args = case @method.arity
match 2
[request, response]
match 1
[response]
else
[]
end

@method.apply_to(app, args)
end
end

% Route that handle errors.
% TODO Make this invoke a hook in the app.
module ErrorRoute
def __bound__(status)
@('status, status)
end
def match?(_)
true
end
def call(_app, _request, response)
response.set(@status, {}, "Status: #{@status}")
end
end
module Definition
module Routing
% Adds a new route to the route set. The route object
% only needs to respond to a `match?` which receives the
% request object and to `call` which receives the application
% (not instanciated yet), request and response objects.
def bare_route(route_object)
def route(route_object)
update_ivar 'routes, _.push(route_object)
end
% Add a new route with a verb, path and the callback.
def route(verb, path, method)
bare_route(#Frankie::App::Route(verb, path, method))
def verb_route(verb, path, method)
route(#Frankie::Routes::VerbRoute(verb, path, method))
end
def get(route, method)
route 'GET, route, method
verb_route 'GET, route, method
end

def post(route, method)
route 'POST, route, method
verb_route 'POST, route, method
end
def put(route, method)
route 'PUT, route, method
verb_route 'PUT, route, method
end

def patch(route, method)
route 'PATCH, route, method
verb_route 'PATCH, route, method
end
def delete(route, method)
route 'DELETE, route, method
verb_route 'DELETE, route, method
end
end

attr_reader ['routes]
def __mixed_in__(base)
base.set_ivar('routes, [])
base.using Frankie::App::Definition
base.using Frankie::App::Routing
end
end
91 changes: 91 additions & 0 deletions lib/frankie/routes.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
module Frankie::Routes
% Wraps the given application in a format that is acceptable for ExBridge.
%
% On each request, the handle_http method is invoked which then tries to
% find a matching route. If a matching route is found, we call it, otherwise
% we eventually call the error route with 404 status code. The wrapper is
% responsible to manage the result given and finally dispatch the response
% object.
module Wrapper
def __bound__(app)
@('routes: app.routes, 'app: #app())
end

def handle_http(request, response)
verb = request.request_method
path = request.path_chars
route = find_route(@routes, verb, path, request)
result = route.call(@app, request, response)

if result.__module_name__ == 'String::Behavior
result = response.body(result)
end
result.dispatch!
end
private
def find_route([h|t], verb, path, request)
result =
if h.respond_to?('match?, 2)
h.match?(verb, path) % Optimize the most common case.
else
h.match?(request)
end

if result
h
else
find_route(t, verb, path, request)
end
end

def find_route([], _, _, _)
#Frankie::Routes::ErrorRoute(404)
end
end

% Main route object that asserts for the verb,
% route and dispatches the stored method/callback.
module VerbRoute
attr_reader ['verb, 'path, 'method]
def __bound__(verb, path, method)
@('verb: verb, 'path: path.to_char_list, 'method: method)
end

def match?(verb, path)
@verb == verb andalso @path == path
end

def call(app, request, response)
args = case @method.arity
match 2
[request, response]
match 1
[response]
else
[]
end

@method.apply_to(app, args)
end
end

% Route that handle errors.
% TODO Make this invoke a hook in the app.
module ErrorRoute
def __bound__(status)
@('status, status)
end

def match?(_)
true
end

def call(_app, _request, response)
response.set(@status, {}, "Status: #{@status}")
end
end
end
2 changes: 2 additions & 0 deletions lib/frankie/templates.ex
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
module Frankie::Templates
end

0 comments on commit 821e5fa

Please sign in to comment.