* Added class support to template engine
authorSteven Barth <steven@midlink.org>
Mon, 17 Mar 2008 18:06:41 +0000 (18:06 +0000)
committerSteven Barth <steven@midlink.org>
Mon, 17 Mar 2008 18:06:41 +0000 (18:06 +0000)
* Cleaned up dispatcher
* Added 404 error page
* Cleaned up properties

src/ffluci/dispatcher.lua
src/ffluci/template.lua
src/ffluci/view/error404.htm [new file with mode: 0644]

index f43d7f5a9d5158c27455aaf458aa099b3539d7a7..bf2ac511e4350543b4c540ace7fd73a066d1b512 100644 (file)
@@ -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()
index 3d6457169020c6aa78323ab89829967677c6cb32..00145a0a02cf99436deb8efd859278a9094feff8 100644 (file)
@@ -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 (file)
index 0000000..adc671d
--- /dev/null
@@ -0,0 +1,5 @@
+<%+header%>
+<h1>404 Not Found</h1>
+<p>Sorry, the object you requested was not found.</p>
+<tt>Unable to dispatch: <%=os.getenv("PATH_INFO")%></tt>
+<%+footer%>
\ No newline at end of file