libutil.lua

-- Random useful Lua things

-- Written by Rici Lake, released into the public domain

local string = import "string"
local strfind = string.find

return function(util)

  local function gsegs(stuff)
    return string.gfind(stuff, "([%S]+)%s*=>%s*([%S]+)")
  end
  local function gwords(stuff) return string.gfind(stuff, "%S+") end
  local function setMulti(t, val, gen, st, obj)
    for k, v in gen, st, obj do t[k] = v or val end
    return t
  end

  util.words = gwords

  util.pairs = gsegs

  util.setMulti = setMulti

  function util.setFrom(stuff) return setMulti({}, true, gwords(stuff)) end

  function util.tableFrom(stuff) return setMulti({}, "", gsegs(stuff)) end

  -- Mappers
  
  -- This mapper takes a handler table, an opaque argument, and a key/value
  -- iterator, and uses the key to lookup up a handler in the handler table.
  -- (The iterator has to come last because it has multiple returns.)
  -- The handler is called with three arguments: opaque, key, value.
  -- Normally, handler tables will be Default tables, see functables;
  -- if a handler doesn't exist, you'll get an execution time error.
  
  function util.cases(funcs, opaque, gen, st, obj)
    for k, v in gen, st, obj do funcs[k](opaque, k, v) end
    return opaque
  end

  -- Generalised foreach mapper, using a key/value iterator. The argument
  -- order is inverse to table.foreach, so watch out (again, because
  -- iterators are multiple returns)
  
  function util.foreach(func, gen, st, obj)
    for k, v in gen, st, obj do
      local rv = func(k, v)
      if rv then return rv end
    end
  end
  
  -- Iterators
  
  -- This one is just here because someone wanted to match Ruby :)
  -- An error will be thrown if it encounters a non-string key, so
  -- watch out.
  
  -- The use of pat as the state here is entirely arbitrary; one
  -- of pat, gen, st could avoid being an upvalue.
  function util.grep(pat, gen, st, obj)
    local function filter(pat, obj)
      for k, v in gen, st, obj do
        if strfind(k, pat) then return k, v end
      end
    end
    return filter, pat, obj
  end
  
  -- A more general one which uses a function instead of a string pattern
  -- Nothing except good taste and an adversion to parentheses stops you
  -- from stacking these things:
  --    local function isstring(k) return type(k) == "string" end
  --    for k, v in util.grep("^%w+$", util.filter(isstring, pairs(t))) do
  -- 
  function util.filter(fn, gen, st, obj)
    local function filter(fn, obj)
      for k, v in gen, st, obj do
        if fn(k, v) then return k, v end
      end
    end
    return filter, fn, obj
  end
  
  return util
end

Produced by TNT, the Lua-linter. TNT/0.5 Copyright (C) 2004 Rici Lake