lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


On Thu, Jun 11, 2009 at 7:39 AM, steve donovan <steve.j.donovan@gmail.com> wrote:
Here's another little example of how metamethods can do interesting
things, so that what appears to be a function actually translates into
a shell command.

The idea is to write the shell commands in a natural Lua way:

print(shell.which 'lua')
print(shell.chmod('+x','test3.lua'))
print(shell.gcc ({'-shared','-fpic'},'test 3.lua'))

and then use __index on the shell table to do the translation. This
could be called the 'shell pattern' for lack of a better term.

-- shell.lua
shell = {}
local mt = {}
setmetatable(shell,mt)

function shell.command(cmd,no_lf)
   print(cmd)
  local f = io.popen(cmd..' 2>&1; echo "-retcode:$?"' ,'r')
  local l = f:read '*a'
  f:close()
  local i1,i2,ret = l:find('%-retcode:(%d+)\n$')
  if no_lf and i1 > 1 then i1 = i1 - 1 end
  l = l:sub(1,i1-1)
  return tonumber(ret),l
end

local concat

concat = function (args)
   for i,s in ipairs(args) do
       if type(s) == 'table' then
           args[i] = concat(s)
       else
           args[i] = s:find '%s' and '"'..s..'"' or s
       end
   end
   return table.concat(args,' ')
end

function mt.__index(t,k)
   return function(...)
       return shell.command(k..' '..concat{...},true)
   end
end

print(shell.which 'lua')
print(shell.chmod('+x','test3.lua'))
print(shell.gcc ({'-shared','-fpic'},'test 3.lua'))
------

And the output is:

which lua
0       /usr/local/bin/lua
chmod +x test3.lua
0
gcc -shared -fpic "test 3.lua"
1       gcc: test 3.lua: No such file or directory
gcc: no input files

Ignore the particular implementation of shell.command, which can be
more elegantly done with luaex.

A subpattern here is a generalization of concat to handle nested
tables, which makes it easy to compose command lines.

For example, to compile simple Lua extensions:

local liboptions = {'-shared','-fpic'}
local includes = {'-I','/home/sdonovan/lua/include'}

function lcompile(name)
  local status = shell.gcc(liboptions,includes,name..'.c','-o',name..'.so')
  return status == 0
end

steve d.

That is very cool! Thanks for sharing.
--
Regards,
Ryan