Restrict arguments to a specific type/size and test adherence to validation functions/formulas.
restrict.Rd
This function takes any number of named expressions referring to objects
in the given environment, checking and possibly coercing them to the specified
type and/or size, and also checking them against any number of validation
functions/formulas. Using the function keywords of validate
, cast
,
lossy_cast
, recycle
, and coerce
within the expressions allows for
different behaviours:
validate
: checks that the object is of the specified type/size and adheres to the validations, throwing an error if not.cast
: differs from validate by checking that the object is of the specified type, and if not attempts to cast it to that type (throwing an error if not possible).lossy_cast
: differs fromcast
by allowing lossy casting (e.g. double to integer).recycle
: differs fromvalidate
by checking that the object is of the specified size, and if not attempts to recycle it to that size (throwing an error if not possible).coerce
: differs fromvalidate
by checking both the type and size, and attempting to cast and/or recycle it to that type/size (throwing an error if not possible). Casting is not lossy by default but can be made lossy by addinglossy = TRUE
within thecoerce()
call.
Arguments
- ...
any number of named R expressions, with the names referring to objects in the environment specified by the
.env
argument, and the expressions built using the functions:validate()
,cast()
,lossy_cast()
,recycle()
, andcoerce()
.- .env
the environment to use for the evaluation of the expressions & the (possible) assignment of the variables. Cannot be the global environment.
- .class
class to assign to the error (passed to rlang::abort).
- .error_call
the call environment to use for the error (passed to rlang::abort).
Details
These functions accept the named arguments type
, size
and mask
(lossy
is also accepted within coerce()
):
type
: an R object of the desired type (e.g.integer()
,double()
,character()
,list()
). The type checking and casting are done using the vctrs package (using vctrs::vec_is and vctrs::vec_cast) and thus stick to the vctrs type conversion rules.size
: a scalar integerish value specifying the desired size. The size checking and recycling are done using the vctrs package (using vctrs::vec_size and vctrs::vec_recycle) and thus stick to the vctrs recycling rules.mask
: an optional data frame or list to use as a data mask for evaluations. Expressions are evaluated using rlang::eval_tidy with thedata
argument set to the mask and theenv
argument set to the environment specified by the.env
argument torestrict()
. The mask must be present within the environment.
All other inputs should be unnamed validations: either expressions or formulas
(that evaluate to logical). restrict
first evaluates type, then size, then the
validations. Any change from the prior expression is reflected in subsequent
expressions, i.e. if an object is cast to a new type then that new type is
used for the size check and validations.
If you do not wish to use the vctrs type/size checking,
then instead give validations functions such as ~ is.integer(.x)
.
However, these will only validate, not cast or recycle.
restrict
is designed for the checking of numerous objects, for a smaller number of
objects to check see the abort_if_not, cast_if_not,
recycle_if_not, schema, schema_cast and
schema_recycle functions.
Examples
# Will not alter the global environment so most examples here are wrapped with local().
x <- 1L
restrict(x = validate(type = integer())) |> try()
# => Error : Argument `.env` cannot be the global environment.
local({
x <- 1L
restrict(x = coerce(type = double(), size = 3))
cat(class(x), length(x), sep = ", ")
})
#> numeric, 3
local({
x <- 1.5
restrict(x = cast(type = integer())) |> try()
})
#> Error in eval(quote({ : Error in `restrict()`
#> ℹ Can't convert from `x` <double> to <integer> due to loss of precision. •
#> Locations: 1
# => Error : Can't convert from `x` <double> to <integer> due to loss of precision.
local({
x <- 1.5
restrict(x = lossy_cast(type = integer()))
cat(x, class(x), sep = ", ")
# or
x <- 1.5
restrict(x = coerce(type = integer(), lossy = TRUE))
cat(x, class(x), sep = ", ")
})
#> 1, integer1, integer
# other objects can be used as the type to cast to or size to recycle to, e.g.:
local({
x <- 1L
y <- 2.3
z <- 3L
restrict(x = coerce(type = y, size = z))
cat(class(x), length(x), sep = ", ")
})
#> numeric, 3
# restrict works sequentially, so references to objects will be
# after they have been evaluated:
local({
x <- y <- 1L
restrict(
x = cast(type = double()),
y = cast(type = x)
)
cat(class(x), class(y), sep = ", ")
})
#> numeric, numeric
# numerous validations can be given and type and size checking can be done
# within if base R checking is preferred:
local({
x <- 1L
restrict(
x = validate(
~ is.integer(.x),
~ length(.x) == 1,
\(y) all(y > 0),
\(z) !is.character(z)
)
)
})
# the `.env` argument determines the expression and assignment environment:
local({
x <- 1L
e <- new.env()
e$x <- 1L
restrict(x = cast(type = 1.5), .env = e)
cat(class(e$x), class(x), sep = ", ")
})
#> numeric, integer
# names (lhs) are checked to be in the `.env` environment, throwing an error if not found:
local({
x <- 1L
e <- new.env()
restrict(x = cast(type = 1.5), .env = e) |> try()
})
#> Error in eval(quote({ : Error in `restrict()`
#> ℹ Objects `x` are not found in the `.env` environment specified.
# => Error: Objects `x` are not found in the `.env` environment specified.
# for expressions (rhs), the `.env` argument is preferentially chosen, but if not found
# then the normal R scoping rules apply:
local({
x <- 1.5
e <- new.env()
e$z <- 1L
restrict(x = cast(type = x), .env = e) |> try()
cat(class(e$z))
})
#> Error in eval(quote({ : Error in `restrict()`
#> ℹ Objects `x` are not found in the `.env` environment specified.
#> integer