[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 ) )