Reputation: 3534
I would like the end-user functions in my R package (S3 style) to validate their arguments and give the user informative errors or warnings when a particular validity check fails.
The obvious (but tedious and unmaintainable) way to do this would be:
foo<-function(aa,bb,cc,dd){
if(length(aa)!=1) stop("The argument 'aa' must have a single value");
if(!is.numeric(aa)) stop("The argument 'aa' must be numeric");
if(!is.character(bb)) stop("The argument 'bb' must be a character");
if(length(bb)>=4||length(bb)<=2) stop("The argument 'bb' must be a vector with a length between 2 and 4");
if(!is.recursive(cc)) stop("The argument 'cc' must be a list-like object");
if(!is.integer(dd)) stop("The argument 'dd' must contain only integers");
if(any(dd<aa)) stop("All values in the argument 'dd' must be greater than the value of argument 'aa'");
## ...and so on
}
I'm assuming that I'm by far not the first one to do this. So, can anybody suggest a package that automates all or part of such validation tasks? Or, failing that, some concise, generic idioms that will limit the ugliness to as few lines as possible within each function?
Thanks.
Upvotes: 4
Views: 354
Reputation: 12819
You can write a helper function like this (rudimentary example):
validate <- function(x, ...){
for(s in c(...)) switch(s,
lengthone = if(length(x)!=1) stop("argument has length != 1."),
numeric = if(!all(is.numeric(x))) stop("non-numeric arguments."),
positive = if(any(x <= 0)) stop("non-positive arguments."),
nonmissing = if(any(is.na(x))) stop("Missing values in arguments.")
)
}
Results:
> validate(1, "numeric", "positive")
> validate(0, "numeric", "positive")
Error in validate(0, "numeric", "positive") : non-positive arguments.
Upvotes: 1
Reputation: 61933
stopifnot
might be similar to what you're looking for. The error messages won't be quite as nice though
foo <- function(x){
stopifnot(length(x) == 1, is.numeric(x))
return(x)
}
which gives
> foo(c(1,3))
Error: length(x) == 1 is not TRUE
> foo("a")
Error: is.numeric(x) is not TRUE
> foo(3)
[1] 3
Upvotes: 5