From cfe8fc894fb2e51885b7a992ea685c71baf6b769 Mon Sep 17 00:00:00 2001 From: Steven Barth Date: Mon, 17 Mar 2008 18:06:41 +0000 Subject: * Added class support to template engine * Cleaned up dispatcher * Added 404 error page * Cleaned up properties --- src/ffluci/dispatcher.lua | 27 ++++++----- src/ffluci/template.lua | 112 +++++++++++++++++++++++++++---------------- src/ffluci/view/error404.htm | 5 ++ 3 files changed, 92 insertions(+), 52 deletions(-) create mode 100644 src/ffluci/view/error404.htm (limited to 'src') diff --git a/src/ffluci/dispatcher.lua b/src/ffluci/dispatcher.lua index f43d7f5a9d..bf2ac511e4 100644 --- a/src/ffluci/dispatcher.lua +++ b/src/ffluci/dispatcher.lua @@ -100,16 +100,17 @@ function dispatch(req) end end - -- Sends a 404 error code and renders the "error404" template if available function error404(message) message = message or "Not Found" - ffluci.http.status(404, "Not Found") + local s, t = pcall(ffluci.template.Template, "error404") - if not pcall(ffluci.template.render, "error404") then + if not s then ffluci.http.textheader() - print(message) + print(message) + else + t:render() end return false end @@ -118,9 +119,13 @@ end function error500(message) ffluci.http.status(500, "Internal Server Error") - if not pcall(ffluci.template.render, "error500") then + local s, t = pcall(ffluci.template.Template, "error500") + + if not s then ffluci.http.textheader() print(message) + else + t:render() end return false end @@ -147,14 +152,15 @@ end function simpleview(request) local i18n = require("ffluci.i18n") local tmpl = require("ffluci.template") - local conf = require("ffluci.config") local disp = require("ffluci.dispatcher") - pcall(i18n.load, request.module .. "." .. conf.lang) - if not pcall(tmpl.get, request.module .. "/" .. request.action) then + i18n.loadc(request.module) + local s, t = pcall(tmpl.Template, request.module .. "/" .. request.action) + + if not s then disp.error404() else - tmpl.render(request.module .. "/" .. request.action) + t:render() end end @@ -162,10 +168,9 @@ end -- action_"request.action" and calls it function action(request) local i18n = require("ffluci.i18n") - local conf = require("ffluci.config") local disp = require("ffluci.dispatcher") - pcall(i18n.load, request.module .. "." .. conf.lang) + i18n.loadc(request.module) local action = getfenv()["action_" .. request.action:gsub("-", "_")] if action then action() diff --git a/src/ffluci/template.lua b/src/ffluci/template.lua index 3d64571690..00145a0a02 100644 --- a/src/ffluci/template.lua +++ b/src/ffluci/template.lua @@ -35,10 +35,9 @@ viewdir = ffluci.fs.dirname(ffluci.util.__file__()) .. "view/" -- Compile modes: --- none: Never compile, only render precompiled +-- none: Never compile, only use precompiled data from files -- memory: Always compile, do not save compiled files, ignore precompiled --- always: Same as "memory" but also saves compiled files --- smart: Compile on demand, save compiled files, update precompiled +-- file: Compile on demand, save compiled files, update precompiled compiler_mode = "memory" @@ -56,25 +55,12 @@ viewns = { config = ffluci.model.uci.get, controller = os.getenv("SCRIPT_NAME"), media = ffluci.config.mediaurlbase, - include = function(name) return render(name, getfenv(2)) end, - write = io.write + write = io.write, + include = function(name) Template(name):render(getfenv(2)) end, } - --- Compiles and builds a given template -function build(template, compiled) - local template = compile(ffluci.fs.readfile(template)) - - if compiled then - ffluci.fs.writefile(compiled, template) - end - - return template -end - - -- Compiles a given template into an executable Lua module -function compile(template) +function compile(template) -- Search all <% %> expressions (remember: Lua table indexes begin with #1) local function expr_add(command) table.insert(expr, command) @@ -137,53 +123,97 @@ function compile(template) return template end +-- Oldstyle render shortcut +function render(name, ...) + local s, t = pcall(Template, name) + if not s then + error("Unable to load template: " .. name) + else + t:render(...) + end +end + + +-- Template class +Template = ffluci.util.class() + +-- Shared template cache to store templates in to avoid unnecessary reloading +Template.cache = {} --- Returns and builds the template for "name" depending on the compiler mode -function get(name) - local templatefile = viewdir .. name .. ".htm" - local compiledfile = viewdir .. name .. ".lua" - local template = nil + +-- Constructor - Reads and compiles the template on-demand +function Template.__init__(self, name) + if self.cache[name] then + self.template = self.cache[name] + else + self.template = nil + end + + -- Create a new namespace for this template + self.viewns = {} + + -- Copy over from general namespace + for k, v in pairs(viewns) do + self.viewns[k] = v + end + + -- If we have a cached template, skip compiling and loading + if self.template then + return + end - if compiler_mode == "smart" then - local tplmt = ffluci.fs.mtime(templatefile) + -- Compile and build + local sourcefile = viewdir .. name .. ".htm" + local compiledfile = viewdir .. name .. ".lua" + + if compiler_mode == "file" then + local tplmt = ffluci.fs.mtime(sourcefile) local commt = ffluci.fs.mtime(compiledfile) -- Build if there is no compiled file or if compiled file is outdated if ((commt == nil) and not (tplmt == nil)) or (not (commt == nil) and not (tplmt == nil) and commt < tplmt) then - template = loadstring(build(templatefile, compiledfile)) + local compiled = compile(ffluci.fs.readfile(sourcefile)) + ffluci.fs.writefile(compiledfile, compiled) + self.template = loadstring(compiled) else - template = loadfile(compiledfile) + self.template = loadfile(compiledfile) end elseif compiler_mode == "none" then - template = loadfile(compiledfile) + self.template = loadfile(self.compiledfile) elseif compiler_mode == "memory" then - template = loadstring(build(templatefile)) - - elseif compiler_mode == "always" then - template = loadstring(build(templatefile, compiledfile)) - + self.template = loadstring(compile(ffluci.fs.readfile(sourcefile))) + else error("Invalid compiler mode: " .. compiler_mode) end - return template or error("Unable to load template: " .. name) + -- If we have no valid template throw error, otherwise cache the template + if not self.template then + error("Unable to load template: " .. name) + else + self.cache[name] = self.template + end end + -- Renders a template -function render(name, scope) +function Template.render(self, scope) scope = scope or getfenv(2) - -- Our template module - local view = get(name) + -- Save old environment + local oldfenv = getfenv(self.template) -- Put our predefined objects in the scope of the template - ffluci.util.updfenv(view, scope) - ffluci.util.updfenv(view, viewns) + ffluci.util.updfenv(self.template, scope) + ffluci.util.updfenv(self.template, self.viewns) -- Now finally render the thing - return view() + self.template() + + -- Reset environment + setfenv(self.template, oldfenv) end diff --git a/src/ffluci/view/error404.htm b/src/ffluci/view/error404.htm new file mode 100644 index 0000000000..adc671de00 --- /dev/null +++ b/src/ffluci/view/error404.htm @@ -0,0 +1,5 @@ +<%+header%> +

404 Not Found

+

Sorry, the object you requested was not found.

+Unable to dispatch: <%=os.getenv("PATH_INFO")%> +<%+footer%> \ No newline at end of file -- cgit v1.2.3