Cosmo (000013)

Cosmo is a "safe templates" engine that is used by Sputnik but which can also be used for many other purposes. You can get the trunk copy of Cosmo from SVN.

Cosmo provides three functions that you would want to use. The first one is cosmo.fill which takes two parameters: a string that serves as a template and a table that provides the values for filling the template. The string can be in any format and Cosmo only looks for two kind of patterns in it: $var_name and $fn_name[[ a subtemplate ]]. Note that in the latter case, [=[...]=], [==[...]==], etc. can be used instead of [[...]].

If Cosmo encounters something that starts with a $ (e.g., $var_name) it will simply look up the value in the table and substitute it. E.g.:

template = [==[  $x+$y = $sum  ]==]
cosmo.fill( template,
            { x   = 1,
              y   = 2,
              sum = "?" } )

will return

1+2 = ?  

If cosmo.fill finds something like $fn_name[=[...]=], it will look up the fn_name field in the table but will assume this field to be a function. Cosmo will then call this function in a coroutine and resume it until the function stops yielding. (If you are not familiar with coroutines, think of yielding as the function throwing a response to the caller and then waiting until the caller tells it to continue where it yielded. It's like returning, except that the function can only return once, but it can yield many times.) Each time the function yields, it is expected to yield a table, and this table will be used to fill the template inside [=[...]=]. The function should yield by calling cosmo.yield. E.g.:

template = [==[ 
<h1>$list_name</h1>
<ul>
 $do_items[=[<li>$item</li>]=]
</ul>
]==]

cosmo.fill(template,
           { list_name = "My List",
             do_items  = function()
                for i=1,5 do
                   cosmo.yield { item = i }
                end
             end
           }
          )

Will return

<h1>My List</h1>
<ul>
 <li>1</li><li>2</li><li>3</li><li>4</li><li>5</li>
</ul>

Finally, the third function (i.e. after cosmo.fill and cosmo.yield) is used for the frequent case where we want to include a fill string 0 or 1 times depending on whether a condition holds. cosmo.cond takes two parameters: a boolean and a table and yields the table if a condition holds.

Thus

cosmo.fill ( "-- $if_warning[=[<b>Beware of $warning!<b>]=] --",
             { if_warning = cosmo.cond(warn_about_alligators,
                                       { warning = "ALLIGATORS" }
                                      )
             }
           )

Will return "-- <b>Beware of ALLIGATORS!<b> --" if warn_about_alligators is true and "-- --" otherwise.

Future of Cosmo

We are planning to add an additional pattern in future, which allow insertion of a Lua table between the function name and the inner table. The table would then be passed the only parameter to the function:

template = [===[
   $do_warnings{animals={"Alligators", "Hippos"}, threat_level="orange"}[=[
       <b>Beware of $threat!<b>
   ]=]
]===]

f = function(params) 
       for i, animal in ipairs(params.animals} do
          if is_dangerous(animal) and params.threat_level=="orange" then
             yield { threat = animal }
          end
       end
    end

return cosmo.fill(template, {do_warnings = f})
Powered by Sputnik | XHTML 1.1