Skip to content

Instantly share code, notes, and snippets.

@mascarenhas
Created October 30, 2009 18:47
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 2 You must be signed in to fork a gist
  • Save mascarenhas/222620 to your computer and use it in GitHub Desktop.
Save mascarenhas/222620 to your computer and use it in GitHub Desktop.
require "orbit"
require "orbit.routes"
local R = orbit.routes.R
local hello = orbit.new()
hello:dispatch_get(function (web)
return string.format('<h1>Welcome to %s!</h1>', web.real_path)
end, R'/')
hello:dispatch_get(function(web, params)
return string.format('Hello %s!', params.name)
end, R'/hello/:name')
hello:dispatch_get(function(web, params)
return string.format('Hi %s!', params.splat[1])
end, R'/hi/*')
hello:dispatch_get(function(web, params)
return string.format('Hey %s!', params.name or "stranger")
end, R'/hey/?:name?')
return hello
require "lpeg"
require "re"
require "wsapi.util"
-- monkeypatching
wsapi.util.url_decode = function (str)
if type(str) ~= "string" then return str end
str = string.gsub (str, "+", " ")
str = string.gsub (str, "%%(%x%x)", function(h)
return string.char(tonumber(h,16))
end)
str = string.gsub (str, "\r\n", "\n")
return str
end
module("orbit.routes", package.seeall)
local function foldr(t, f, acc)
for i = #t, 1, -1 do
acc = f(t[i], acc)
end
return acc
end
param = re.compile[[ [/%.] ':' {[%w_]+} &('/' / {'.'} / !.) ]] /
function (name, dot)
local extra = { inner = (lpeg.P(1) - lpeg.S("/" .. (dot or "")))^1,
close = lpeg.P"/" + lpeg.P(dot or -1) + lpeg.P(-1) }
return { cap = lpeg.Carg(1) * re.compile([[ [/%.] {%inner+} &(%close) ]], extra) /
function (params, item, delim)
params[name] = wsapi.util.url_decode(item)
end,
clean = re.compile([[ [/%.] %inner &(%close) ]], extra) }
end
opt_param = re.compile[[ [/%.] '?:' {[%w_]+} '?' &('/' / {'.'} / !.) ]] /
function (name, dot)
local extra = { inner = (lpeg.P(1) - lpeg.S("/" .. (dot or "")))^1,
close = lpeg.P"/" + lpeg.P(dot or -1) + lpeg.P(-1) }
return { cap = (lpeg.Carg(1) * re.compile([[ [/%.] {%inner+} &(%close) ]], extra) /
function (params, item, delim)
params[name] = wsapi.util.url_decode(item)
end)^-1,
clean = re.compile([[ [/%.] %inner &(%close) ]], extra)^-1 }
end
splat = re.compile[[ {[/%.]} {'*'} &('/' / '.' / !.) ]]
rest = lpeg.C((lpeg.P(1) - param - opt_param - splat)^1)
fold_caps = function (cap, acc)
if cap == "*" then
return { cap = (lpeg.Carg(1) * lpeg.C((lpeg.P(1) - acc.clean)^1) /
function (params, splat)
if not params.splat then params.splat = {} end
params.splat[#params.splat+1] = wsapi.util.url_decode(splat)
end) * acc.cap,
clean = (lpeg.P(1) - acc.clean)^1 * acc.clean }
elseif type(cap) == "string" then
return { cap = lpeg.P(cap) * acc.cap, clean = lpeg.P(cap) * acc.clean }
else
return { cap = cap.cap * acc.cap, clean = cap.clean * acc.clean }
end
end
route = lpeg.Ct((param + opt_param + splat + rest)^1 * lpeg.P(-1)) /
function (caps)
return foldr(caps, fold_caps, { cap = lpeg.P("/")^-1 * lpeg.P(-1),
clean = lpeg.P("/")^-1 * lpeg.P(-1) })
end
function R(path)
local p = route:match(path)
return setmetatable({ patt = p.cap }, { __index = { match = function (t, s)
local params = {}
if t.patt:match(s, 1, params) then
return params
else
return nil
end
end } })
end
require "orbit.routes"
local R = orbit.routes.R
do
local r = R('/foo')
local t = r:match("/foo")
assert(t)
end
do
local r = R('/foo')
local t = r:match("/bar")
assert(not t)
end
do
local r = R('/foo')
local t = r:match("/foobar")
assert(not t)
end
do
local r = R("/foo/bar/:baz")
local t = r:match("/foo/bar/boo")
assert(t.baz == "boo")
end
do
local r = R("/foo/bar/:baz")
local t = r:match("/bar/boo")
assert(not t)
end
do
local r = R("/foo/bar/:baz")
local t = r:match("/foo/bar/boo/bloo")
assert(not t)
end
do
local r = R("/say/:msg/to/:to")
local t = r:match("/say/hello/to/world")
assert(t.msg == "hello")
assert(t.to == "world")
end
do
local r = R('/say/*/to/*')
local t = r:match('/say/hello/to/world')
assert(#t.splat == 2)
assert(t.splat[1] == "hello")
assert(t.splat[2] == "world")
end
do
local r = R('/download/*.*')
local t = r:match('/download/path/to/file.xml')
assert(#t.splat == 2)
assert(t.splat[1] == "path/to/file")
assert(t.splat[2] == "xml")
end
do
local r = R('/*/foo/*/*')
local t = r:match('/bar/foo/bling/baz/boom')
assert(#t.splat == 3)
assert(t.splat[1] == "bar")
assert(t.splat[2] == "bling")
assert(t.splat[3] == "baz/boom")
end
do
local r = R('/:foo/*')
local t = r:match('/foo/bar/baz')
assert(#t.splat == 1)
assert(t.foo == "foo")
assert(t.splat[1] == "bar/baz")
end
do
local r = R('/:foo/:bar')
local t = r:match('/user@example.com/name')
assert(t.foo == "user@example.com")
assert(t.bar == "name")
end
do
local r = R('/:foo.:bar')
local t = r:match('/user@example.com')
assert(t.foo == "user@example")
assert(t.bar == "com")
end
do
local r = R('/*')
local t = r:match("/foo/bar/baz")
assert(t.splat[1] == "foo/bar/baz")
end
do
local r = R('/?:foo?/?:bar?')
local t = r:match('/hello/world')
assert(t.foo == 'hello')
assert(t.bar == 'world')
end
do
local r = R('/?:foo?/?:bar?')
local t = r:match('/hello')
assert(t.foo == 'hello')
assert(not t.bar)
end
do
local r = R('/?:foo?/?:bar?')
local t = r:match('/')
assert(not t.foo)
assert(not t.bar)
end
do
local r = R('/:foo/*')
local t = r:match('/hello%20world/how%20are%20you')
assert(t.foo == "hello world")
assert(t.splat[1] == "how are you")
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment