diff options
author | Natanael Copa <ncopa@alpinelinux.org> | 2012-02-17 08:15:59 +0000 |
---|---|---|
committer | Natanael Copa <ncopa@alpinelinux.org> | 2012-02-17 08:15:59 +0000 |
commit | 50f896f59089364269b694a0210fb7e045dbc9e2 (patch) | |
tree | df46393e2fb7b5df01fecc1d9e694301fe6d3f77 | |
parent | a50741c2139274ec94034a18da6d4d0b051c6ff8 (diff) | |
download | aports-50f896f59089364269b694a0210fb7e045dbc9e2.tar.bz2 aports-50f896f59089364269b694a0210fb7e045dbc9e2.tar.xz |
testing/lua-microlight: new aport
a really compact set of general Lua functions
http://stevedonovan.github.com/microlight/
-rw-r--r-- | testing/lua-microlight/APKBUILD | 36 | ||||
-rw-r--r-- | testing/lua-microlight/ml.lua | 543 |
2 files changed, 579 insertions, 0 deletions
diff --git a/testing/lua-microlight/APKBUILD b/testing/lua-microlight/APKBUILD new file mode 100644 index 000000000..632a65333 --- /dev/null +++ b/testing/lua-microlight/APKBUILD @@ -0,0 +1,36 @@ +# Contributor: Natanael Copa <ncopa@alpinelinux.org> +# Maintainer: Natanael Copa <ncopa@alpinelinux.org> +pkgname=lua-microlight +pkgver=0_git20120215 +pkgrel=0 +pkgdesc="a really compact set of general Lua functions" +url="http://stevedonovan.github.com/microlight/" +arch="noarch" +license="MIT" +depends="lua" +makedepends="wget" +install="" +subpackages="" +source="https://raw.github.com/gist/1834789/2bbb01662de1d83af93d2bd2990fee229b473d54/ml.lua" + +_builddir= +prepare() { + local i + cd "$_builddir" + for i in $source; do + case $i in + *.patch) msg $i; patch -p1 -i "$srcdir"/$i || return 1;; + esac + done +} + +build() { + cd "$_builddir" +} + +package() { + cd "$_builddir" + install -Dm644 "$srcdir"/ml.lua "$pkgdir"/usr/share/lua/5.1/ml.lua +} + +md5sums="0a1e55c9babf6c093aa24f391c07cfd7 ml.lua" diff --git a/testing/lua-microlight/ml.lua b/testing/lua-microlight/ml.lua new file mode 100644 index 000000000..2bbb01662 --- /dev/null +++ b/testing/lua-microlight/ml.lua @@ -0,0 +1,543 @@ +----------------- +-- Microlight - a very compact Lua utilities module +-- +-- Steve Donovan, 2012; License MIT +-- @module ml + +local ml = {} + +--- String utilties. +-- @section string + +--- split a string into a list of strings separated by a delimiter. +-- @param s The input string +-- @param re A Lua string pattern; defaults to '%s+' +-- @param n optional maximum number of splits +-- @return a list +function ml.split(s,re,n) + local find,sub,append = string.find, string.sub, table.insert + local i1,ls = 1,{} + if not re then re = '%s+' end + if re == '' then return {s} end + while true do + local i2,i3 = find(s,re,i1) + if not i2 then + local last = sub(s,i1) + if last ~= '' then append(ls,last) end + if #ls == 1 and ls[1] == '' then + return {} + else + return ls + end + end + append(ls,sub(s,i1,i2-1)) + if n and #ls == n then + ls[#ls] = sub(s,i1) + return ls + end + i1 = i3+1 + end +end + +--- escape any 'magic' characters in a string +-- @param s The input string +-- @return an escaped string +function ml.escape(s) + return (s:gsub('[%-%.%+%[%]%(%)%$%^%%%?%*]','%%%1')) +end + +--- expand a string containing any ${var} or $var. +-- @param s the string +-- @param subst either a table or a function (as in `string.gsub`) +-- @return expanded string +function ml.expand (s,subst) + local res = s:gsub('%${([%w_]+)}',subst) + return (res:gsub('%$([%w_]+)',subst)) +end + +--- return the contents of a file as a string +-- @param filename The file path +-- @param is_bin open in binary mode, default false +-- @return file contents +function ml.readfile(filename,is_bin) + local mode = is_bin and 'b' or '' + local f,err = io.open(filename,'r'..mode) + if not f then return nil,err end + local res,err = f:read('*a') + f:close() + if not res then return nil,err end + return res +end + +--- File and Path functions +-- @section file + +--~ exists(filename) +--- Does a file exist? +-- @param filename a file path +-- @return the file path, otherwise nil +-- @usage exists 'readme' or exists 'readme.txt' or exists 'readme.md' +function ml.exists (filename) + local f = io.open(filename) + if not f then + return nil + else + f:close() + return filename + end +end + +local sep, other_sep = package.config:sub(1,1),'/' + + +--- split a file path. +-- if there's no directory part, the first value will be the empty string +-- @param P A file path +-- @return the directory part +-- @return the file part +function ml.splitpath(P) + local i = #P + local ch = P:sub(i,i) + while i > 0 and ch ~= sep and ch ~= other_sep do + i = i - 1 + ch = P:sub(i,i) + end + if i == 0 then + return '',P + else + return P:sub(1,i-1), P:sub(i+1) + end +end + +--- given a path, return the root part and the extension part. +-- if there's no extension part, the second value will be empty +-- @param P A file path +-- @return the name part +-- @return the extension +function ml.splitext(P) + local i = #P + local ch = P:sub(i,i) + while i > 0 and ch ~= '.' do + if ch == sep or ch == other_sep then + return P,'' + end + i = i - 1 + ch = P:sub(i,i) + end + if i == 0 then + return P,'' + else + return P:sub(1,i-1),P:sub(i) + end +end + +--- Extended table functions. +-- 'list' here is shorthand for 'list-like table'; these functions +-- only operate over the numeric `1..#t` range of a table and are +-- particularly efficient for this purpose. +-- @section table + +local function quote (v) + if type(v) == 'string' then + return ('%q'):format(v) + else + return tostring(v) + end +end + +local tbuff +function tbuff (t,buff,k) + buff[k] = "{" + k = k + 1 + for key,value in pairs(t) do + key = quote(key) + if type(value) ~= 'table' then + value = quote(value) + buff[k] = ('[%s]=%s'):format(key,value) + k = k + 1 + if buff.limit and k > buff.limit then + buff[k] = "..." + error("buffer overrun") + end + else + if not buff.tables then buff.tables = {} end + if not buff.tables[value] then + k = tbuff(value,buff,k) + buff.tables[value] = true + else + buff[k] = "<cycle>" + k = k + 1 + end + end + buff[k] = "," + k = k + 1 + end + if buff[k-1] == "," then k = k - 1 end + buff[k] = "}" + k = k + 1 + return k +end + +--- return a string representation of a Lua table. +-- Cycles are detected, and a limit on number of items can be imposed. +-- @param t the table +-- @param limit the limit on items, default 1000 +-- @return a string +function ml.tstring (t,limit) + local buff = {limit = limit or 1000} + pcall(tbuff,t,buff,1) + return table.concat(buff) +end + +--- dump a Lua table to a file object. +-- @param t the table +-- @param f the file object (anything supporting f.write) +function ml.tdump(t,...) + local f = select('#',...) > 0 and select(1,...) or io.stdout + f:write(ml.tstring(t),'\n') +end + +--- map a function over a list. +-- The output must always be the same length as the input, so +-- any `nil` values are mapped to `false`. +-- @param f a function of one or more arguments +-- @param t the table +-- @param ... any extra arguments to the function +-- @return a list with elements `f(t[i])` +function ml.imap(f,t,...) + f = ml.function_arg(f) + local res = {} + for i = 1,#t do + local val = f(t[i],...) + if val == nil then val = false end + res[i] = val + end + return res +end + +--- filter a list using a predicate. +-- @param t a table +-- @param pred the predicate function +-- @param ... any extra arguments to the predicate +-- @return a list such that `pred(t[i])` is true +function ml.ifilter(t,pred,...) + local res,k = {},1 + pred = ml.function_arg(pred) + for i = 1,#t do + if pred(t[i],...) then + res[k] = t[i] + k = k + 1 + end + end + return res +end + +--- find an item in a list using a predicate. +-- @param t the list +-- @param pred a function of at least one argument +-- @param ... any extra arguments +-- @return the item value +function ml.ifind(t,pred,...) + pred = ml.function_arg(pred) + for i = 1,#t do + if pred(t[i],...) then + return t[i] + end + end +end + +--- return the index of an item in a list. +-- @param t the list +-- @param value item value +-- @return index, otherwise `nil` +function ml.index (t,value) + for i = 1,#t do + if t[i] == value then return i end + end +end + +--- return a slice of a list. +-- Like string.sub, the end index may be negative. +-- @param t the list +-- @param i1 the start index +-- @param i2 the end index, default #t +function ml.sub(t,i1,i2) + if not i2 or i2 > #t then + i2 = #t + elseif i2 < 0 then + i2 = #t + i2 + 1 + end + local res,k = {},1 + for i = i1,i2 do + res[k] = t[i] + k = k + 1 + end + return res +end + +--- map a function over a Lua table. +-- @param f a function of one or more arguments +-- @param t the table +-- @param ... any optional arguments to the function +function ml.tmap(f,t,...) + f = ml.function_arg(f) + local res = {} + for k,v in pairs(t) do + res[k] = f(v,...) + end + return res +end + +--- filter a table using a predicate. +-- @param t a table +-- @param pred the predicate function +-- @param ... any extra arguments to the predicate +-- @usage tfilter({a=1,b='boo'},tonumber) == {a=1} +function ml.tfilter (t,pred,...) + local res = {} + pred = ml.function_arg(pred) + for k,v in pairs(t) do + if pred(v,...) then + res[k] = v + end + end + return res +end + +--- add the key/value pairs of `other` to `t`. +-- For sets, this is their union. For the same keys, +-- the values from the first table will be overwritten +-- @param t table to be updated +-- @param other table +-- @return the updated table +function ml.update(t,other) + for k,v in pairs(other) do + t[k] = v + end + return t +end + +--- extend a list using values from another. +-- @param t the list to be extended +-- @param other a list +-- @return the extended list +function ml.extend(t,other) + local n = #t + for i = 1,#other do + t[n+i] = other[i] + end + return t +end + +--- make a set from a list. +-- @param t a list of values +-- @return a table where the keys are the values +-- @usage set{'one','two'} == {one=true,two=true} +function ml.set(t) + local res = {} + for i = 1,#t do + res[t[i]] = true + end + return res +end + +--- extract the keys of a table as a list. +-- This is the opposite operation to tset +-- @param t a table +-- @param a list of keys +function ml.keys(t) + local res,k = {},1 + for key in pairs(t) do + res[k] = key + k = k + 1 + end + return res +end + +--- is `other` a subset of `t`? +-- @param t a set +-- @param other a possible subset +-- @return true or false +function ml.subset(t,other) + for k,v in pairs(other) do + if t[k] ~= v then return false end + end + return true +end + +--- are these two tables equal? +-- This is shallow equality. +-- @param t a table +-- @param other a table +-- @return true or false +function ml.tequal(t,other) + return ml.subset(t,other) and ml.subset(other,t) +end + +--- the intersection of two tables. +-- Works as expected for sets, otherwise note that the first +-- table's values are preseved +-- @param t a table +-- @param other a table +-- @return the intersection of the tables +function ml.intersect(t,other) + local res = {} + for k,v in pairs(t) do + if other[k] then + res[k] = v + end + end + return res +end + +--- collect the values of an iterator into a list. +-- @param iter a single or double-valued iterator +-- @param count an optional number of values to collect +-- @return a list of values. +-- @usage collect(ipairs{10,20}) == {{1,10},{2,20}} +function ml.collect (iter, count) + local res,k = {},1 + local v1,v2 = iter() + local dbl = v2 ~= nil + while v1 do + if dbl then v1 = {v1,v2} end + res[k] = v1 + k = k + 1 + if count and k > count then break end + v1,v2 = iter() + end + return res +end + +--- Functional helpers. +-- @section function + +--- create a function which will throw an error on failure. +-- @param f a function that returns nil,err if it fails +-- @return an equivalent function that raises an error +function ml.throw(f) + f = ml.function_arg(f) + return function(...) + local res,err = f(...) + if err then error(err) end + return res + end +end + +--- create a function which will never throw an error. +-- This is the opposite situation to throw; if the +-- original function throws an error e, then this +-- function will return nil,e. +-- @param f a function which can throw an error +-- @return a function which returns nil,error when it fails +function ml.safe(f) + f = ml.function_arg(f) + return function(...) + local ok,r1,r2,r3 = pcall(f,...) + if ok then return r1,r2,r3 + else + return nil,r1 + end + end +end +--memoize(f) + +--- bind the value `v` to the first argument of function `f`. +-- @param f a function of at least one argument +-- @param v a value +-- @return a function of one less argument +-- @usage (bind1(string.match,'hello')('^hell') == 'hell' +function ml.bind1(f,v) + f = ml.function_arg(f) + return function(...) + return f(v,...) + end +end + +--- compose two functions. +-- For instance, `printf` can be defined as `compose(io.write,string.format)` +-- @param f1 a function +-- @param f2 a function +-- @return f1(f2(...)) +function ml.compose(f1,f2) + f1 = ml.function_arg(f1) + f2 = ml.function_arg(f2) + return function(...) + return f1(f2(...)) + end +end + +--- is the object either a function or a callable object?. +-- @param obj Object to check. +-- @return true if callable +function ml.callable (obj) + return type(obj) == 'function' or getmetatable(obj) and getmetatable(obj).__call +end + +function ml.function_arg(f) + assert(ml.callable(f),"expecting a function or callable object") + return f +end + +--- Classes. +-- @section class + +--- create a class with an optional base class. +-- The resulting table has a new() function for invoking +-- the constructor, which must be named `_init`. If the base +-- class has a constructor, you can call it as the `super()` method. +-- The `__tostring` metamethod is also inherited, but others need +-- to be brought in explicitly. +-- @param base optional base class +-- @return the metatable representing the class +function ml.class(base) + local klass, base_ctor = {} + klass.__index = klass + if base then + setmetatable(klass,base) + klass._base = base + base_ctor = rawget(base,'_init') + klass.__tostring = base.__tostring + end + function klass.new(...) + local self = setmetatable({},klass) + if rawget(klass,'_init') then + klass.super = base_ctor -- make super available for ctor + klass._init(self,...) + elseif base_ctor then -- call base ctor automatically + base_ctor(self,...) + end + return self + end + return klass +end + +--- is an object derived from a class? +-- @param self the object +-- @param klass a class created with `class` +-- @return true or false +function ml.is_a(self,klass) + local m = getmetatable(self) + if not m then return false end --*can't be an object! + while m do + if m == klass then return true end + m = rawget(m,'_base') + end + return false +end + +local _type = type + +--- extended type of an object. +-- The type of a table is its metatable, otherwise works like standard type() +-- @param obj a value +-- @return the type, either a string or the metatable +function ml.type (obj) + if _type(obj) == 'table' then + return getmetatable(obj) or 'table' + else + return _type(obj) + end +end + +return ml |