mint

function mint( template [, ename] ) --> ( sandbox ) --> expstr, err

Description

Expand the Lua code contained in the template. The following pattern in the template will be expanded:

@{luaexp}

Will be substituted with the result of the Lua expression.

@{{luastm}}

Embeds the Lua statement. This allow to mix Lua code and verbatim text.

The function works in two steps:

  1. returns a generator function that takes a table(sandbox)

  2. returns the generator function the expanded string(expstr)

Parameters

template

The string that should be expanded.

ename

The Lua code will have access to a global with this name. It will be a function that will append its first argument to the template output string. This parameter is optional, the default value is _o.

sandbox

The contents of this table will be injected into the environment of the Lua code (both expressions and statements). This allows you to pass parameters to the template.

Return Values

expstr

The resulting expanded text or nil if an error occurse.

err

A message if an error occurse, otherwise nil.

Code

--ZFUNC-mint-v1
local function mint( template, ename ) --> ( sandbox ) --> expstr, err
   if not ename then ename = '_o' end
   local function expr(e) return ' '..ename..'('..e..')' end

   local function compat_load( str, env )
      local chunkname = 'mint_script'
      local func, err
      if _VERSION ~= 'Lua 5.1' then
         func, err = load( str, chunkname, 't', env )
      else
         func, err = loadstring( str, chunkname)
         if func then setfenv( func, env ) end
      end
      return func, err
   end

   -- Generate a script that expands the template
   local script = ''
   template:gsub( '(.-)@(%b{})', function( text, code )
      script = script..expr( string.format( '%q', text ) )
      code = code:sub( 2, #code-1 )
      if code:match( '^{.*}$' ) then
         script = script..code:sub( 2, #code-1 )
      else
         script = script..expr( code )
      end
   end )
   local text = template:match( '^.*@%b{}(.-)$' )
   if text then
      script = script..expr( string.format( '%q', text ) )
   end

   -- Return a function that executes the script with a custom environment
   return function( sandbox )
    local expstr = ''
    if 'table' ~= type( sandbox ) then
      return nil, "mint generator requires a sandbox"
    end
    sandbox[ ename ] = function( out ) expstr = expstr..out end
    local generate, err = compat_load( script, sandbox )
    if not generate or err then
       return nil, err..'\nTemplate script: [[\n'..script..'\n]]'
    end
    generate()
    return expstr
  end
end

return mint

Examples

local t = require( "tapered" )
local mint = require( "mint" )

-- Lua expression expansion with @{}
local m = mint( "@{item.a} @{item.b:upper()}" )
t.same( 'a B', m{ item = { a = 'a', b = 'b' } } )
t.same( 'B A', m{ item = { a = 'B', b = 'a' } } )

-- Mix lua statements and text with @{{}}
m = mint( "@{{for i=1,3 do}} hello @{item}!@{{end}}" )
t.same( ' hello world! hello world! hello world!', m{ item = 'world' } )

-- Use the output function to expand text from complex lua code
m = mint( "@{{for i=1,3 do o(' hello '..item..'!') end}}", 'o' )
t.same( ' hello dude! hello dude! hello dude!', m{ item = 'dude' } )

t.done()