librelist archives

« back to archive

Inherit function for TIr's template rendering

Inherit function for TIr's template rendering

From:
Tang Daogang
Date:
2011-02-17 @ 08:11
hi, guys,

I have implemented inheriting function for TIr's template rendering, which
is borrowed from Django.

My design is:

add two tag {: :}, and {[]}, their functions are:

   1. put the {: "xxxx" :} to the front of the html file to render. e.g. {:
   "base.html" :}. It means when meet this tag, load the base.html on fly;
   2. in the base.html file, there are somewhere {[ 'xxxzzz' ]};
   3. in the child fragment file, there are somewhere {[ ===== 'xxxzzz'
   =====    content    ]};
   4. when render, it will use child fragment file's block xxxzzz's content
   to replace base.html's {[ 'xxxzzz' ]}.

My English is not good, so I don't know where describe it clearly.

Wish some help to Tir.

module(..., package.seeall)

local TEMPLATES = APP_DIR + "views/"


local VIEW_ACTIONS = {

    ['{%'] = function(code)
        return code
    end,

    ['{{'] = function(code)

        if not code then code = "" end
        return ('_result[#_result+1] = %s'):format(code)
    end,

    ['{('] = function(code)
        return ([[
            if not _children[%s] then
                local View = require 'bamboo.view'
                _children[%s] = View(%s)
            end

            _result[#_result+1] = _children[%s](getfenv())
        ]]):format(code, code, code, code)
    end,

    ['{<'] = function(code)
        return ('_result[#_result+1] = http.escapeHTML(%s)'):format(code)
    end,

    ['{['] = function(code)
        -- nothing now
        return true
    end,

    ['{:'] = function(code, this_page)
        local base_page = io.loadFile(TEMPLATES, unseri(code))
        local new_page = base_page
        for block in new_page:gmatch("({%[[%s_%w%.%-\'\"]+%]})") do

            local block_content = block:sub(3, -3):trim()

            local this_part = this_page:match('{%[%s*======*%s*' +
block_content + '%s*======*%s+(.+)%s*%]}')

            if this_part then
                new_page = new_page:gsub('{%[ *' + block_content + ' *%]}',
this_part)
            else
                new_page = new_page:gsub('{%[ *' + block_content + ' *%]}',
"")
            end

        end
        return new_page
    end,

}


local View = Object:extend {
    __tag = "Bamboo.View";
    __name = 'View';

    init = function (self, name)
        assert(posix.access(TEMPLATES + name), "Template " + TEMPLATES +
name + " does not exist or wrong permissions.")

        if os.getenv('PROD') then
            local tmpf = io.loadFile(TEMPLATES, name)
            tmpf = self.preprocess(tmpf)
            return self.compileView(tmpf, name)
        else
            return function (params)
                local tmpf = io.loadFile(TEMPLATES, name)
                assert(tmpf, "Template " + TEMPLATES + name + " does not
exist.")
                tmpf = self.preprocess(tmpf)
                return self.compileView(tmpf, name)(params)
            end
        end

    end;

    preprocess = function(tmpl)

        if tmpl:match('{:') then
            local block = tmpl:match("(%b{})")
            local headtwo = block:sub(1,2)
            local block_content = block:sub(3, -3)
            assert(headtwo == '{:', 'The inheriate tag must be put in front
of the page.')

            local act = VIEW_ACTIONS[headtwo]
            return act(block_content, tmpl)

        else
            return tmpl
        end
    end;

    compileView = function (tmpl, name)
        local tmpl = ('%s{}'):format(tmpl)
        local code = {'local _result, _children = {}, {}\n'}

        for text, block in tmpl:gmatch("([^{]-)(%b{})") do
            local act = VIEW_ACTIONS[block:sub(1,2)]
            local output = text

            if act then
                code[#code+1] =  '_result[#_result+1] = [[' + text + ']]'
                code[#code+1] = act(block:sub(3,-3))
            elseif #block > 2 then
                code[#code+1] = '_result[#_result+1] = [[' + text + block +
']]'
            else
                code[#code+1] =  '_result[#_result+1] = [[' + text + ']]'
            end
        end

        code[#code+1] = 'return table.concat(_result)'

        code = table.concat(code, '\n')
        local func, err = loadstring(code, name)

        if err then
            assert(func, err)
        end

        return function(context)
            assert(context, "You must always pass in a table for context.")
            setmetatable(context, {__index=_G})
            setfenv(func, context)
            return func()
        end
    end;
}

return View

And one example:
*minindex.html*
{( "header.html" )}

<div class="container">
    <!--    Header Part    -->
    <div id="front">
        {( "front.html" )}
    </div>
    <hr />
    <!--    Menu Part    -->
    <div id="menu" class="column span-24 last">
        <!--   先考虑静态页面    -->
        {( "menu.html" )}
    </div>

    <!--    Content Part    -->
    <div id="page" class="column span-24 last">
        {[ "page" ]}
    </div>

    <!--    Footer Part    -->
    <hr />
    <div id="footer">
        {( "footer.html" )}
    </div>

</div>

{( "tail.html" )}

*minipage.html*
{: 'minindex.html' :}

{[ ======== "page" ========

<div id="page_head">
    <div id="page_breadcrums">
        当面页面:{{page.breadcrums}}
    </div>
    <div id="page_toolbar">
        {( "toolbar.html" )}
    </div>
    <div style="clear: both;"> </div>
</div>

<div id="page_content">

    <div id="page_content_title"> {{page.title}} </div>
    <div id="page_content_body">
        {{page.content}}
    </div>
</div>

<hr/>
<div id="page_children">
    {( "children.html" )}
</div>

{( "comment/comment.html" )}
{( "upload/upload.html" )}

]}

this code is very alpha yet, so any suggestions are welcomed.

BR.

-- 
Nothing is impossible.

Re: [mongrel2] Inherit function for TIr's template rendering

From:
Zed A. Shaw
Date:
2011-02-17 @ 16:59
On Thu, Feb 17, 2011 at 04:11:05PM +0800, Tang Daogang wrote:
> hi, guys,
> 
> I have implemented inheriting function for TIr's template rendering, which
> is borrowed from Django.

Ah, that's cool.

> My English is not good, so I don't know where describe it clearly.

No problem, I'm very good at English so it's easy to understand you. :-)

I'll take the code you have here and bring it in.

-- 
Zed A. Shaw
http://zedshaw.com/