## ----setup, include=FALSE----------------------------------------------------- knitr::opts_chunk$set(echo = TRUE, eval = TRUE) ## ----echo = FALSE------------------------------------------------------------- library(dreamerr) x = 1:5 y = pt sum_check = function(...){ check_arg(..., "numeric vector") sum(...) } Sys.setenv(LANG = "en") ## ----error = TRUE------------------------------------------------------------- sum(x, y) ## ----error = TRUE------------------------------------------------------------- sum_check(x, y) ## ----eval = FALSE------------------------------------------------------------- # sum_check = function(...){ # check_arg(..., "numeric vector") # sum(...) # } ## ----------------------------------------------------------------------------- plot_cor = function(x, y = NULL, line.opts = list(), ...){ # x: numeric vector, must be given by the user check_arg(x, "numeric vector mbt") # y: # - numeric vector of the same length as x # - if y is NULL, then x with some noise is assigned to it check_set_arg(y, "NULL{x + rnorm(length(x))} numeric vector len(data)", .data = x) # We ensure line.opts is a list check_arg(line.opts, "named list") # The linear regression + options from ... reg = lm(y ~ x, ...) # plotting the correlation plot(x, y) # The fit, all arguments are in line.opts # col: # - if not provided => "firebrick" # - partially matched to firebrick or darkblue # - otherwise, a positive integer or a character scalar check_set_arg(line.opts$col, "NULL{'firebrick'} match(firebrick, darkblue) | scalar(integer, character) GE{0}") # lwd: # - if not provided => 2 # - otherwise a positive integer scalar check_set_arg(line.opts$lwd, "integer scalar GE{0} NULL{2}") # check + default line.opts$a = reg do.call("abline", line.opts) } plot_cor(rnorm(100), line.opts = list(col = "dark")) ## ----------------------------------------------------------------------------- lm_check = function(formula, data, subset, weights, na.action, method = "qr", model = TRUE, x = FALSE, y = FALSE, qr = TRUE, singular.ok = TRUE, contrasts = NULL, offset, ...){ # data: # - data.frame or named list (a data.frame is a named list, but it is still added for clarity) check_arg(data, "data.frame | named list") # formula: # - must be provided by the user (mbt) # - must be two-sided (ts) # - variables must be in the data or in the environment [var(data, env)] check_arg(formula, "ts formula var(data, env) mbt", .data = data) # subset: # - either a logical or an integer vector # - can be a variable of the data set (eval) check_arg(subset, "eval vector(logical, strict integer)", .data = data) # weights: # - vector of positive integers # - can be NULL # - can be a variable of the data set (eval) check_arg(weights, "eval vector numeric GE{0} safe null", .data = data) # na.action: # - can be NULL # - must be a function with at least one argument check_arg(na.action, "null function arg(1,)") # method: # - either 'qr' or 'model.frame', partially matched check_set_arg(method, "match(qr, model.frame)") # You can pool arguments of the same type: check_arg(model, x, y, qr, singular.ok, "logical scalar") # contrasts: # - NULL or list check_arg(contrasts, "null list") # offset: # - can be NULL # - numeric matrix or vector check_arg(offset, "null numeric vmatrix") mc = match.call() mc[[1]] = as.name("lm") eval(mc, parent.frame()) } ## ----------------------------------------------------------------------------- lm_check_bis = function(formula, data, subset, weights, na.action, method = "qr", model = TRUE, x = FALSE, y = FALSE, qr = TRUE, singular.ok = TRUE, contrasts = NULL, offset, ...){ # data: now only a data.frame and required check_arg(data, "data.frame mbt") # formula: All variables must be in the data check_arg(formula, "ts formula var(data) mbt", .data = data) # subset: => now we can be more precise # - if logical: must be of the same length as the data (otherwise it's a mistake) # - if integer, can be of any length (strict integer is used, because we don't want it to be logical) check_arg(subset, "eval vector strict logical len(data) | vector strict integer", .data = data) # weights:vector of positive integers, of the same length as the data check_arg(weights, "eval vector numeric GE{0} safe null len(data)", .data = data) # Below: same as before check_arg(na.action, "null function arg(1,)") check_set_arg(method, "match(qr, model.frame)") check_arg(model, x, y, qr, singular.ok, "logical scalar") check_arg(contrasts, "null list") # we extract the left hand side (it can be multi response) y = eval(formula[[2]], data) # offset: # - if y is a matrix => offset must be a matrix of the same number of columns check_arg(offset, "null numeric vmatrix ncol(data)", .data = y) mc = match.call() mc[[1]] = as.name("lm") eval(mc, parent.frame()) }