From 8559a6c5eb295f8af6b089ede2e8c891e9eccdfd Mon Sep 17 00:00:00 2001 From: Gael <Gael@WL20-0067.corp.pasteur.fr> Date: Fri, 16 Oct 2020 09:56:21 +0200 Subject: [PATCH] v1.3 release --- README.md | 9 ++++++- r_debugging_tools.R | 58 ++++++++++++++++++++++++++++++++++----------- 2 files changed, 52 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index b4ddcfa..ea15132 100644 --- a/README.md +++ b/README.md @@ -3,6 +3,13 @@ Download the desired Tagged version, never the current master. Source the cute_little_functions.R into R/RStudio to have the functions available in the working environment. -WHAT'S NEW IN v1.2: +WHAT'S NEW IN + +v1.3: + +1) NULL arguments, non NULL argument, logical and NA arguments added + + +v1.2: 1) printing result improvement diff --git a/r_debugging_tools.R b/r_debugging_tools.R index 84a397c..7489584 100644 --- a/r_debugging_tools.R +++ b/r_debugging_tools.R @@ -13,50 +13,80 @@ str_basic_arg_check_dev <- ' # AIM: # string that check: -# NULL argument default value -# argument without default values +# NULL argument default values +# arguments without default values +# arguments with variable as default value (FORBIDDEN) # STRING function.name <- as.list(match.call(expand.dots=FALSE))[[1]] default.arg.list <- formals(fun = sys.function(sys.parent(n = 2))) # list of all the arguments of the function with their default values (not the values of the user !). Use n = 2 when he string has to be evaluated by eval() inside a function. Use n=1 (default) if not evaluation. It seems that ls() as first line of the function provide the names of the arguments (empty, called, etc., or not) arg.without.default.value <- sapply(default.arg.list, is.symbol) & sapply(sapply(default.arg.list, as.character), identical, "") # logical to detect argument without default values (these are typeof "symbol" and class "name" and empty character +name.or.empty.default.val.arg.log <- sapply(default.arg.list, FUN = "class") == "name" + +if(length(name.or.empty.default.val.arg.log) != length(arg.without.default.value)){ +stop(paste0("\n\n================\n\nINTERNAL ERROR IN str_basic_arg_check_dev IN ", function.name,". CODE MUST BE MODIFED\n\n================\n\n")) +}else if(any(name.or.empty.default.val.arg.log & ! arg.without.default.value)){ +cat(paste0("\n\n================\n\nALERT\nDEFAULT VALUE OF ARGUMENT OF ", function.name," MUST NOT BE A VARIABLE (POTENTIAL PROBLEM OF SCOPE)\nTHE CONCERNED ARGUMENTS ARE:\n", paste(names(formals(fun = sys.function(sys.parent(n = 2))))[name.or.empty.default.val.arg.log & ! arg.without.default.value], collapse = "\n"), "\n\n================\n\n")) +} + cat(paste0("\n\n================================\n\n", function.name," FUNCTION ARGUMENT CHECKING\n\n================================\n")) cat(paste0("\n================\nARGUMENTS OF THE FUNCTION ARE (INCLUDING DEFAULT VALUES):\n\n")) print(default.arg.list) + +if(any(arg.without.default.value)){ # argument names that are empty by default added now because null arguments will not be inserted thenafter +cat(paste0("\n================\nARGUMENTS WITHOUT DEFAULT VALUES ARE: ", paste(names(default.arg.list)[arg.without.default.value], collapse= " "))) +}else{ +cat(paste0("\n================\nNO ARGUMENTS WITHOUT DEFAULT VALUES")) +} + if(any(sapply(default.arg.list, FUN = is.null))){ cat(paste0("\n================\nNULL ARGUMENTS ARE: ", paste(names(default.arg.list)[sapply(default.arg.list, FUN = is.null)], collapse= " "))) }else{ cat(paste0("\n================\nNO NULL ARGUMENTS")) } -if(any(arg.without.default.value)){ # argument names that are empty by default added now because null arguments will not be inserted thenafter -cat(paste0("\n================\nARGUMENTS WITHOUT DEFAULT VALUES ARE: ", paste(names(default.arg.list)[arg.without.default.value], collapse= " "))) + +if(any( ! sapply(default.arg.list, FUN = is.null))){ +cat(paste0("\n================\nNON NULL ARGUMENTS ARE: ", paste(names(default.arg.list)[ ! sapply(default.arg.list, FUN = is.null)], collapse= " "))) }else{ -cat(paste0("\n================\nNO ARGUMENTS WITHOUT DEFAULT VALUES")) +cat(paste0("\n================\nNO NON NULL ARGUMENTS")) +} + +if(any(sapply(default.arg.list, FUN = is.logical))){ +cat(paste0("\n================\nLOGICAL ARGUMENTS ARE: ", paste(names(default.arg.list)[sapply(default.arg.list, FUN = is.logical)], collapse= " "))) +}else{ +cat(paste0("\n================\nNO LOGICAL ARGUMENTS")) } + +if(any(sapply(default.arg.list, FUN = is.na))){ +cat(paste0("\n================\nNA ARGUMENTS ARE: ", paste(names(default.arg.list)[sapply(default.arg.list, FUN = is.na)], collapse= " "))) +}else{ +cat(paste0("\n================\nNO NA ARGUMENTS")) +} + cat(paste0("\n================\n\n")) # END STRING ' -str_arg_check_with_fun_param_check_dev <- ' +str_arg_check_with_fun_check_dev <- ' # AIM: # string that check: -# which arguments have been checked using fun_param_check() +# which arguments have been checked using fun_check() # STRING function.name <- as.list(match.call(expand.dots=FALSE))[[1]] default.arg.list <- formals(fun = sys.function(sys.parent(n = 2))) # list of all the arguments of the function with their default values (not the values of the user !). Use n = 2 when he string has to be evaluated by eval() inside a function. Use n=1 (default) if not evaluation. It seems that ls() as first line of the function provide the names of the arguments (empty, called, etc., or not) if( ! any(ls() %in% "checked.arg.names")){ - cat(paste0("\n\n================\n\nERROR: MISSING checked.arg.names OBJECT. ARGUMENTS MAY HAVE NOT BEEN CHECKED USING fun_param_check(). SEE THE fun_export_data() FUNCTION FOR THIS KIND OF CHECKING\n\n================\n\n")) + cat(paste0("\n\n================\n\nERROR: MISSING checked.arg.names OBJECT. ARGUMENTS MAY HAVE NOT BEEN CHECKED USING fun_check(). SEE THE fun_export_data() FUNCTION FOR THIS KIND OF CHECKING\n\n================\n\n")) } -if( ! find("fun_param_check") == ".GlobalEnv"){ - cat(paste0("\n\n================\n\nERROR: MISSING fun_param_check() FUNCTION IN THE GLOBAL ENVIRONMENT. ARGUMENTS MAY HAVE NOT BEEN CHECKED USING fun_param_check(). SEE THE fun_export_data() FUNCTION FOR THIS KIND OF CHECKING\n\n================\n\n")) +if( ! find("fun_check") == ".GlobalEnv"){ + cat(paste0("\n\n================\n\nERROR: MISSING fun_check() FUNCTION IN THE GLOBAL ENVIRONMENT. ARGUMENTS MAY HAVE NOT BEEN CHECKED USING fun_check(). SEE THE fun_export_data() FUNCTION FOR THIS KIND OF CHECKING\n\n================\n\n")) } -cat(paste0("\n\n================================\n\n", function.name," FUNCTION ARGUMENT CHECKING USING fun_param_check()\n\n================================\n")) +cat(paste0("\n\n================================\n\n", function.name," FUNCTION ARGUMENT CHECKING USING fun_check()\n\n================================\n")) if(any(duplicated(checked.arg.names))){ # for function debbuging -cat(paste0("\n================\nTHESE ARGUMENTS ARE DUPLICATED IN CHECK USING fun_param_check(): ", paste(checked.arg.names[duplicated(checked.arg.names)], collapse = " "))) +cat(paste0("\n================\nTHESE ARGUMENTS ARE DUPLICATED IN CHECK USING fun_check(): ", paste(checked.arg.names[duplicated(checked.arg.names)], collapse = " "))) } if( any(! names(default.arg.list) %in% checked.arg.names)){ # check the correct number of args # for function debbuging # names(default.arg.list) can be replaced by formalArgs("name of the created function") -cat(paste0("\n================\nTHESE ARGUMENTS HAVE NOT BEEN CHECKED WITH fun_param_check(): ", paste(names(default.arg.list)[ ! names(default.arg.list) %in% checked.arg.names], collapse = " "))) +cat(paste0("\n================\nTHESE ARGUMENTS HAVE NOT BEEN CHECKED WITH fun_check(): ", paste(names(default.arg.list)[ ! names(default.arg.list) %in% checked.arg.names], collapse = " "))) }else{ -cat(paste0("\n================\nALL THE ARGUMENTS HAVE BEEN CHECKED USING fun_param_check()")) +cat(paste0("\n================\nALL THE ARGUMENTS HAVE BEEN CHECKED USING fun_check()")) } cat(paste0("\n================\n\n")) # END STRING -- GitLab