lua-users home
lua-l archive

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


I know there are many existing implementations of custom type predicates
floating around. But I thought I'd point out my own, which readers of
this thread may find of interest. From
https://github.com/dubiousjim/luafiveq/blob/master/BENEFITS-LUA:
> 
> What do I get when I ... require "fiveqplus"?
> ---------------------------------------------
> 
>     an additional global function `check` is provided; this is somewhat
>     akin to assert:
>             check(test, arg#, fmt, args ...)
>     One difference is that check expects a second argument `arg#`
>     that identifies the position of the checked object in an argument list.
>     If check's `test` argument is true-like, then that argument (and it
>     alone) is returned, else the third argument is used as a format string
>     together with all subsequent arguments. For example:
> 
>             > function example(arg) local x = check(arg, 1, "foo %s",
>             > "bar") end
>             > example(false)
>             stdin:1: bad argument #1 to 'example' (foo bar)
>             stack traceback:
>                 [C]: in function 'check'
>                 stdin:1: in function 'example'
>                 stdin:1: in main chunk
>                 [C]: ?
> 
> 
>     an additional library `err` is provided with more specific
>     error/checking functions to complement error, assert, and check...
> 
> 
>     err.istype(obj, types ...)
>         returns the first of the type arguments that obj satisfies, or false
>         if it satisfies none of them. The type arguments can be any of:
>             * the standard return values from type(obj): "nil", "table",
>               "boolean", and so on. Both full and light userdata satisfy
>               "userdata". For "string" and "number", obj merely has to be
>               convertible to the type
>             * "positive" if obj is convertible to a positive integer
>             * "natural" if obj is convertible to a non-negative integer
>             * "negative" if obj is convertible to a negative integer
>             * "string!" if obj is literally a string; whereas "string" merely
>               requires obj to be convertible to a string
>             * "number!" if obj is literally a number, not just convertible to
>               one
>             * "integer!" if obj is literally an integer-valued number
>               (plain "integer" is also available, but anything that satisfies
>               "number" also counts as convertible to an integer, by truncation)
>             * "positive!" if obj is literally a positive integer
>             * "natural!" if obj is literally a non-negative integer
>             * "negative!" if obj is literally a negative integer
>             * "callable" if obj is a function or has a function for its __call
>               metamethod
>             * "indexable" if obj is a table or has a table or function for
>               its __index metamethod
>             * "iterable" if obj is a table or has an __singles or __pairs
>               metamethod
>             * "iterator" if obj is a function: the idea is that
>               istype({}, "iterator") returns false but
>               istype(pairs({}), "iterator") returns true. The same effect
>               can be achieved with "function", but this documents the
>               programmer's intentions more clearly.
>             * any typeobject: obj will count as satisfying this type if either
>               obj's metatable or its __type metamethod equals the typeobject
> 
>     err.checktype(obj, arg#, [expected index], types ...)
>         a hybrid of check and istype: if object satisfies any of the type
>         arguments, the first one it satisfies is returned. Else an error
>         is raised complaining that the function expected an object of type
>         so-and-so, but received one of type such-and-such. You can
>         explicitly specify the index of the type that was expected (the first
>         one having index 1); else 1 is assumed. Examples:
> 
>         > function example(a, b, c) checktype(c, 3, "number", "string") end
>         > example(1, 2, false)
>         stdin:1: bad argument #3 to 'example' (number expected, got boolean)
>         stack traceback:
>             [C]: in function 'checktype'
>             stdin:1: in function 'example'
>             stdin:1: in main chunk
>             [C]: ?
> 
>         > function example(a, b, c) checktype(c, 3, 2, "number", "string") end
>         > example(1, 2, false)
>         stdin:1: bad argument #3 to 'example' (string expected, got boolean)
>         stack traceback:
>             [C]: in function 'checktype'
>             stdin:1: in function 'example'
>             stdin:1: in main chunk
>             [C]: ?
> 
>     err.checkopt(obj, arg#, type, [default])
>         asserts that obj satisfies the single type argument, or else is nil;
>         if the assertion fails, raises an error of the same format as checktype.
>         if the assertion succeeds and obj is nil, returns default; else
>         returns obj
> 
>     err.checkany(obj, arg#)
>         asserts that obj is of any non-nil type; if the assertion fails,
>         raises an error of the same format as checktype. if the assertion
>         succeeds, returns obj
> 
>     err.arenil(args, ...)
>             returns true if all its arguments are nil
> 
>     err.checkrange(num, arg#, [min], max)
>     err.checkrange(num, arg#, [min], -max)
>         asserts that num is a number in the inclusive range min...max;
>         min defaults to 1. If max is negative, its absolute value is used,
>         and additionally, num is also permitted to be -1, -2, and so on.
>         A value of -1 for num is converted to max; -2 is converted to max-1;
>         and so on. Raises an error of the same format as checktype if the
>         range constraints are violated; else returns the (possibly converted)
>         num.
> 

There's more to the err library (and much more to fiveqplus), but these
are the elements relevant to the present discussion.

-- 
Dubiousjim
dubiousjim@gmail.com