[Date Prev][Date Next][Thread Prev][Thread Next]
[Date Index]
[Thread Index]
- Subject: Re: Suggestion: "usertype()" function
- From: Dubiousjim <lists+lua@...>
- Date: Thu, 31 May 2012 01:48:14 -0400
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