[Date Prev][Date Next][Thread Prev][Thread Next]
[Date Index]
[Thread Index]
- Subject: string interpolator
 
- From: "Dimiter \"malkia\" Stanev" <malkia@...>
 
- Date: Sat, 24 Dec 2011 23:34:19 -0800
 
I came up with this string interpolator.
For example if I have some environment table (naah, nothing do with lua 
environments)
local env = {
   ver1 = "-alpha",
   ver2 = "-beta",
   ver = 1,
   name = "cairo${ver${ver}}", -- cairo${ver1} -> cairo-alpha
   one = {
      two = "${ENV.HOME}" -- /Users/<user> (or /home/<user>)
   },
   depo = "${one.two}/${name}" -- /Users/<user>/cairo-alpha
}
and want to expand env.depo, it would give me
> print( interpolate( env.depo, env ) )
/Users/malkia/cairo-alpha
I haven't check what's out there yet, as it was fun to discover what I 
can do, later would recheck (and probably laugh at my lame code)
In any case, here is the code, same license as lua/luajit:
local env = {
   ver1 = "-alpha",
   ver2 = "-beta",
   ver = 1,
   name = "cairo${ver${ver}}", -- cairo${ver1} -> cairo-alpha
   one = {
      two = "${ENV.HOME}" -- /Users/<user> (or /home/<user>)
   },
   depo = "${one.two}/${name}" -- /Users/<user>/cairo-alpha
}
local function split(s, d)
   local r, b, e, d = {}, 1, 2, d or '.'
   while e ~= 0 do
      e = s:find(d, b, true) or 0
      b, r[#r+1] = e + 1, s:sub(b, e - 1)
   end
   return r
end
local function interpolate(a, env)
   local rcnt, more, env = 50, true, env or {}
   local function subst(s)
      local skey = s:sub(2, -2)
      local key = interpolate(skey, env)
      local val = env
      -- Handle one.two.three case
      for _, k in ipairs(split(key)) do
	 if val[k] == nil then
	    -- Handle array indices
	    k = tonumber(k)
	    if val[k] == nil then
	       if skey == key then
		  error( 'No value for key [' .. tostring(key) .. ']' )
	       else
		  error( 'No value for key [' .. tostring(key) .. '] <- [' .. 
tostring(skey) .. ']' )
	       end
	    end
	 end
	 val = val[k]
      end
      -- Don't expand more than 50 deep
      rcnt = rcnt - 1
      if rcnt == 0 then
	 error( 'Expansion too deep' )
      end
      more = true
      return tostring(val)
   end
   while more do
      more = false
      a = string.gsub(a, "$(%b{})", subst)
   end
   return a
end
-- The Process Environment wrapper
local procenv = setmetatable(
   {}, {
      __index = function(t, k) return os.getenv(k) end,
      __newindex = function(...) error("Can't modify process 
environment") end
   }
)
-- Attach the process environment ot our test environment
-- under the key "ENV". If the key has been re-used, then
-- it's no longer accessible.
local env = setmetatable(
   env, {
      __index = function(t, k)
		   local kenv = "ENV"
		   if k == kenv and rawget(t, kenv)==nil then
		      return procenv
		   end
		end
   }
)
print( interpolate( env.depo, env ) )