Skip to content

Commit

Permalink
Merge pull request #3 from huffman/app_ivars
Browse files Browse the repository at this point in the history
Application ivars and Route matching
  • Loading branch information
josevalim committed Aug 27, 2011
2 parents 0701814 + d0d405e commit 24ddfbc
Show file tree
Hide file tree
Showing 4 changed files with 88 additions and 29 deletions.
12 changes: 9 additions & 3 deletions README.md
Expand Up @@ -67,19 +67,25 @@ Frankie allows you to easily build simple web applications. Here is an example:
"1.2.3"
end
get "/set_cookie", def (request, response)
get "/set_cookie", def
response = response.cookies.set("hello", "world")
response = response.body("Cookie set")
response
end
get "/read_cookie", def (request, response)
get "/read_cookie", def
"#{request.cookies["hello"]}"
end
get "/get_value_param", def (request, response)
get "/get_value_param", def
"Query parameter \"value\" is: #{request.query_params["value"]}"
end

get "/multiply/'arg1/'arg2", def
arg1 = params['arg1].to_i
arg2 = params['arg2].to_i
"#{arg1} * #{arg2} = #{arg1 * arg2}"
end
end

Frankie.run 'mochiweb, MyApp
Expand Down
9 changes: 7 additions & 2 deletions lib/frankie/app.ex
Expand Up @@ -34,10 +34,15 @@ module Frankie::App
end
end

attr_reader ['routes]
attr_reader ['routes, 'request, 'response, 'params]

def __mixed_in__(base)
base.set_ivar('routes, [])
base.using Frankie::App::Routing
end
end
def __bound__(request, response, params)
@('request: request, 'response: response, 'params: params)
end
end

67 changes: 43 additions & 24 deletions lib/frankie/routes.ex
Expand Up @@ -8,14 +8,20 @@ module Frankie::Routes
% object.
module Wrapper
def __bound__(app)
@('routes: app.routes, 'app: #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)
{route, params} = find_route(@routes, verb, path, request)
result =
if route.respond_to?('call, 3)
route.call(#(@app)(request, response, params), request, response)
else
route.call(#(@app)(request, response, params))
end
if result.__module_name__ == 'String::Behavior
result = response.body(result)
Expand All @@ -28,21 +34,21 @@ module Frankie::Routes

def find_route([h|t], verb, path, request)
result =
if h.respond_to?('match?, 2)
h.match?(verb, path) % Optimize the most common case.
if h.respond_to?('match_route, 2)
h.match_route(verb, path) % Optimize the most common case.
else
h.match?(request)
h.match_route(request)
end
if result
h
{h, result}
else
find_route(t, verb, path, request)
end
end
def find_route([], _, _, _)
#Frankie::Routes::ErrorRoute(404)
{#Frankie::Routes::ErrorRoute(404), {}}
end
end
Expand All @@ -52,24 +58,36 @@ module Frankie::Routes
attr_reader ['verb, 'path, 'method]

def __bound__(verb, path, method)
@('verb: verb, 'path: path.to_char_list, 'method: method)
@('verb: verb, 'path: path.split(~r"/"), 'method: method)
end

def match?(verb, path)
@verb == verb andalso @path == path
def match_route(verb, path)
@verb == verb && match_route(@path, path.to_bin.split(~r"/"), {'splat: []})
end

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

def match_route([<<$', key|binary>> | t1], [value|t2], matched)
key = key.to_atom
match_route(t1, t2, matched.set(key, value))
end
def match_route(["*" | t1], [value|t2], matched)
match_route(t1, t2, matched.update 'splat, _.push(value))
end

def match_route([h|t1], [h|t2], matched)
match_route(t1, t2, matched)
end

@method.apply_to(app, args)
def match_route(_, _, _)
false
end

def call(app)
@method.apply_to(app, [])
end
end

Expand All @@ -80,12 +98,13 @@ module Frankie::Routes
@('status, status)
end

def match?(_)
true
def match_route(_)
{}
end

def call(_app, _request, response)
response.set(@status, {}, "Status: #{@status}")
end
end
end
end

29 changes: 29 additions & 0 deletions test/frankie/routes_test.exs
@@ -0,0 +1,29 @@
Code.require_file "../test_helper", __FILE__

module RouteTest
mixin ExUnit::Case

def match_route_test
vr = #Frankie::Routes::VerbRoute('GET, "/some/route", nil)
{} = vr.match_route('GET, "/some/route")
false = vr.match_route('GET, "/some/other_route")
false = vr.match_route('GET, "/")
false = vr.match_route('POST, "/some/route")

vr = #Frankie::Routes::VerbRoute('GET, "/'arg1/path/'arg2", nil)
{'arg1: "hello", 'arg2: "world"} = vr.match_route('GET, "/hello/path/world")
false = vr.match_route('POST, "/hello/path/world")
false = vr.match_route('GET, "/hello/pathh/world")
vr = #Frankie::Routes::VerbRoute('POST, "/'arg1/path/'arg2", nil)
{'arg1: "hello", 'arg2: "world"} = vr.match_route('POST, "/hello/path/world")
false = vr.match_route('GET, "/hello/path/world")
false = vr.match_route('POST, "/hello/pathh/world")
vr = #Frankie::Routes::VerbRoute('GET, "/*/*/*/'arg/*", nil)
{'arg: "and", 'splat: ["1", "2", "3", "4"]} = vr.match_route('GET, "/1/2/3/and/4")
false = vr.match_route('GET, "/1/2/3/and/4/5")
false = vr.match_route('GET, "/1/2/3/and")
end
end

0 comments on commit 24ddfbc

Please sign in to comment.