local orbit = require "orbit" local model = require "orbit.model" local cosmo = require "cosmo" local io, string = io, string local setmetatable, loadstring, setfenv = setmetatable, loadstring, setfenv local type, error, tostring = type, error, tostring local print, pcall, xpcall, traceback = print, pcall, xpcall, debug.traceback local select, unpack = select, unpack local _G = _G module("orbit.pages", orbit.new) local template_cache = {} local BOM = string.char(239) .. string.char(187) .. string.char(191) local function remove_shebang(s) return s:gsub("^#![^\n]+", "") end local function splitpath(filename) local path, file = string.match(filename, "^(.*)[/\\]([^/\\]*)$") return path, file end function load(filename, contents) filename = filename or contents local template = template_cache[filename] if not template then if not contents then local file = io.open(filename) if not file then return nil end contents = file:read("*a") file:close() if contents:sub(1,3) == BOM then contents = contens:sub(4) end end template = cosmo.compile(remove_shebang(contents)) template_cache[filename] = template end return template end local function env_index(env, key) local val = _G[key] if not val and type(key) == "string" then local template = load(env.web.real_path .. "/" .. key .. ".op") if not template then return nil end return function (arg) arg = arg or {} if arg[1] then arg.it = arg[1] end local subt_env = setmetatable(arg, { __index = env }) return template(subt_env) end end return val end local function abort(res) error{ abort, res or "abort" } end local function make_env(web, initial) local env = setmetatable(initial or {}, { __index = env_index }) env._G = env env.app = _G env.web = web env.finish = abort function env.lua(arg) local f, err = loadstring(arg[1]) if not f then error(err .. " in \n" .. arg[1]) end setfenv(f, env) local ok, res = pcall(f) if not ok and (type(res)~= "table" or res[1] ~= abort) then error(res .. " in \n" .. arg[1]) elseif ok then return res or "" else abort(res[2]) end end env["if"] = function (arg) if type(arg[1]) == "function" then arg[1] = arg[1](select(2, unpack(arg))) end if arg[1] then cosmo.yield{ it = arg[1], _template = 1 } else cosmo.yield{ _template = 2 } end end function env.redirect(target) if type(target) == "table" then target = target[1] end web:redirect(target) abort() end function env.fill(arg) cosmo.yield(arg[1]) end function env.link(arg) local url = arg[1] arg[1] = nil return web:link(url, arg) end function env.static_link(arg) return web:static_link(arg[1]) end function env.include(name, subt_env) local filename if type(name) == "table" then name = name[1] subt_env = name[2] end if name:sub(1, 1) == "/" then filename = web.doc_root .. name else filename = web.real_path .. "/" .. name end local template = load(filename) if not template then return "" end if subt_env then if type(subt_env) ~= "table" then subt_env = { it = subt_env } end subt_env = setmetatable(subt_env, { __index = env }) else subt_env = env end return template(subt_env) end function env.forward(...) abort(env.include(...)) end env.mapper = model.new() function env.model(name, dao) if type(name) == "table" then name, dao = name[1], name[2] end return env.mapper:new(name, dao) end env.recycle = model.recycle return env end function fill(web, template, env) if template then local ok, res = xpcall(function () return template(make_env(web, env)) end, function (msg) if type(msg) == "table" and msg[1] == abort then return msg else return traceback(msg) end end) if not ok and (type(res) ~= "table" or res[1] ~= abort) then error(res) elseif ok then return res else return res[2] end end end function handle_get(web) local filename = web.path_translated web.real_path = splitpath(filename) local res = fill(web, load(filename)) if res then return res else web.status = 404 return [[ Not Found

Not found!

]] end end handle_post = handle_get return _M