├── .Rbuildignore ├── .Renviron ├── .Rprofile ├── .github └── workflows │ └── r-checks.yml ├── .gitignore ├── .vscode ├── settings.json └── tasks.json ├── DESCRIPTION ├── NAMESPACE ├── NEWS.md ├── R ├── check_arg.R ├── check_dreamerr_calls.R ├── dreamerr.R ├── misc_funs.R ├── onLoad.R └── stop.R ├── README.md ├── docs ├── 404.html ├── articles │ ├── check_arg_call.png │ ├── dreamerr_introduction.html │ ├── dreamerr_introduction_files │ │ └── figure-html │ │ │ └── unnamed-chunk-5-1.png │ ├── forming_a_type.png │ ├── images │ │ ├── check_arg_call.png │ │ └── forming_a_type.png │ └── index.html ├── authors.html ├── bootstrap-toc.css ├── bootstrap-toc.js ├── docsearch.css ├── docsearch.js ├── index.html ├── link.svg ├── news │ └── index.html ├── pkgdown.css ├── pkgdown.js ├── pkgdown.yml ├── reference │ ├── Rplot001.png │ ├── Rplot002.png │ ├── Rplot003.png │ ├── Rplot004.png │ ├── Rplot005.png │ ├── check_arg-1.png │ ├── check_arg-2.png │ ├── check_arg-3.png │ ├── check_arg-4.png │ ├── check_arg-5.png │ ├── check_arg.html │ ├── check_expr.html │ ├── dreamerr-package.html │ ├── enumerate_items.html │ ├── fit_screen.html │ ├── fsignif.html │ ├── ifsingle.html │ ├── index.html │ ├── n_times.html │ ├── package_stats.html │ ├── plural.html │ ├── setDreamerr_check.html │ ├── setDreamerr_dev.mode.html │ ├── setDreamerr_show_stack.html │ ├── set_check.html │ ├── set_up.html │ ├── sfill.html │ ├── stop_hook.html │ ├── stop_up.html │ ├── suggest_item.html │ └── validate_dots.html └── sitemap.xml ├── man ├── check_arg.Rd ├── check_expr.Rd ├── dreamerr-package.Rd ├── enumerate_items.Rd ├── fit_screen.Rd ├── fsignif.Rd ├── ifsingle.Rd ├── n_times.Rd ├── package_stats.Rd ├── plural.Rd ├── setDreamerr_check.Rd ├── setDreamerr_dev.mode.Rd ├── setDreamerr_show_stack.Rd ├── set_check.Rd ├── set_up.Rd ├── sfill.Rd ├── stop_hook.Rd ├── stop_up.Rd ├── suggest_item.Rd └── validate_dots.Rd ├── tests └── tests_dreamerr.R └── vignettes ├── dreamerr_introduction.Rmd └── images ├── check_arg_call.png └── forming_a_type.png /.Rbuildignore: -------------------------------------------------------------------------------- 1 | ^.*\.Rproj$ 2 | ^\.Rproj\.user$ 3 | Rplots.pdf 4 | ^\.Renviron$ 5 | ^\.Rprofile$ 6 | ^\.vscode$ 7 | ^docs$ 8 | ^\.github$ 9 | -------------------------------------------------------------------------------- /.Renviron: -------------------------------------------------------------------------------- 1 | 2 | package_ROOT = TRUE 3 | -------------------------------------------------------------------------------- /.Rprofile: -------------------------------------------------------------------------------- 1 | 2 | 3 | local({ 4 | # 0-dep function to silently load (and install if needed) packages at startup 5 | load_pkg = function(...){ 6 | mc = match.call(expand.dots = FALSE) 7 | mc_dots = mc[["..."]] 8 | 9 | for(i in seq_along(mc_dots)){ 10 | pkg_i = mc_dots[[i]] 11 | pkg_name = if(is.character(pkg_i)) pkg_i else deparse(pkg_i) 12 | 13 | if(!requireNamespace(pkg_name, quietly = TRUE)){ 14 | ok = try(utils::install.packages(pkg_name, repos = "https://cloud.r-project.org/")) 15 | if(inherits(ok, "try-error")){ 16 | stop("Could not install package `", pkg_name, "`. Please fix the problem manually.") 17 | } 18 | } 19 | 20 | suppressWarnings(suppressPackageStartupMessages(library(pkg_name, character.only = TRUE))) 21 | } 22 | } 23 | 24 | # add packages to load here: eg load_pkg(fixest, stringmagic) 25 | 26 | # Replacing View with datadive 27 | if(requireNamespace("datadive", quietly = TRUE)){ 28 | assign("View", datadive::app_explore, .GlobalEnv) 29 | } 30 | 31 | # VSCode specific 32 | # adapted from: https://github.com/REditorSupport/vscode-R/wiki/Interacting-with-R-terminals 33 | # => no error if file is missing 34 | if (interactive() && Sys.getenv("RSTUDIO") == "") { 35 | Sys.setenv(TERM_PROGRAM = "vscode") 36 | HOME = if(.Platform$OS.type == "windows") "USERPROFILE" else "HOME" 37 | my_file = file.path(Sys.getenv(HOME), ".vscode-R", "init.R") 38 | if(file.exists(my_file)){ 39 | source(my_file) 40 | options(vsc.rstudioapi = TRUE) 41 | } 42 | } 43 | }) 44 | 45 | 46 | -------------------------------------------------------------------------------- /.github/workflows/r-checks.yml: -------------------------------------------------------------------------------- 1 | # Workflow derived from https://github.com/r-lib/actions/tree/v2/examples 2 | # Need help debugging build failures? Start at https://github.com/r-lib/actions#where-to-find-help 3 | on: 4 | push: 5 | branches: [main, master] 6 | pull_request: 7 | branches: [main, master] 8 | 9 | name: R-CMD-check 10 | 11 | jobs: 12 | R-CMD-check: 13 | runs-on: ${{ matrix.config.os }} 14 | 15 | name: ${{ matrix.config.os }} (${{ matrix.config.r }}) 16 | 17 | strategy: 18 | fail-fast: false 19 | matrix: 20 | config: 21 | - {os: macos-latest, r: 'release'} 22 | - {os: windows-latest, r: 'release'} 23 | - {os: ubuntu-latest, r: 'release'} 24 | 25 | env: 26 | GITHUB_PAT: ${{ secrets.GITHUB_TOKEN }} 27 | R_KEEP_PKG_SOURCE: yes 28 | 29 | steps: 30 | - uses: actions/checkout@v3 31 | 32 | - uses: r-lib/actions/setup-pandoc@v2 33 | 34 | - uses: r-lib/actions/setup-r@v2 35 | with: 36 | r-version: ${{ matrix.config.r }} 37 | http-user-agent: ${{ matrix.config.http-user-agent }} 38 | use-public-rspm: true 39 | 40 | - uses: r-lib/actions/setup-r-dependencies@v2 41 | with: 42 | extra-packages: any::rcmdcheck 43 | needs: check 44 | 45 | - uses: r-lib/actions/check-r-package@v2 46 | with: 47 | upload-snapshots: true 48 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .Rproj.user 2 | .Rhistory 3 | .RData 4 | .Ruserdata 5 | Rplots.pdf 6 | dreamerr.Rproj 7 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "cmake.configureOnOpen": true 3 | } -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | 2 | { 3 | // This task has been automatically generated by 4 | // {$userHome}/.vscode/scripts/setup-r-projects 5 | // 6 | // When the VSCode folder is open, this task opens a split terminal 7 | // with git bash on the left and R terminal on the right 8 | // 9 | // This task is automatically added to the project only if an R folder is there 10 | // or the workspace root contains an .R file, or at least one direct childern folder 11 | // contains an .R file 12 | // 13 | // See ctrl+shift+P -> Tasks: Open user tasks -> "Setup R projects watcher" 14 | // 15 | 16 | "version": "2.0.0", 17 | "tasks": [ 18 | { 19 | "label": "Create terminals", 20 | "dependsOn": [ 21 | "git bash", 22 | "R-term" 23 | ], 24 | "runOptions": { 25 | "runOn": "folderOpen" 26 | } 27 | }, 28 | { 29 | "type": "R", 30 | "code": [ 31 | "devtools::install()" 32 | ], 33 | "group": "build", 34 | "problemMatcher": [], 35 | "label": "R: Install" 36 | } 37 | ] 38 | } 39 | 40 | 41 | -------------------------------------------------------------------------------- /DESCRIPTION: -------------------------------------------------------------------------------- 1 | Package: dreamerr 2 | Type: Package 3 | Title: Error Handling Made Easy 4 | Version: 1.5.0 5 | Authors@R: person("Laurent", "Berge", email = "laurent.berge@u-bordeaux.fr", role = c("aut", "cre")) 6 | Imports: Formula, utils, stringmagic(>= 1.2.0) 7 | Suggests: knitr, rmarkdown, stats, graphics 8 | Description: Set of tools to facilitate package development and make R a more user-friendly place. Mostly for developers (or anyone who writes/shares functions). Provides a simple, powerful and flexible way to check the arguments passed to functions. 9 | The developer can easily describe the type of argument needed. If the user provides a wrong argument, then an informative error message is prompted with the requested type and the problem clearly stated--saving the user a lot of time in debugging. 10 | License: GPL-3 11 | Encoding: UTF-8 12 | VignetteBuilder: knitr 13 | BugReports: https://github.com/lrberge/dreamerr/issues 14 | RoxygenNote: 7.3.2 15 | Roxygen: list(markdown = TRUE) 16 | -------------------------------------------------------------------------------- /NAMESPACE: -------------------------------------------------------------------------------- 1 | 2 | 3 | # Functions to export -- main 4 | export(check_arg, check_arg_plus, check_set_arg) 5 | export(check_value, check_value_plus, check_set_value) 6 | export(check_expr) 7 | export(validate_dots) 8 | 9 | # hook related functions 10 | export(set_hook, stop_hook, warn_hook, check_expr_hook) 11 | export(generate_set_hook, generate_stop_hook, generate_warn_hook, 12 | generate_check_expr_hook, generate_get_hook) 13 | 14 | # stop/warn 15 | export(stop_up, warn_up, stopi, warni) 16 | 17 | # misc 18 | export(fit_screen, suggest_item) 19 | 20 | # Other, deprecated following stringmagic integration 21 | export(n_letter, n_th, n_times) 22 | export(signif_plus, fsignif) 23 | export(ifsingle, ifunit, plural, plural_len, enumerate_items) 24 | export(sfill) 25 | 26 | # Setter/Getter 27 | export(setDreamerr_check, setDreamerr_dev.mode, setDreamerr_show_stack) 28 | export(set_up, set_check) 29 | 30 | # Goodies 31 | export(package_stats) 32 | 33 | 34 | # 35 | # IMPORTS 36 | # 37 | 38 | importFrom(Formula, Formula) 39 | importFrom(utils, find) 40 | importFrom(stringmagic, sma, string_magic) 41 | 42 | 43 | -------------------------------------------------------------------------------- /NEWS.md: -------------------------------------------------------------------------------- 1 | 2 | # dreamerr 1.5.0 3 | 4 | ## New features 5 | 6 | - the argument `.message` of the `check_` functions is now interpolated with `string_magic()` 7 | 8 | ## User-level changes 9 | 10 | - the type `l0` has been removed. Now `check_arg(x, "vector")` (or the like) receiving something 0-length in input will not send an error (in the previous version, `l0` was required). Vector length can still be checked with the `len(a,b)` mechanism (thanks to @kylebutts for early bug reports). 11 | 12 | ## Minor changes 13 | 14 | - to increase clarity, now the problem leading to an error is displayed in a newline with the prefix `PROBLEM` in uppercase 15 | 16 | - improve clarity of error messages involving lower than/greater than 17 | 18 | - improve the number of items suggested by `suggest_item` 19 | 20 | ## Bug fixes 21 | 22 | - fix display problem in `fsignif` 23 | 24 | - increase the requirement of `stringmagic` version to be compatible with R v3.5.0 25 | 26 | - the `check_arg` family of functions now correctly reports the full call stack when requested 27 | 28 | - fix bug: wrong argument name displayed when `check_value` was used with the argument `.arg_name` and an error was produced because a variable was missing in a formula. Thanks to @kylebutts, #4. 29 | 30 | # dreamerr 1.4.0 31 | 32 | ## New functions 33 | 34 | - New set of `hook` error and warning functions for reporting in complex internal functions. These are `set_hook` to set a function as the hook and `stop_hook`/`warn_hook` error and warning functions used to report as if they were called from the hooked function. 35 | 36 | - `warni` and `stopi` for warning and stop functions with character interpolation using [stringmagic](https://github.com/lrberge/stringmagic) 37 | 38 | ## New type 39 | 40 | - The type `path` has been added to `check_arg`. It is used to check paths. 41 | 42 | ## Improvements 43 | 44 | - All warning and stop functions gain string interpolation with [stringmagic](https://github.com/lrberge/stringmagic). 45 | 46 | 47 | # dreamerr 1.3.0 48 | 49 | ## Bug fixes 50 | 51 | - fixes `fit_screen` so that it does not mess with white spaces. 52 | 53 | ## Name changes 54 | 55 | - Functions `check_arg_plus` and `check_value_plus` become `check_set_arg` and `check_set_value` to improve clarity. 56 | 57 | ## Improvements 58 | 59 | - `fsignif` now displays trailing 0s appropriately and is neutral to character vectors (instead of throwing an error). 60 | 61 | - the comparison types now can evaluate values from the calling frame: 62 | ```r 63 | z = 32 64 | x = 77 65 | try(check_value(x, "numeric scalar LE{z}")) 66 | #> Error: in check_value(x, "numeric scalar LE{z}"): 67 | #> Value 'x' must be a numeric scalar lower than, or equal to, 32. Problem: it is strictly greater than 32. 68 | ``` 69 | 70 | - `stop_up` now accepts the argument msg which is an extra message displayed right after the error message. 71 | 72 | # dreamerr 1.2.3 73 | 74 | #### Bug fixes 75 | 76 | - in `check_arg_plus` conversion of factors to characters now works properly. 77 | 78 | - Fix bug in `stop_up` when the argument `up` was not appropriately set by the user. 79 | 80 | - fix bug in `sfill` regarding the combined usage of `anchor` and `right` in special circumstances. 81 | 82 | #### New features 83 | 84 | - now `sfill` accepts 0-length vectors. 85 | 86 | - new exported function: `fit_screen`. 87 | 88 | 89 | # dreamerr 1.2.2 90 | 91 | #### Bug fixes 92 | 93 | - fix bugs in `sfill`: 94 | 95 | * when an anchor was provided and all characters before that were of the same length. 96 | 97 | * when an anchor was provided and the fill was from the right. 98 | 99 | #### User visible changes 100 | 101 | - `check_`family: objects are now returned invisibly. 102 | 103 | - new function `fsignif` which is an alias of `signif_plus`. 104 | 105 | # dreamerr 1.2.1 106 | 107 | #### Bug fixes 108 | 109 | - Bug when using commas or parentheses in arguments `.prefix` or `.argname` of `check_value`. 110 | - Bug in the error message in `check_value` when the argument could not be evaluated. 111 | - Bug introduced in the previous version, when checking types or equality with the option "no na" 112 | 113 | 114 | #### User visible changes 115 | 116 | - `validate_dots`: nicer messages. 117 | 118 | # dreamerr 1.2.0 119 | 120 | #### Important changes (no retro compatibility) 121 | 122 | - IMPORTANT CHANGE: Now by default, there is `NA` tolerance for the main classes `vector` and `matrix` (opposite to the previous behavior). The new keywords `NO NA` replace the former keywords `NA OK` for these classes. 123 | ``` 124 | test = function(x){ 125 | check_arg(x, "numeric vector") 126 | } 127 | # Before (version <= 1.1.0) 128 | test(c(5, NA)) # => Error 129 | # Now (version >= 1.2.0) 130 | test(c(5, NA)) # => is OK 131 | ``` 132 | 133 | - IMPORTANT CHANGE: values of 0 or 1 are not valid by default anymore when the `logical` type is requested. 134 | ``` 135 | test = function(x){ 136 | check_arg(x, "logical scalar") 137 | } 138 | # Before (version <= 1.1.0) 139 | test(0) # => is OK 140 | # Now (version >= 1.2.0) 141 | test(0) # => Error, must be logical 142 | ``` 143 | The new behavior is equivalent to the previous behavior when the type was `strict logical`. Now strict logical has been removed and `loose logical` has been introduced which accepts 0 and 1. Why this change? I remarked that when you allow arguments of very different types, one of which was a logical scalar, it was really useful to distinguish between them safely using `isTRUE` or `is.logical`. With the previous default behavior you could have a 0 or 1 that would prevent you from doing that. Of course you could use `strict logical` to trigger that behavior but it was non-intuitive. 144 | 145 | #### New features 146 | 147 | - In `check_value`: you can use the new argument `.prefix` to design the error message. 148 | 149 | - Function `check_value_plus` now returns the value of the element it has checked and possibly modified. 150 | ``` 151 | x = "t" 152 | y = check_value_plus(x, "match(This, Is, Raw)") 153 | y # => "This" 154 | fml = ~head(Petal.Length) 155 | z = check_value_plus(fml[[2]], "evalset numeric vector", .data = iris) 156 | z 157 | ``` 158 | 159 | - `sfill` now accepts NAs. 160 | 161 | #### Other changes 162 | 163 | - Error messages in `check_value` have been improved. 164 | 165 | - `enumerate_items` now returns the empty string when 0-length vectors are in input. 166 | 167 | #### Bug correction 168 | 169 | - The main class `match` could lead the argument to lose its attributes (like names), now corrected. 170 | 171 | - Vectors containing only NAs when NAs are tolerated could lead to a wrong error message, now corrected. 172 | 173 | - Bug when `check_value_plus` was called from the global environment and an error was triggered. 174 | 175 | - Bug when `check_value` was called and `.arg_name` was provided. 176 | 177 | - Bug when the "`...`" argument contained `NULL` values. 178 | 179 | - The developer mode now never applies to functions from packages using dreamerr 180 | 181 | - Behavior of argument `nmax` in `enumerate_items` is fixed. 182 | 183 | - Type conversion of matrices returned a vector, now corrected. 184 | 185 | 186 | # dreamerr 1.1.0 187 | 188 | #### New functions 189 | 190 | - `sfill`: formatting function for strings. Fills a character string up to the required length. Helps to form nice messages. 191 | 192 | - `set_up`: sets the argument `up` semi-globally (i.e. throughout all calls within a function). 193 | 194 | - `set_check`: turns on/off argument checking semi-globally (i.e. throughout all calls within a function). 195 | 196 | #### New features 197 | 198 | - When devising your own message (with argument `.message`), you can use the special character `__ARG__`. If found, it will be replaced by the appropriate argument name. 199 | 200 | #### User visible changes 201 | 202 | - Message informing no NA tolerance in the types is prompted only when the error comes from NA values. 203 | 204 | - The developer mode catches more errors and provide more suggestions. 205 | 206 | - `check_value` now doesn't throw an error for missing `.x`. 207 | 208 | #### Change in argument names 209 | 210 | - `.call_up` becomes `.up` -- retro-compatibility is NOT ensured. 211 | 212 | #### Bug correction 213 | 214 | - Small bug that could occur for the types `"integer scalar na ok"` with the argument equal to `NA`. 215 | 216 | - Important bug when using features requiring evaluations in the environment. Now the default environment is set up appropriately. 217 | 218 | - Bug when using `var(data,env)` in a `formula` class with missing `data`. 219 | 220 | - Very sneaky bug when badly forming a call to `check_arg` to check `...` in nested functions is now caught. 221 | 222 | - In `enumerate_items`, when there were many elements, `quote = TRUE` led to quote the `XX others` that shouldn't be quoted. Now corrected. 223 | 224 | - In the `formula` class, if a variable was passed as a `Formula` (notice the capital F), this caused an error if one-sidedness or two-sidedness were to be checked. 225 | 226 | - Bug when in `n_letter` when negative numbers are in. This bug propagated into `check_arg`. 227 | 228 | 229 | # dreamerr 1.0.0 230 | 231 | This package is the outcome of over a decade of coding and developing packages in R. As a package developer I always wanted my code to be "safe": so that if a user provides arguments of the good type the functions always work, and if there's an argument of the wrong type then an informative error message is shown. 232 | 233 | The big problem is that error handling is extremely time consuming, especially if you want to specify informative error messages stating clearly where the problem comes from. This problem is compounded when you want to offer the user flexible arguments that can be of many types. To do error handling properly in such situations is a nightmare: you end up with big if/else trees with a lot of different messages. And it doesn't improve the speed of your code! So you have little incentives to invest time in proper error handling. 234 | 235 | This is why I developed this function. It's one line of code, and it does all the work for you. From the developer side it's super simple, and from the user side, s/he ends up with extremely informative error messages therefore saving a lot of time in debugging. 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | -------------------------------------------------------------------------------- /R/dreamerr.R: -------------------------------------------------------------------------------- 1 | 2 | 3 | #' Error Handling Made Easy 4 | #' 5 | #' The main purpose of this package is twofold: i) to facilitate the developer's life, and ii) to provide to the users meaningful, useful error messages. These objectives are accomplished with a single function: \code{\link[dreamerr]{check_arg}}. That function checks the arguments given by the user: it offers a compact syntax such that complex arguments can be simply stated by the developer. In turn, if the user provides an argument of the wrong type then an informative error message will be buit, stating the expected type and where the error comes from--saving the user quite some time in debugging. 6 | #' 7 | #' Thus you can very easily make your package look professional with \code{\link[dreamerr]{check_arg}} (checking arguments properly \emph{is} professional). 8 | #' 9 | #' It also offers a set of small tools to provide informative messages to the users. See \code{\link[dreamerr]{stop_up}} and \code{\link[dreamerr:stop_up]{warn_up}} to throw errors and warnings in the appropriate location. There are many tools to form messages: \code{\link[dreamerr]{enumerate_items}} to form textual list of elements (with many options including conjugating verbs, etc...), \code{\link[dreamerr]{plural}} to conjugate verbs depending on the argument, and \code{\link[dreamerr:n_times]{n_letter}}, \code{\link[dreamerr:n_times]{n_th}}, \code{\link[dreamerr]{n_times}} to write integers in words (which usually looks nicer). 10 | #' 11 | #' To sum up in a few words, this package was created to enhance the user experience and facilitate package development. 12 | #' 13 | #' 14 | "_PACKAGE" 15 | -------------------------------------------------------------------------------- /R/onLoad.R: -------------------------------------------------------------------------------- 1 | 2 | 3 | # 4 | # compatibility 5 | # 6 | 7 | if(!exists("str2lang", asNamespace("base"))){ 8 | str2lang = function(x){ 9 | parse(text = x, keep.source = FALSE)[[1]] 10 | } 11 | } 12 | 13 | 14 | # 15 | # startup 16 | # 17 | 18 | 19 | .onLoad <- function(libname, pkgname){ 20 | # setting some options 21 | 22 | options("dreamerr_check" = TRUE) 23 | options("dreamerr_dev.mode" = FALSE) 24 | 25 | fix_pkgwdown_path() 26 | 27 | invisible() 28 | } 29 | 30 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | # dreamerr: Error Handling Made Easy 5 | 6 | CRAN status 7 | Version 8 | Downloads 9 | 10 | 11 | This package is addressed to developers or anyone writing functions (therefore almost everyone). 12 | 13 | It intends to increase R's user-friendliness and has two main objectives: 14 | 15 | 1. to provide to the developer a simple and intuitive, yet powerful and flexible, way to check the arguments passed to a function 16 | 2. to offer informative error messages to the user, in the case s/he passes arguments of the wrong type, stating clearly the problem, therefore saving their precious time in debugging 17 | 18 | These two goals can be achieved with a single line: `check_arg(arg_name, "expected type")`. 19 | 20 | This package aims to be the end of R's sometimes cryptic error messages, like the infamous 21 | 22 | ``` 23 | Error in xj[i] : invalid subscript type 'closure' 24 | ``` 25 | 26 | Below is a motivating example, for more details see the [introduction](https://CRAN.R-project.org/package=dreamerr/vignettes/dreamerr_introduction.html). 27 | 28 | ## Motivating example 29 | 30 | To illustrate the usefulness, let's rewrite the `lm()` function with some error handling and compare the results without/with error handling. In this simple example, we just add argument checking to the first two arguments of `lm`. 31 | 32 | ```r 33 | lm_check = function(formula, data){ 34 | 35 | # data: can be missing, if provided, it must be a data.frame or a list with names 36 | # (a data.frame is a named list, but the two types are added for clarity) 37 | check_arg(data, "data.frame | named list") 38 | 39 | # formula: 40 | # - must be a two-sided formula (ts) 41 | # - must be given by the user (mbt: must be there) 42 | # - the variables of the formula must be in the data set or in the environment (var(data, env)) 43 | check_arg(formula, "ts formula var(data, env) mbt", .data = data) 44 | 45 | # Now the call to lm 46 | lm(formula, data) 47 | } 48 | ``` 49 | 50 | As we can see each argument is checked with one line, and the types are rather explicit since natural language is used. 51 | 52 | Now let's compare the two functions. First without error handling (`lm`'s default): 53 | 54 | ```r 55 | # No argument 56 | lm() 57 | #> Error in terms.formula(formula, data = data) : 58 | #> argument is not a valid model 59 | 60 | # Problems in the formula 61 | lm(~Sepal.Width, iris) 62 | #> Error in lm.fit(x, y, offset = offset, singular.ok = singular.ok, ...) : 63 | #> incompatible dimensions 64 | 65 | lm(1+1, iris) 66 | #> Error in formula.default(object, env = baseenv()) : invalid formula 67 | 68 | lm(1+"a", iris) 69 | #> Error in 1 + "a" : non-numeric argument to binary operator 70 | 71 | lm(moien, iris) 72 | #> Error in stats::model.frame(formula = moien, data = iris, drop.unused.levels = TRUE) : 73 | #> object 'moien' not found 74 | 75 | # Problem in the data 76 | lm(Sepal.Length~Sepal.Width, pt) 77 | #> Error in as.data.frame.default(data, optional = TRUE) : 78 | #> cannot coerce class ‘"function"’ to a data.frame 79 | 80 | lm(Sepal.Length ~ Sepal.Width, 1:5) 81 | #> Error in eval(predvars, data, env) : 82 | #> numeric 'envir' arg not of length one 83 | 84 | # Mistake in the variable name 85 | lm(Sopal.Length~Sepal.Width, iris) 86 | #> Error in eval(predvars, data, env) : object 'Sopal.Length' not found 87 | 88 | ``` 89 | 90 | As we can see, the error messages are not really explicit. It's not easy to find: i) what the problem is, ii) which function really drives the error, iii) which argument is involved. It is therefore at best difficult, at worst impossible, to solve the problem from the error messages. 91 | 92 | Now with error handling: 93 | 94 | ```r 95 | # No argument 96 | lm_check() 97 | #> Error : in lm_check(): 98 | #> Argument 'formula' is required. Problem: it is missing. 99 | 100 | # Problems in the formula 101 | lm_check(~Sepal.Width, iris) 102 | #> Error : in lm_check(~Sepal.Width, iris): 103 | #> Argument 'formula' must be a two-sided formula. Problem: it is currently only one-sided. 104 | 105 | lm_check(1 + 1, iris) 106 | #> Error : in lm_check(1 + 1, iris): 107 | #> Argument 'formula' must be a two-sided formula. Problem: it is not a formula (instead it is a vector). 108 | 109 | lm_check(1 + "a", iris) 110 | #> Error : in lm_check(1 + "a", iris): 111 | #> Argument 'formula' (equal to '1 + "a"') could not be evaluated. Problem: non-numeric argument to binary operator. 112 | 113 | lm_check(moien, iris) 114 | #> Error : in lm_check(moien, iris): 115 | #> Argument 'formula' (equal to 'moien') could not be evaluated. Problem: object 'moien' not found. 116 | 117 | # Problem in the data 118 | lm_check(Sepal.Length ~ Sepal.Width, pt) 119 | #> Error : in lm_check(Sepal.Length ~ Sepal.Width, pt): 120 | #> Argument 'data' must be either: i) a data.frame, or ii) a named list. Problem: it is not a data.frame nor a list 121 | #> (instead it is a function). 122 | 123 | lm_check(Sepal.Length ~ Sepal.Width, 1:5) 124 | #> Error : in lm_check(Sepal.Length ~ Sepal.Width, 1:...: 125 | #> Argument 'data' must be either: i) a data.frame, or ii) a named list. Problem: it is not a data.frame nor a list 126 | #> (instead it is a vector). 127 | 128 | # Mistake in the variable name 129 | lm_check(Sopal.Length ~ Sepal.Width, iris) 130 | #> Error : in lm_check(Sopal.Length ~ Sepal.Width, iris): 131 | #> The argument 'formula' is a formula whose variables must be in the data set (given in argument 'data') or in the 132 | #> environment. Problem: the variable 'Sopal.Length' isn't there. 133 | 134 | ``` 135 | 136 | Now the error messages are explicit: we know where the problem comes from, the function `lm_check` is always shown as the root cause of the problem. The problematic argument is also explicitly mentioned. What the argument is expected to be is reminded and the mismatch with the actual argument is clearly mentioned after `Problem:`. Note that even nasty evaluation problems are caught. 137 | 138 | Debugging a call to `lm_check` is a piece of cake (especially compared to a direct call to `lm`): a lot of time is saved, the function looks a lot more user-friendly... with just two damn lines of code. 139 | 140 | 141 | 142 | ## A note on performance 143 | 144 | You may wonder: how much argument checking would slow down my code? Well, not much. Even not at all to be honest. 145 | 146 | Although the function `check_arg` supports literally over hundreds of different types, it has been highly optimized, meaning its performance cost is close to 0. Talking numbers, in a moderately slow computer (2.6GHz) it is in the ballpark of 20 micro seconds for missing arguments (i.e. not provided by the user) and of 70 micro seconds for simple checks of non-missing arguments. So you end up with a cost of 1s if you check 20K to 50K arguments, which seems reasonnably fast. 147 | 148 | In any case, the user can always set argument checking off with `setDreamerr_check(FALSE)`. So no reason not to make your functions user-friendly! 149 | 150 | -------------------------------------------------------------------------------- /docs/404.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | Page not found (404) • dreamerr 9 | 10 | 11 | 12 | 13 | 14 | 15 | 19 | 20 | 21 | 22 | 23 |
24 |
73 | 74 | 75 | 76 | 77 |
78 |
79 | 82 | 83 | Content not found. Please use links in the navbar. 84 | 85 |
86 | 87 | 91 | 92 |
93 | 94 | 95 | 96 | 107 |
108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | -------------------------------------------------------------------------------- /docs/articles/check_arg_call.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lrberge/dreamerr/ee0086ecfeafd932a2d8600511e67862e9c02c08/docs/articles/check_arg_call.png -------------------------------------------------------------------------------- /docs/articles/dreamerr_introduction_files/figure-html/unnamed-chunk-5-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lrberge/dreamerr/ee0086ecfeafd932a2d8600511e67862e9c02c08/docs/articles/dreamerr_introduction_files/figure-html/unnamed-chunk-5-1.png -------------------------------------------------------------------------------- /docs/articles/forming_a_type.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lrberge/dreamerr/ee0086ecfeafd932a2d8600511e67862e9c02c08/docs/articles/forming_a_type.png -------------------------------------------------------------------------------- /docs/articles/images/check_arg_call.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lrberge/dreamerr/ee0086ecfeafd932a2d8600511e67862e9c02c08/docs/articles/images/check_arg_call.png -------------------------------------------------------------------------------- /docs/articles/images/forming_a_type.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lrberge/dreamerr/ee0086ecfeafd932a2d8600511e67862e9c02c08/docs/articles/images/forming_a_type.png -------------------------------------------------------------------------------- /docs/articles/index.html: -------------------------------------------------------------------------------- 1 | 2 | Articles • dreamerr 6 | 7 | 8 |
9 |
50 | 51 | 52 | 53 |
54 |
55 | 58 | 59 |
60 |

All vignettes

61 |

62 | 63 |
dreamerr: Error Handling Made Easy
64 |
65 |
66 |
67 |
68 | 69 | 70 |
79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | -------------------------------------------------------------------------------- /docs/authors.html: -------------------------------------------------------------------------------- 1 | 2 | Authors and Citation • dreamerr 6 | 7 | 8 |
9 |
50 | 51 | 52 | 53 |
54 |
55 |
56 | 59 | 60 | 61 |
  • 62 |

    Laurent Berge. Author, maintainer. 63 |

    64 |
  • 65 |
66 |
67 |
68 |

Citation

69 | Source: DESCRIPTION 70 |
71 |
72 | 73 | 74 |

Berge L (2024). 75 | dreamerr: Error Handling Made Easy. 76 | R package version 1.5.0. 77 |

78 |
@Manual{,
 79 |   title = {dreamerr: Error Handling Made Easy},
 80 |   author = {Laurent Berge},
 81 |   year = {2024},
 82 |   note = {R package version 1.5.0},
 83 | }
84 | 85 |
86 | 87 |
88 | 89 | 90 | 91 |
100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | -------------------------------------------------------------------------------- /docs/bootstrap-toc.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Bootstrap Table of Contents v0.4.1 (http://afeld.github.io/bootstrap-toc/) 3 | * Copyright 2015 Aidan Feldman 4 | * Licensed under MIT (https://github.com/afeld/bootstrap-toc/blob/gh-pages/LICENSE.md) */ 5 | 6 | /* modified from https://github.com/twbs/bootstrap/blob/94b4076dd2efba9af71f0b18d4ee4b163aa9e0dd/docs/assets/css/src/docs.css#L548-L601 */ 7 | 8 | /* All levels of nav */ 9 | nav[data-toggle='toc'] .nav > li > a { 10 | display: block; 11 | padding: 4px 20px; 12 | font-size: 13px; 13 | font-weight: 500; 14 | color: #767676; 15 | } 16 | nav[data-toggle='toc'] .nav > li > a:hover, 17 | nav[data-toggle='toc'] .nav > li > a:focus { 18 | padding-left: 19px; 19 | color: #563d7c; 20 | text-decoration: none; 21 | background-color: transparent; 22 | border-left: 1px solid #563d7c; 23 | } 24 | nav[data-toggle='toc'] .nav > .active > a, 25 | nav[data-toggle='toc'] .nav > .active:hover > a, 26 | nav[data-toggle='toc'] .nav > .active:focus > a { 27 | padding-left: 18px; 28 | font-weight: bold; 29 | color: #563d7c; 30 | background-color: transparent; 31 | border-left: 2px solid #563d7c; 32 | } 33 | 34 | /* Nav: second level (shown on .active) */ 35 | nav[data-toggle='toc'] .nav .nav { 36 | display: none; /* Hide by default, but at >768px, show it */ 37 | padding-bottom: 10px; 38 | } 39 | nav[data-toggle='toc'] .nav .nav > li > a { 40 | padding-top: 1px; 41 | padding-bottom: 1px; 42 | padding-left: 30px; 43 | font-size: 12px; 44 | font-weight: normal; 45 | } 46 | nav[data-toggle='toc'] .nav .nav > li > a:hover, 47 | nav[data-toggle='toc'] .nav .nav > li > a:focus { 48 | padding-left: 29px; 49 | } 50 | nav[data-toggle='toc'] .nav .nav > .active > a, 51 | nav[data-toggle='toc'] .nav .nav > .active:hover > a, 52 | nav[data-toggle='toc'] .nav .nav > .active:focus > a { 53 | padding-left: 28px; 54 | font-weight: 500; 55 | } 56 | 57 | /* from https://github.com/twbs/bootstrap/blob/e38f066d8c203c3e032da0ff23cd2d6098ee2dd6/docs/assets/css/src/docs.css#L631-L634 */ 58 | nav[data-toggle='toc'] .nav > .active > ul { 59 | display: block; 60 | } 61 | -------------------------------------------------------------------------------- /docs/bootstrap-toc.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * Bootstrap Table of Contents v0.4.1 (http://afeld.github.io/bootstrap-toc/) 3 | * Copyright 2015 Aidan Feldman 4 | * Licensed under MIT (https://github.com/afeld/bootstrap-toc/blob/gh-pages/LICENSE.md) */ 5 | (function() { 6 | 'use strict'; 7 | 8 | window.Toc = { 9 | helpers: { 10 | // return all matching elements in the set, or their descendants 11 | findOrFilter: function($el, selector) { 12 | // http://danielnouri.org/notes/2011/03/14/a-jquery-find-that-also-finds-the-root-element/ 13 | // http://stackoverflow.com/a/12731439/358804 14 | var $descendants = $el.find(selector); 15 | return $el.filter(selector).add($descendants).filter(':not([data-toc-skip])'); 16 | }, 17 | 18 | generateUniqueIdBase: function(el) { 19 | var text = $(el).text(); 20 | var anchor = text.trim().toLowerCase().replace(/[^A-Za-z0-9]+/g, '-'); 21 | return anchor || el.tagName.toLowerCase(); 22 | }, 23 | 24 | generateUniqueId: function(el) { 25 | var anchorBase = this.generateUniqueIdBase(el); 26 | for (var i = 0; ; i++) { 27 | var anchor = anchorBase; 28 | if (i > 0) { 29 | // add suffix 30 | anchor += '-' + i; 31 | } 32 | // check if ID already exists 33 | if (!document.getElementById(anchor)) { 34 | return anchor; 35 | } 36 | } 37 | }, 38 | 39 | generateAnchor: function(el) { 40 | if (el.id) { 41 | return el.id; 42 | } else { 43 | var anchor = this.generateUniqueId(el); 44 | el.id = anchor; 45 | return anchor; 46 | } 47 | }, 48 | 49 | createNavList: function() { 50 | return $(''); 51 | }, 52 | 53 | createChildNavList: function($parent) { 54 | var $childList = this.createNavList(); 55 | $parent.append($childList); 56 | return $childList; 57 | }, 58 | 59 | generateNavEl: function(anchor, text) { 60 | var $a = $(''); 61 | $a.attr('href', '#' + anchor); 62 | $a.text(text); 63 | var $li = $('
  • '); 64 | $li.append($a); 65 | return $li; 66 | }, 67 | 68 | generateNavItem: function(headingEl) { 69 | var anchor = this.generateAnchor(headingEl); 70 | var $heading = $(headingEl); 71 | var text = $heading.data('toc-text') || $heading.text(); 72 | return this.generateNavEl(anchor, text); 73 | }, 74 | 75 | // Find the first heading level (`

    `, then `

    `, etc.) that has more than one element. Defaults to 1 (for `

    `). 76 | getTopLevel: function($scope) { 77 | for (var i = 1; i <= 6; i++) { 78 | var $headings = this.findOrFilter($scope, 'h' + i); 79 | if ($headings.length > 1) { 80 | return i; 81 | } 82 | } 83 | 84 | return 1; 85 | }, 86 | 87 | // returns the elements for the top level, and the next below it 88 | getHeadings: function($scope, topLevel) { 89 | var topSelector = 'h' + topLevel; 90 | 91 | var secondaryLevel = topLevel + 1; 92 | var secondarySelector = 'h' + secondaryLevel; 93 | 94 | return this.findOrFilter($scope, topSelector + ',' + secondarySelector); 95 | }, 96 | 97 | getNavLevel: function(el) { 98 | return parseInt(el.tagName.charAt(1), 10); 99 | }, 100 | 101 | populateNav: function($topContext, topLevel, $headings) { 102 | var $context = $topContext; 103 | var $prevNav; 104 | 105 | var helpers = this; 106 | $headings.each(function(i, el) { 107 | var $newNav = helpers.generateNavItem(el); 108 | var navLevel = helpers.getNavLevel(el); 109 | 110 | // determine the proper $context 111 | if (navLevel === topLevel) { 112 | // use top level 113 | $context = $topContext; 114 | } else if ($prevNav && $context === $topContext) { 115 | // create a new level of the tree and switch to it 116 | $context = helpers.createChildNavList($prevNav); 117 | } // else use the current $context 118 | 119 | $context.append($newNav); 120 | 121 | $prevNav = $newNav; 122 | }); 123 | }, 124 | 125 | parseOps: function(arg) { 126 | var opts; 127 | if (arg.jquery) { 128 | opts = { 129 | $nav: arg 130 | }; 131 | } else { 132 | opts = arg; 133 | } 134 | opts.$scope = opts.$scope || $(document.body); 135 | return opts; 136 | } 137 | }, 138 | 139 | // accepts a jQuery object, or an options object 140 | init: function(opts) { 141 | opts = this.helpers.parseOps(opts); 142 | 143 | // ensure that the data attribute is in place for styling 144 | opts.$nav.attr('data-toggle', 'toc'); 145 | 146 | var $topContext = this.helpers.createChildNavList(opts.$nav); 147 | var topLevel = this.helpers.getTopLevel(opts.$scope); 148 | var $headings = this.helpers.getHeadings(opts.$scope, topLevel); 149 | this.helpers.populateNav($topContext, topLevel, $headings); 150 | } 151 | }; 152 | 153 | $(function() { 154 | $('nav[data-toggle="toc"]').each(function(i, el) { 155 | var $nav = $(el); 156 | Toc.init($nav); 157 | }); 158 | }); 159 | })(); 160 | -------------------------------------------------------------------------------- /docs/docsearch.css: -------------------------------------------------------------------------------- 1 | /* Docsearch -------------------------------------------------------------- */ 2 | /* 3 | Source: https://github.com/algolia/docsearch/ 4 | License: MIT 5 | */ 6 | 7 | .algolia-autocomplete { 8 | display: block; 9 | -webkit-box-flex: 1; 10 | -ms-flex: 1; 11 | flex: 1 12 | } 13 | 14 | .algolia-autocomplete .ds-dropdown-menu { 15 | width: 100%; 16 | min-width: none; 17 | max-width: none; 18 | padding: .75rem 0; 19 | background-color: #fff; 20 | background-clip: padding-box; 21 | border: 1px solid rgba(0, 0, 0, .1); 22 | box-shadow: 0 .5rem 1rem rgba(0, 0, 0, .175); 23 | } 24 | 25 | @media (min-width:768px) { 26 | .algolia-autocomplete .ds-dropdown-menu { 27 | width: 175% 28 | } 29 | } 30 | 31 | .algolia-autocomplete .ds-dropdown-menu::before { 32 | display: none 33 | } 34 | 35 | .algolia-autocomplete .ds-dropdown-menu [class^=ds-dataset-] { 36 | padding: 0; 37 | background-color: rgb(255,255,255); 38 | border: 0; 39 | max-height: 80vh; 40 | } 41 | 42 | .algolia-autocomplete .ds-dropdown-menu .ds-suggestions { 43 | margin-top: 0 44 | } 45 | 46 | .algolia-autocomplete .algolia-docsearch-suggestion { 47 | padding: 0; 48 | overflow: visible 49 | } 50 | 51 | .algolia-autocomplete .algolia-docsearch-suggestion--category-header { 52 | padding: .125rem 1rem; 53 | margin-top: 0; 54 | font-size: 1.3em; 55 | font-weight: 500; 56 | color: #00008B; 57 | border-bottom: 0 58 | } 59 | 60 | .algolia-autocomplete .algolia-docsearch-suggestion--wrapper { 61 | float: none; 62 | padding-top: 0 63 | } 64 | 65 | .algolia-autocomplete .algolia-docsearch-suggestion--subcategory-column { 66 | float: none; 67 | width: auto; 68 | padding: 0; 69 | text-align: left 70 | } 71 | 72 | .algolia-autocomplete .algolia-docsearch-suggestion--content { 73 | float: none; 74 | width: auto; 75 | padding: 0 76 | } 77 | 78 | .algolia-autocomplete .algolia-docsearch-suggestion--content::before { 79 | display: none 80 | } 81 | 82 | .algolia-autocomplete .ds-suggestion:not(:first-child) .algolia-docsearch-suggestion--category-header { 83 | padding-top: .75rem; 84 | margin-top: .75rem; 85 | border-top: 1px solid rgba(0, 0, 0, .1) 86 | } 87 | 88 | .algolia-autocomplete .ds-suggestion .algolia-docsearch-suggestion--subcategory-column { 89 | display: block; 90 | padding: .1rem 1rem; 91 | margin-bottom: 0.1; 92 | font-size: 1.0em; 93 | font-weight: 400 94 | /* display: none */ 95 | } 96 | 97 | .algolia-autocomplete .algolia-docsearch-suggestion--title { 98 | display: block; 99 | padding: .25rem 1rem; 100 | margin-bottom: 0; 101 | font-size: 0.9em; 102 | font-weight: 400 103 | } 104 | 105 | .algolia-autocomplete .algolia-docsearch-suggestion--text { 106 | padding: 0 1rem .5rem; 107 | margin-top: -.25rem; 108 | font-size: 0.8em; 109 | font-weight: 400; 110 | line-height: 1.25 111 | } 112 | 113 | .algolia-autocomplete .algolia-docsearch-footer { 114 | width: 110px; 115 | height: 20px; 116 | z-index: 3; 117 | margin-top: 10.66667px; 118 | float: right; 119 | font-size: 0; 120 | line-height: 0; 121 | } 122 | 123 | .algolia-autocomplete .algolia-docsearch-footer--logo { 124 | background-image: url("data:image/svg+xml;utf8,"); 125 | background-repeat: no-repeat; 126 | background-position: 50%; 127 | background-size: 100%; 128 | overflow: hidden; 129 | text-indent: -9000px; 130 | width: 100%; 131 | height: 100%; 132 | display: block; 133 | transform: translate(-8px); 134 | } 135 | 136 | .algolia-autocomplete .algolia-docsearch-suggestion--highlight { 137 | color: #FF8C00; 138 | background: rgba(232, 189, 54, 0.1) 139 | } 140 | 141 | 142 | .algolia-autocomplete .algolia-docsearch-suggestion--text .algolia-docsearch-suggestion--highlight { 143 | box-shadow: inset 0 -2px 0 0 rgba(105, 105, 105, .5) 144 | } 145 | 146 | .algolia-autocomplete .ds-suggestion.ds-cursor .algolia-docsearch-suggestion--content { 147 | background-color: rgba(192, 192, 192, .15) 148 | } 149 | -------------------------------------------------------------------------------- /docs/docsearch.js: -------------------------------------------------------------------------------- 1 | $(function() { 2 | 3 | // register a handler to move the focus to the search bar 4 | // upon pressing shift + "/" (i.e. "?") 5 | $(document).on('keydown', function(e) { 6 | if (e.shiftKey && e.keyCode == 191) { 7 | e.preventDefault(); 8 | $("#search-input").focus(); 9 | } 10 | }); 11 | 12 | $(document).ready(function() { 13 | // do keyword highlighting 14 | /* modified from https://jsfiddle.net/julmot/bL6bb5oo/ */ 15 | var mark = function() { 16 | 17 | var referrer = document.URL ; 18 | var paramKey = "q" ; 19 | 20 | if (referrer.indexOf("?") !== -1) { 21 | var qs = referrer.substr(referrer.indexOf('?') + 1); 22 | var qs_noanchor = qs.split('#')[0]; 23 | var qsa = qs_noanchor.split('&'); 24 | var keyword = ""; 25 | 26 | for (var i = 0; i < qsa.length; i++) { 27 | var currentParam = qsa[i].split('='); 28 | 29 | if (currentParam.length !== 2) { 30 | continue; 31 | } 32 | 33 | if (currentParam[0] == paramKey) { 34 | keyword = decodeURIComponent(currentParam[1].replace(/\+/g, "%20")); 35 | } 36 | } 37 | 38 | if (keyword !== "") { 39 | $(".contents").unmark({ 40 | done: function() { 41 | $(".contents").mark(keyword); 42 | } 43 | }); 44 | } 45 | } 46 | }; 47 | 48 | mark(); 49 | }); 50 | }); 51 | 52 | /* Search term highlighting ------------------------------*/ 53 | 54 | function matchedWords(hit) { 55 | var words = []; 56 | 57 | var hierarchy = hit._highlightResult.hierarchy; 58 | // loop to fetch from lvl0, lvl1, etc. 59 | for (var idx in hierarchy) { 60 | words = words.concat(hierarchy[idx].matchedWords); 61 | } 62 | 63 | var content = hit._highlightResult.content; 64 | if (content) { 65 | words = words.concat(content.matchedWords); 66 | } 67 | 68 | // return unique words 69 | var words_uniq = [...new Set(words)]; 70 | return words_uniq; 71 | } 72 | 73 | function updateHitURL(hit) { 74 | 75 | var words = matchedWords(hit); 76 | var url = ""; 77 | 78 | if (hit.anchor) { 79 | url = hit.url_without_anchor + '?q=' + escape(words.join(" ")) + '#' + hit.anchor; 80 | } else { 81 | url = hit.url + '?q=' + escape(words.join(" ")); 82 | } 83 | 84 | return url; 85 | } 86 | -------------------------------------------------------------------------------- /docs/link.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 8 | 12 | 13 | -------------------------------------------------------------------------------- /docs/pkgdown.css: -------------------------------------------------------------------------------- 1 | /* Sticky footer */ 2 | 3 | /** 4 | * Basic idea: https://philipwalton.github.io/solved-by-flexbox/demos/sticky-footer/ 5 | * Details: https://github.com/philipwalton/solved-by-flexbox/blob/master/assets/css/components/site.css 6 | * 7 | * .Site -> body > .container 8 | * .Site-content -> body > .container .row 9 | * .footer -> footer 10 | * 11 | * Key idea seems to be to ensure that .container and __all its parents__ 12 | * have height set to 100% 13 | * 14 | */ 15 | 16 | html, body { 17 | height: 100%; 18 | } 19 | 20 | body { 21 | position: relative; 22 | } 23 | 24 | body > .container { 25 | display: flex; 26 | height: 100%; 27 | flex-direction: column; 28 | } 29 | 30 | body > .container .row { 31 | flex: 1 0 auto; 32 | } 33 | 34 | footer { 35 | margin-top: 45px; 36 | padding: 35px 0 36px; 37 | border-top: 1px solid #e5e5e5; 38 | color: #666; 39 | display: flex; 40 | flex-shrink: 0; 41 | } 42 | footer p { 43 | margin-bottom: 0; 44 | } 45 | footer div { 46 | flex: 1; 47 | } 48 | footer .pkgdown { 49 | text-align: right; 50 | } 51 | footer p { 52 | margin-bottom: 0; 53 | } 54 | 55 | img.icon { 56 | float: right; 57 | } 58 | 59 | /* Ensure in-page images don't run outside their container */ 60 | .contents img { 61 | max-width: 100%; 62 | height: auto; 63 | } 64 | 65 | /* Fix bug in bootstrap (only seen in firefox) */ 66 | summary { 67 | display: list-item; 68 | } 69 | 70 | /* Typographic tweaking ---------------------------------*/ 71 | 72 | .contents .page-header { 73 | margin-top: calc(-60px + 1em); 74 | } 75 | 76 | dd { 77 | margin-left: 3em; 78 | } 79 | 80 | /* Section anchors ---------------------------------*/ 81 | 82 | a.anchor { 83 | display: none; 84 | margin-left: 5px; 85 | width: 20px; 86 | height: 20px; 87 | 88 | background-image: url(./link.svg); 89 | background-repeat: no-repeat; 90 | background-size: 20px 20px; 91 | background-position: center center; 92 | } 93 | 94 | h1:hover .anchor, 95 | h2:hover .anchor, 96 | h3:hover .anchor, 97 | h4:hover .anchor, 98 | h5:hover .anchor, 99 | h6:hover .anchor { 100 | display: inline-block; 101 | } 102 | 103 | /* Fixes for fixed navbar --------------------------*/ 104 | 105 | .contents h1, .contents h2, .contents h3, .contents h4 { 106 | padding-top: 60px; 107 | margin-top: -40px; 108 | } 109 | 110 | /* Navbar submenu --------------------------*/ 111 | 112 | .dropdown-submenu { 113 | position: relative; 114 | } 115 | 116 | .dropdown-submenu>.dropdown-menu { 117 | top: 0; 118 | left: 100%; 119 | margin-top: -6px; 120 | margin-left: -1px; 121 | border-radius: 0 6px 6px 6px; 122 | } 123 | 124 | .dropdown-submenu:hover>.dropdown-menu { 125 | display: block; 126 | } 127 | 128 | .dropdown-submenu>a:after { 129 | display: block; 130 | content: " "; 131 | float: right; 132 | width: 0; 133 | height: 0; 134 | border-color: transparent; 135 | border-style: solid; 136 | border-width: 5px 0 5px 5px; 137 | border-left-color: #cccccc; 138 | margin-top: 5px; 139 | margin-right: -10px; 140 | } 141 | 142 | .dropdown-submenu:hover>a:after { 143 | border-left-color: #ffffff; 144 | } 145 | 146 | .dropdown-submenu.pull-left { 147 | float: none; 148 | } 149 | 150 | .dropdown-submenu.pull-left>.dropdown-menu { 151 | left: -100%; 152 | margin-left: 10px; 153 | border-radius: 6px 0 6px 6px; 154 | } 155 | 156 | /* Sidebar --------------------------*/ 157 | 158 | #pkgdown-sidebar { 159 | margin-top: 30px; 160 | position: -webkit-sticky; 161 | position: sticky; 162 | top: 70px; 163 | } 164 | 165 | #pkgdown-sidebar h2 { 166 | font-size: 1.5em; 167 | margin-top: 1em; 168 | } 169 | 170 | #pkgdown-sidebar h2:first-child { 171 | margin-top: 0; 172 | } 173 | 174 | #pkgdown-sidebar .list-unstyled li { 175 | margin-bottom: 0.5em; 176 | } 177 | 178 | /* bootstrap-toc tweaks ------------------------------------------------------*/ 179 | 180 | /* All levels of nav */ 181 | 182 | nav[data-toggle='toc'] .nav > li > a { 183 | padding: 4px 20px 4px 6px; 184 | font-size: 1.5rem; 185 | font-weight: 400; 186 | color: inherit; 187 | } 188 | 189 | nav[data-toggle='toc'] .nav > li > a:hover, 190 | nav[data-toggle='toc'] .nav > li > a:focus { 191 | padding-left: 5px; 192 | color: inherit; 193 | border-left: 1px solid #878787; 194 | } 195 | 196 | nav[data-toggle='toc'] .nav > .active > a, 197 | nav[data-toggle='toc'] .nav > .active:hover > a, 198 | nav[data-toggle='toc'] .nav > .active:focus > a { 199 | padding-left: 5px; 200 | font-size: 1.5rem; 201 | font-weight: 400; 202 | color: inherit; 203 | border-left: 2px solid #878787; 204 | } 205 | 206 | /* Nav: second level (shown on .active) */ 207 | 208 | nav[data-toggle='toc'] .nav .nav { 209 | display: none; /* Hide by default, but at >768px, show it */ 210 | padding-bottom: 10px; 211 | } 212 | 213 | nav[data-toggle='toc'] .nav .nav > li > a { 214 | padding-left: 16px; 215 | font-size: 1.35rem; 216 | } 217 | 218 | nav[data-toggle='toc'] .nav .nav > li > a:hover, 219 | nav[data-toggle='toc'] .nav .nav > li > a:focus { 220 | padding-left: 15px; 221 | } 222 | 223 | nav[data-toggle='toc'] .nav .nav > .active > a, 224 | nav[data-toggle='toc'] .nav .nav > .active:hover > a, 225 | nav[data-toggle='toc'] .nav .nav > .active:focus > a { 226 | padding-left: 15px; 227 | font-weight: 500; 228 | font-size: 1.35rem; 229 | } 230 | 231 | /* orcid ------------------------------------------------------------------- */ 232 | 233 | .orcid { 234 | font-size: 16px; 235 | color: #A6CE39; 236 | /* margins are required by official ORCID trademark and display guidelines */ 237 | margin-left:4px; 238 | margin-right:4px; 239 | vertical-align: middle; 240 | } 241 | 242 | /* Reference index & topics ----------------------------------------------- */ 243 | 244 | .ref-index th {font-weight: normal;} 245 | 246 | .ref-index td {vertical-align: top; min-width: 100px} 247 | .ref-index .icon {width: 40px;} 248 | .ref-index .alias {width: 40%;} 249 | .ref-index-icons .alias {width: calc(40% - 40px);} 250 | .ref-index .title {width: 60%;} 251 | 252 | .ref-arguments th {text-align: right; padding-right: 10px;} 253 | .ref-arguments th, .ref-arguments td {vertical-align: top; min-width: 100px} 254 | .ref-arguments .name {width: 20%;} 255 | .ref-arguments .desc {width: 80%;} 256 | 257 | /* Nice scrolling for wide elements --------------------------------------- */ 258 | 259 | table { 260 | display: block; 261 | overflow: auto; 262 | } 263 | 264 | /* Syntax highlighting ---------------------------------------------------- */ 265 | 266 | pre, code, pre code { 267 | background-color: #f8f8f8; 268 | color: #333; 269 | } 270 | pre, pre code { 271 | white-space: pre-wrap; 272 | word-break: break-all; 273 | overflow-wrap: break-word; 274 | } 275 | 276 | pre { 277 | border: 1px solid #eee; 278 | } 279 | 280 | pre .img, pre .r-plt { 281 | margin: 5px 0; 282 | } 283 | 284 | pre .img img, pre .r-plt img { 285 | background-color: #fff; 286 | } 287 | 288 | code a, pre a { 289 | color: #375f84; 290 | } 291 | 292 | a.sourceLine:hover { 293 | text-decoration: none; 294 | } 295 | 296 | .fl {color: #1514b5;} 297 | .fu {color: #000000;} /* function */ 298 | .ch,.st {color: #036a07;} /* string */ 299 | .kw {color: #264D66;} /* keyword */ 300 | .co {color: #888888;} /* comment */ 301 | 302 | .error {font-weight: bolder;} 303 | .warning {font-weight: bolder;} 304 | 305 | /* Clipboard --------------------------*/ 306 | 307 | .hasCopyButton { 308 | position: relative; 309 | } 310 | 311 | .btn-copy-ex { 312 | position: absolute; 313 | right: 0; 314 | top: 0; 315 | visibility: hidden; 316 | } 317 | 318 | .hasCopyButton:hover button.btn-copy-ex { 319 | visibility: visible; 320 | } 321 | 322 | /* headroom.js ------------------------ */ 323 | 324 | .headroom { 325 | will-change: transform; 326 | transition: transform 200ms linear; 327 | } 328 | .headroom--pinned { 329 | transform: translateY(0%); 330 | } 331 | .headroom--unpinned { 332 | transform: translateY(-100%); 333 | } 334 | 335 | /* mark.js ----------------------------*/ 336 | 337 | mark { 338 | background-color: rgba(255, 255, 51, 0.5); 339 | border-bottom: 2px solid rgba(255, 153, 51, 0.3); 340 | padding: 1px; 341 | } 342 | 343 | /* vertical spacing after htmlwidgets */ 344 | .html-widget { 345 | margin-bottom: 10px; 346 | } 347 | 348 | /* fontawesome ------------------------ */ 349 | 350 | .fab { 351 | font-family: "Font Awesome 5 Brands" !important; 352 | } 353 | 354 | /* don't display links in code chunks when printing */ 355 | /* source: https://stackoverflow.com/a/10781533 */ 356 | @media print { 357 | code a:link:after, code a:visited:after { 358 | content: ""; 359 | } 360 | } 361 | 362 | /* Section anchors --------------------------------- 363 | Added in pandoc 2.11: https://github.com/jgm/pandoc-templates/commit/9904bf71 364 | */ 365 | 366 | div.csl-bib-body { } 367 | div.csl-entry { 368 | clear: both; 369 | } 370 | .hanging-indent div.csl-entry { 371 | margin-left:2em; 372 | text-indent:-2em; 373 | } 374 | div.csl-left-margin { 375 | min-width:2em; 376 | float:left; 377 | } 378 | div.csl-right-inline { 379 | margin-left:2em; 380 | padding-left:1em; 381 | } 382 | div.csl-indent { 383 | margin-left: 2em; 384 | } 385 | -------------------------------------------------------------------------------- /docs/pkgdown.js: -------------------------------------------------------------------------------- 1 | /* http://gregfranko.com/blog/jquery-best-practices/ */ 2 | (function($) { 3 | $(function() { 4 | 5 | $('.navbar-fixed-top').headroom(); 6 | 7 | $('body').css('padding-top', $('.navbar').height() + 10); 8 | $(window).resize(function(){ 9 | $('body').css('padding-top', $('.navbar').height() + 10); 10 | }); 11 | 12 | $('[data-toggle="tooltip"]').tooltip(); 13 | 14 | var cur_path = paths(location.pathname); 15 | var links = $("#navbar ul li a"); 16 | var max_length = -1; 17 | var pos = -1; 18 | for (var i = 0; i < links.length; i++) { 19 | if (links[i].getAttribute("href") === "#") 20 | continue; 21 | // Ignore external links 22 | if (links[i].host !== location.host) 23 | continue; 24 | 25 | var nav_path = paths(links[i].pathname); 26 | 27 | var length = prefix_length(nav_path, cur_path); 28 | if (length > max_length) { 29 | max_length = length; 30 | pos = i; 31 | } 32 | } 33 | 34 | // Add class to parent
  • , and enclosing
  • if in dropdown 35 | if (pos >= 0) { 36 | var menu_anchor = $(links[pos]); 37 | menu_anchor.parent().addClass("active"); 38 | menu_anchor.closest("li.dropdown").addClass("active"); 39 | } 40 | }); 41 | 42 | function paths(pathname) { 43 | var pieces = pathname.split("/"); 44 | pieces.shift(); // always starts with / 45 | 46 | var end = pieces[pieces.length - 1]; 47 | if (end === "index.html" || end === "") 48 | pieces.pop(); 49 | return(pieces); 50 | } 51 | 52 | // Returns -1 if not found 53 | function prefix_length(needle, haystack) { 54 | if (needle.length > haystack.length) 55 | return(-1); 56 | 57 | // Special case for length-0 haystack, since for loop won't run 58 | if (haystack.length === 0) { 59 | return(needle.length === 0 ? 0 : -1); 60 | } 61 | 62 | for (var i = 0; i < haystack.length; i++) { 63 | if (needle[i] != haystack[i]) 64 | return(i); 65 | } 66 | 67 | return(haystack.length); 68 | } 69 | 70 | /* Clipboard --------------------------*/ 71 | 72 | function changeTooltipMessage(element, msg) { 73 | var tooltipOriginalTitle=element.getAttribute('data-original-title'); 74 | element.setAttribute('data-original-title', msg); 75 | $(element).tooltip('show'); 76 | element.setAttribute('data-original-title', tooltipOriginalTitle); 77 | } 78 | 79 | if(ClipboardJS.isSupported()) { 80 | $(document).ready(function() { 81 | var copyButton = ""; 82 | 83 | $("div.sourceCode").addClass("hasCopyButton"); 84 | 85 | // Insert copy buttons: 86 | $(copyButton).prependTo(".hasCopyButton"); 87 | 88 | // Initialize tooltips: 89 | $('.btn-copy-ex').tooltip({container: 'body'}); 90 | 91 | // Initialize clipboard: 92 | var clipboardBtnCopies = new ClipboardJS('[data-clipboard-copy]', { 93 | text: function(trigger) { 94 | return trigger.parentNode.textContent.replace(/\n#>[^\n]*/g, ""); 95 | } 96 | }); 97 | 98 | clipboardBtnCopies.on('success', function(e) { 99 | changeTooltipMessage(e.trigger, 'Copied!'); 100 | e.clearSelection(); 101 | }); 102 | 103 | clipboardBtnCopies.on('error', function() { 104 | changeTooltipMessage(e.trigger,'Press Ctrl+C or Command+C to copy'); 105 | }); 106 | }); 107 | } 108 | })(window.jQuery || window.$) 109 | -------------------------------------------------------------------------------- /docs/pkgdown.yml: -------------------------------------------------------------------------------- 1 | pandoc: 3.1.3 2 | pkgdown: 2.0.7 3 | pkgdown_sha: ~ 4 | articles: 5 | dreamerr_introduction: dreamerr_introduction.html 6 | last_built: 2024-07-05T13:50Z 7 | 8 | -------------------------------------------------------------------------------- /docs/reference/Rplot001.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lrberge/dreamerr/ee0086ecfeafd932a2d8600511e67862e9c02c08/docs/reference/Rplot001.png -------------------------------------------------------------------------------- /docs/reference/Rplot002.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lrberge/dreamerr/ee0086ecfeafd932a2d8600511e67862e9c02c08/docs/reference/Rplot002.png -------------------------------------------------------------------------------- /docs/reference/Rplot003.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lrberge/dreamerr/ee0086ecfeafd932a2d8600511e67862e9c02c08/docs/reference/Rplot003.png -------------------------------------------------------------------------------- /docs/reference/Rplot004.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lrberge/dreamerr/ee0086ecfeafd932a2d8600511e67862e9c02c08/docs/reference/Rplot004.png -------------------------------------------------------------------------------- /docs/reference/Rplot005.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lrberge/dreamerr/ee0086ecfeafd932a2d8600511e67862e9c02c08/docs/reference/Rplot005.png -------------------------------------------------------------------------------- /docs/reference/check_arg-1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lrberge/dreamerr/ee0086ecfeafd932a2d8600511e67862e9c02c08/docs/reference/check_arg-1.png -------------------------------------------------------------------------------- /docs/reference/check_arg-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lrberge/dreamerr/ee0086ecfeafd932a2d8600511e67862e9c02c08/docs/reference/check_arg-2.png -------------------------------------------------------------------------------- /docs/reference/check_arg-3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lrberge/dreamerr/ee0086ecfeafd932a2d8600511e67862e9c02c08/docs/reference/check_arg-3.png -------------------------------------------------------------------------------- /docs/reference/check_arg-4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lrberge/dreamerr/ee0086ecfeafd932a2d8600511e67862e9c02c08/docs/reference/check_arg-4.png -------------------------------------------------------------------------------- /docs/reference/check_arg-5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lrberge/dreamerr/ee0086ecfeafd932a2d8600511e67862e9c02c08/docs/reference/check_arg-5.png -------------------------------------------------------------------------------- /docs/reference/check_expr.html: -------------------------------------------------------------------------------- 1 | 2 | Checks the evaluation of an expression — check_expr • dreamerr 7 | 8 | 9 |
    10 |
    51 | 52 | 53 | 54 |
    55 |
    56 | 61 | 62 |
    63 |

    This functions checks the evaluation of an expression and, if an error is thrown, 64 | captures it and integrates the captured message after a custom error message.

    65 |
    66 | 67 |
    68 |
    check_expr(expr, ..., clean, up = 0, arg_name, verbatim = FALSE)
     69 | 
     70 | check_expr_hook(expr, ..., clean, arg_name, verbatim = FALSE)
     71 | 
     72 | generate_check_expr_hook(namespace)
    73 |
    74 | 75 |
    76 |

    Arguments

    77 |
    expr
    78 |

    An expression to be evaluated.

    79 | 80 | 81 |
    ...
    82 |

    Character scalars. The values of ... will be coerced with the function 83 | string_magic. 84 | This means that string interpolation is allowed. Ex: "Arg. {arg} should be positive" 85 | leads to "Arg. power should be positive" if arg is equal to "power".

    86 |

    If argument verbatim is TRUE, the values are instead coereced with paste0.

    87 | 88 | 89 |
    clean
    90 |

    Character vector, default is missing. If provided, the function 91 | string_clean 92 | is applied to the captured error message to clean it when necessary. Each element 93 | of the vector should be of the form "pat => rep" with pat a regular expression 94 | to be replace and rep the replacement.

    95 | 96 | 97 |
    up
    98 |

    Integer, default is 0. It is used to construct the call in the error message. 99 | By default the call reported is the function containing check_expr. If you want to 100 | report a function higher in the stack, use up = 1, or higher.

    101 | 102 | 103 |
    arg_name
    104 |

    Character scalar, default is missing. Used when the expression in 105 | expr leads to an error and the custom message is missing (i.e. no element is 106 | provided in ...). In that case, the default message is: "The argument {arg_name} could not be evaluated.". 107 | The default value for arg_name is deparse(substitute(expr)), if this guess is wrong, 108 | use arg_name.

    109 | 110 | 111 |
    verbatim
    112 |

    Logical scalar, default is FALSE. By default the elements of ... 113 | allow string interpolation with "{}" using stringmagic. 114 | If TRUE, no interpolation is performed.

    115 | 116 | 117 |
    namespace
    118 |

    Character scalar giving the namespace for which the hooks are valid. Only useful 119 | when hook functions are used in a package.

    120 | 121 |
    122 |
    123 |

    Details

    124 |

    The purpose of this functions is to provide useful error messages to the user.

    125 |
    126 |
    127 |

    Functions

    128 | 129 |
    • check_expr_hook(): As check_expr but sets the error call at the level of the hooked function

    • 130 |
    • generate_check_expr_hook(): Generates a package specific check_expr_hook function

    • 131 |
    132 |
    133 |

    See also

    134 |

    For general argument checking, see check_arg() and check_set_arg().

    135 |
    136 |
    137 |

    Author

    138 |

    Laurent Berge

    139 |
    140 | 141 |
    142 |

    Examples

    143 |
    
    144 | test = function(x, y){
    145 |   check_expr(mean(x, y), "Computing the mean didn't work:")
    146 | }
    147 | 
    148 | 
    149 | 
    150 |
    151 |
    152 | 155 |
    156 | 157 | 158 |
    161 | 162 |
    163 |

    Site built with pkgdown 2.0.7.

    164 |
    165 | 166 |
    167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | -------------------------------------------------------------------------------- /docs/reference/dreamerr-package.html: -------------------------------------------------------------------------------- 1 | 2 | Error Handling Made Easy — dreamerr-package • dreamerr 6 | 7 | 8 |
    9 |
    50 | 51 | 52 | 53 |
    54 |
    55 | 60 | 61 |
    62 |

    The main purpose of this package is twofold: i) to facilitate the developer's life, and ii) to provide to the users meaningful, useful error messages. These objectives are accomplished with a single function: check_arg. That function checks the arguments given by the user: it offers a compact syntax such that complex arguments can be simply stated by the developer. In turn, if the user provides an argument of the wrong type then an informative error message will be buit, stating the expected type and where the error comes from--saving the user quite some time in debugging.

    63 |
    64 | 65 | 66 |
    67 |

    Details

    68 |

    Thus you can very easily make your package look professional with check_arg (checking arguments properly is professional).

    69 |

    It also offers a set of small tools to provide informative messages to the users. See stop_up and warn_up to throw errors and warnings in the appropriate location. There are many tools to form messages: enumerate_items to form textual list of elements (with many options including conjugating verbs, etc...), plural to conjugate verbs depending on the argument, and n_letter, n_th, n_times to write integers in words (which usually looks nicer).

    70 |

    To sum up in a few words, this package was created to enhance the user experience and facilitate package development.

    71 |
    72 |
    73 |

    See also

    74 |

    Useful links:

    76 |
    77 |
    78 |

    Author

    79 |

    Maintainer: Laurent Berge laurent.berge@u-bordeaux.fr

    80 |
    81 | 82 |
    83 | 86 |
    87 | 88 | 89 |
    92 | 93 |
    94 |

    Site built with pkgdown 2.0.7.

    95 |
    96 | 97 |
    98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | -------------------------------------------------------------------------------- /docs/reference/fsignif.html: -------------------------------------------------------------------------------- 1 | 2 | Formatting numbers with display of significant digits — fsignif • dreamerr 6 | 7 | 8 |
    9 |
    50 | 51 | 52 | 53 |
    54 |
    55 | 60 | 61 |
    62 |

    Formatting of numbers, when they are to appear in messages. Displays only significant digits in a "nice way" and adds commas to separate thousands. It does much less than the format function, but also a bit more though.

    63 |
    64 | 65 |
    66 |
    fsignif(x, s = 2, r = 0, commas = TRUE)
     67 | 
     68 | signif_plus
    69 |
    70 | 71 |
    72 |

    Format

    73 |

    An object of class function of length 1.

    74 |
    75 |
    76 |

    Arguments

    77 |
    x
    78 |

    A numeric vector.

    79 | 80 | 81 |
    s
    82 |

    The number of significant digits to be displayed. Defaults to 2. All digits not in the decimal are always shown.

    83 | 84 | 85 |
    r
    86 |

    For large values, the number of digits after the decimals to be displayed (beyond the number of significant digits). Defaults to 0. It is useful to suggest that a number is not an integer.

    87 | 88 | 89 |
    commas
    90 |

    Whether or not to add commas to separate thousands. Defaults to TRUE.

    91 | 92 |
    93 |
    94 |

    Value

    95 | 96 | 97 |

    It returns a character vector of the same length as the input.

    98 |
    99 | 100 |
    101 |

    Examples

    102 |
    
    103 | x = rnorm(1e5)
    104 | x[sample(1e5, 1e4, TRUE)] = NA
    105 | 
    106 | # Dumb function telling the number of NA values
    107 | tell_na = function(x) message("x contains ", fsignif(sum(is.na(x))), " NA values.")
    108 | 
    109 | tell_na(x)
    110 | #> x contains 9,473 NA values.
    111 | 
    112 | # Some differences with signif:
    113 | show_diff = function(x, d = 2) cat("signif(x, ", d, ") -> ", signif(x, d),
    114 |                                    " vs fsignif(x, ", d, ") -> ",
    115 |                                    fsignif(x, d), "\n", sep = "")
    116 | 
    117 | # Main difference is for large numbers
    118 | show_diff(95123.125)
    119 | #> signif(x, 2) -> 95000 vs fsignif(x, 2) -> 95,123
    120 | show_diff(95123.125, 7)
    121 | #> signif(x, 7) -> 95123.12 vs fsignif(x, 7) -> 95,123.12
    122 | 
    123 | # Identical for small numbers
    124 | show_diff(pi / 500)
    125 | #> signif(x, 2) -> 0.0063 vs fsignif(x, 2) -> 0.0063
    126 | 
    127 | 
    128 | 
    129 |
    130 |
    131 | 134 |
    135 | 136 | 137 |
    140 | 141 |
    142 |

    Site built with pkgdown 2.0.7.

    143 |
    144 | 145 |
    146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | -------------------------------------------------------------------------------- /docs/reference/index.html: -------------------------------------------------------------------------------- 1 | 2 | Function reference • dreamerr 6 | 7 | 8 |
    9 |
    50 | 51 | 52 | 53 |
    54 |
    55 | 58 | 59 | 63 | 66 | 67 | 70 | 71 | 74 | 75 | 78 | 79 | 82 | 83 | 86 | 87 | 90 | 91 | 94 | 95 | 98 | 99 | 102 | 103 | 106 | 107 | 110 | 111 | 114 | 115 | 118 | 119 | 122 | 123 | 126 | 127 | 130 | 131 | 134 | 135 | 138 | 139 | 142 | 143 |
    60 |

    All functions

    61 |

    62 |
    64 |

    check_arg() check_set_arg() check_value() check_set_value() check_arg_plus check_value_plus

    65 |

    Checks arguments and informs the user appropriately

    68 |

    check_expr() check_expr_hook() generate_check_expr_hook()

    69 |

    Checks the evaluation of an expression

    72 |

    dreamerr dreamerr-package

    73 |

    Error Handling Made Easy

    76 |

    enumerate_items()

    77 |

    Enumerates the elements of a vector

    80 |

    fit_screen()

    81 |

    Nicely fits a message in the current R console

    84 |

    fsignif() signif_plus

    85 |

    Formatting numbers with display of significant digits

    88 |

    ifsingle() ifunit()

    89 |

    Conditional element selection

    92 |

    n_times() n_th() n_letter()

    93 |

    Numbers in letters

    96 |

    package_stats()

    97 |

    Provides package statistics

    100 |

    plural() plural_len()

    101 |

    Adds an s and/or a singular/plural verb depending on the argument's length

    104 |

    setDreamerr_check()

    105 |

    Sets dreamerr argument checking functions on or off

    108 |

    setDreamerr_dev.mode()

    109 |

    Sets the developer mode to help form check_arg calls

    112 |

    setDreamerr_show_stack()

    113 |

    Settings telling whether or not to display the full call stack on errors

    116 |

    set_check()

    117 |

    Sets argument checking on/off "semi-globally"

    120 |

    set_up()

    121 |

    Sets "semi-globally" the 'up' argument of dreamerr's functions

    124 |

    sfill()

    125 |

    Fills a string vector with a symbol

    128 |

    generate_set_hook() generate_stop_hook() generate_warn_hook() set_hook() generate_get_hook() stop_hook() warn_hook()

    129 |

    Error displaying a call located at a hook location

    132 |

    stop_up() stopi() warni() warn_up()

    133 |

    Stops (or warns in) sub-function execution

    136 |

    suggest_item()

    137 |

    Suggest the the closest elements from a string vector

    140 |

    validate_dots()

    141 |

    Checks the arguments in dots from methods

    144 | 145 | 148 |
    149 | 150 | 151 |
    154 | 155 |
    156 |

    Site built with pkgdown 2.0.7.

    157 |
    158 | 159 |
    160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | -------------------------------------------------------------------------------- /docs/reference/n_times.html: -------------------------------------------------------------------------------- 1 | 2 | Numbers in letters — n_times • dreamerr 6 | 7 | 8 |
    9 |
    50 | 51 | 52 | 53 |
    54 |
    55 | 60 | 61 |
    62 |

    Set of (tiny) functions that convert integers into words.

    63 |
    64 | 65 |
    66 |
    n_times(n)
     67 | 
     68 | n_th(n)
     69 | 
     70 | n_letter(n)
    71 |
    72 | 73 |
    74 |

    Arguments

    75 |
    n
    76 |

    An integer vector.

    77 | 78 |
    79 |
    80 |

    Value

    81 | 82 | 83 |

    It returns a character vector of length one.

    84 |
    85 |
    86 |

    Functions

    87 | 88 |
    • n_th(): Transforms the integer n to nth appropiately.

    • 89 |
    • n_letter(): Transforms small integers to words.

    • 90 |
    91 |
    92 |

    Author

    93 |

    Laurent Berge

    94 |
    95 | 96 |
    97 |

    Examples

    98 |
    
     99 | find = function(v, x){
    100 |   if(x %in% v){
    101 |     message("The number ", n_letter(x), " appears ", n_times(sum(v == x)),
    102 |             ", the first occurrence is the ", n_th(which(v==x)[1]), " element.")
    103 |   } else message("The number ", n_letter(x), " was not found.")
    104 | }
    105 | 
    106 | v = sample(100, 500, TRUE)
    107 | find(v, 6)
    108 | #> The number six appears 7 times, the first occurrence is the 104th element.
    109 | 
    110 | 
    111 | 
    112 | 
    113 |
    114 |
    115 | 118 |
    119 | 120 | 121 |
    124 | 125 |
    126 |

    Site built with pkgdown 2.0.7.

    127 |
    128 | 129 |
    130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | -------------------------------------------------------------------------------- /docs/reference/package_stats.html: -------------------------------------------------------------------------------- 1 | 2 | Provides package statistics — package_stats • dreamerr 6 | 7 | 8 |
    9 |
    50 | 51 | 52 | 53 |
    54 |
    55 | 60 | 61 |
    62 |

    Summary statistics of a packages: number of lines, number of functions, etc...

    63 |
    64 | 65 |
    66 |
    package_stats()
    67 |
    68 | 69 |
    70 |

    Value

    71 | 72 | 73 |

    Doesn't return anything, just a prompt in the console.

    74 |
    75 |
    76 |

    Details

    77 |

    This function looks for files in the R/ and src/ folders and gives some stats. If there is no R/ folder directly accessible from the working directory, there will be no stats displayed.

    78 |

    Why this function? Well, it's just some goodies for package developers trying to be user-friendly!

    79 |

    The number of documentation lines (and number of words) corresponds to the number of non-empty roxygen documentation lines. So if you don't document your code with roxygen, well, this stat won't prompt.

    80 |

    Code lines correspond to non-commented, non-empty lines (by non empty: at least one letter must appear).

    81 |

    Comment lines are non-empty comments.

    82 |
    83 | 84 |
    85 |

    Examples

    86 |
    
     87 | package_stats()
     88 | #> Your project doesn't look like a package... Sorry, no stats!
     89 | 
     90 | 
    91 |
    92 |
    93 | 96 |
    97 | 98 | 99 |
    102 | 103 |
    104 |

    Site built with pkgdown 2.0.7.

    105 |
    106 | 107 |
    108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | -------------------------------------------------------------------------------- /docs/reference/setDreamerr_check.html: -------------------------------------------------------------------------------- 1 | 2 | Sets dreamerr argument checking functions on or off — setDreamerr_check • dreamerr 6 | 7 | 8 |
    9 |
    50 | 51 | 52 | 53 |
    54 |
    55 | 60 | 61 |
    62 |

    This function allows to disable, or re-enable, all calls to check_arg within any function. Useful only when running (very) large loops (>100K iter.) over small functions that use dreamerr's check_arg.

    63 |
    64 | 65 |
    66 |
    setDreamerr_check(check = TRUE)
    67 |
    68 | 69 |
    70 |

    Arguments

    71 |
    check
    72 |

    Strict logical: either TRUE of FALSE. Default is TRUE.

    73 | 74 |
    75 |
    76 |

    Author

    77 |

    Laurent Berge

    78 |
    79 | 80 |
    81 |

    Examples

    82 |
    
     83 | # Let's create a small function that returns the argument
     84 | #  if it is a single character string, and throws an error
     85 | #  otherwise:
     86 | 
     87 | test = function(x){
     88 |   check_arg(x, "scalar character")
     89 |   x
     90 | }
     91 | 
     92 | # works:
     93 | test("hey")
     94 | #> [1] "hey"
     95 | # error:
     96 | try(test(55))
     97 | #> Error : in test(55):
     98 | #>  Argument `x` must be a character scalar.
     99 | #> PROBLEM: it is not of type character (instead it is of type 'numeric').
    100 | 
    101 | # Now we disable argument checking
    102 | setDreamerr_check(FALSE)
    103 | # works (although it shouldn't!):
    104 | test(55)
    105 | #> [1] 55
    106 | 
    107 | # re-setting argument checking on:
    108 | setDreamerr_check(TRUE)
    109 | 
    110 | 
    111 | 
    112 |
    113 |
    114 | 117 |
    118 | 119 | 120 |
    123 | 124 |
    125 |

    Site built with pkgdown 2.0.7.

    126 |
    127 | 128 |
    129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | -------------------------------------------------------------------------------- /docs/sitemap.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | /404.html 5 | 6 | 7 | /articles/dreamerr_introduction.html 8 | 9 | 10 | /articles/index.html 11 | 12 | 13 | /authors.html 14 | 15 | 16 | /index.html 17 | 18 | 19 | /news/index.html 20 | 21 | 22 | /reference/check_arg.html 23 | 24 | 25 | /reference/check_expr.html 26 | 27 | 28 | /reference/dreamerr-package.html 29 | 30 | 31 | /reference/enumerate_items.html 32 | 33 | 34 | /reference/fit_screen.html 35 | 36 | 37 | /reference/fsignif.html 38 | 39 | 40 | /reference/ifsingle.html 41 | 42 | 43 | /reference/index.html 44 | 45 | 46 | /reference/n_times.html 47 | 48 | 49 | /reference/package_stats.html 50 | 51 | 52 | /reference/plural.html 53 | 54 | 55 | /reference/setDreamerr_check.html 56 | 57 | 58 | /reference/setDreamerr_dev.mode.html 59 | 60 | 61 | /reference/setDreamerr_show_stack.html 62 | 63 | 64 | /reference/set_check.html 65 | 66 | 67 | /reference/set_up.html 68 | 69 | 70 | /reference/sfill.html 71 | 72 | 73 | /reference/stop_hook.html 74 | 75 | 76 | /reference/stop_up.html 77 | 78 | 79 | /reference/suggest_item.html 80 | 81 | 82 | /reference/validate_dots.html 83 | 84 | 85 | -------------------------------------------------------------------------------- /man/check_expr.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/stop.R 3 | \name{check_expr} 4 | \alias{check_expr} 5 | \alias{check_expr_hook} 6 | \alias{generate_check_expr_hook} 7 | \title{Checks the evaluation of an expression} 8 | \usage{ 9 | check_expr(expr, ..., clean, up = 0, arg_name, verbatim = FALSE) 10 | 11 | check_expr_hook(expr, ..., clean, arg_name, verbatim = FALSE) 12 | 13 | generate_check_expr_hook(namespace) 14 | } 15 | \arguments{ 16 | \item{expr}{An expression to be evaluated.} 17 | 18 | \item{...}{Character scalars. The values of \code{...} will be coerced with the function 19 | \href{https://lrberge.github.io/stringmagic/articles/guide_string_magic.html}{string_magic}. 20 | This means that string interpolation is allowed. Ex: \code{"Arg. {arg} should be positive"} 21 | leads to \code{"Arg. power should be positive"} if \code{arg} is equal to "power". 22 | 23 | If argument \code{verbatim} is \code{TRUE}, the values are instead coereced with \code{paste0}.} 24 | 25 | \item{clean}{Character vector, default is missing. If provided, the function 26 | \href{https://lrberge.github.io/stringmagic/reference/string_clean.html}{\code{string_clean}} 27 | is applied to the \emph{captured error message} to clean it when necessary. Each element 28 | of the vector should be of the form \code{"pat => rep"} with pat a regular expression 29 | to be replace and \code{rep} the replacement.} 30 | 31 | \item{up}{Integer, default is 0. It is used to construct the call in the error message. 32 | By default the call reported is the function containing \code{check_expr}. If you want to 33 | report a function higher in the stack, use \code{up = 1}, or higher.} 34 | 35 | \item{arg_name}{Character scalar, default is missing. Used when the expression in 36 | \code{expr} leads to an error and the custom message is missing (i.e. no element is 37 | provided in \code{...}). In that case, the default message is: "The argument \verb{\{}arg_name\verb{\}} could not be evaluated.". 38 | The default value for \code{arg_name} is \code{deparse(substitute(expr))}, if this guess is wrong, 39 | use \code{arg_name}.} 40 | 41 | \item{verbatim}{Logical scalar, default is \code{FALSE}. By default the elements of \code{...} 42 | allow string interpolation with "\code{{}}" using \href{https://github.com/lrberge/stringmagic}{stringmagic}. 43 | If \code{TRUE}, no interpolation is performed.} 44 | 45 | \item{namespace}{Character scalar giving the namespace for which the hooks are valid. Only useful 46 | when hook functions are used in a package.} 47 | } 48 | \description{ 49 | This functions checks the evaluation of an expression and, if an error is thrown, 50 | captures it and integrates the captured message after a custom error message. 51 | } 52 | \details{ 53 | The purpose of this functions is to provide useful error messages to the user. 54 | } 55 | \section{Functions}{ 56 | \itemize{ 57 | \item \code{check_expr_hook()}: As \code{check_expr} but sets the error call at the level of the hooked function 58 | 59 | \item \code{generate_check_expr_hook()}: Generates a package specific \code{check_expr_hook} function 60 | 61 | }} 62 | \examples{ 63 | 64 | test = function(x, y){ 65 | check_expr(mean(x, y), "Computing the mean didn't work:") 66 | } 67 | 68 | 69 | } 70 | \seealso{ 71 | For general argument checking, see \code{\link[=check_arg]{check_arg()}} and \code{\link[=check_set_arg]{check_set_arg()}}. 72 | } 73 | \author{ 74 | Laurent Berge 75 | } 76 | -------------------------------------------------------------------------------- /man/dreamerr-package.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/dreamerr.R 3 | \docType{package} 4 | \name{dreamerr-package} 5 | \alias{dreamerr} 6 | \alias{dreamerr-package} 7 | \title{Error Handling Made Easy} 8 | \description{ 9 | The main purpose of this package is twofold: i) to facilitate the developer's life, and ii) to provide to the users meaningful, useful error messages. These objectives are accomplished with a single function: \code{\link[dreamerr]{check_arg}}. That function checks the arguments given by the user: it offers a compact syntax such that complex arguments can be simply stated by the developer. In turn, if the user provides an argument of the wrong type then an informative error message will be buit, stating the expected type and where the error comes from--saving the user quite some time in debugging. 10 | } 11 | \details{ 12 | Thus you can very easily make your package look professional with \code{\link[dreamerr]{check_arg}} (checking arguments properly \emph{is} professional). 13 | 14 | It also offers a set of small tools to provide informative messages to the users. See \code{\link[dreamerr]{stop_up}} and \code{\link[dreamerr:stop_up]{warn_up}} to throw errors and warnings in the appropriate location. There are many tools to form messages: \code{\link[dreamerr]{enumerate_items}} to form textual list of elements (with many options including conjugating verbs, etc...), \code{\link[dreamerr]{plural}} to conjugate verbs depending on the argument, and \code{\link[dreamerr:n_times]{n_letter}}, \code{\link[dreamerr:n_times]{n_th}}, \code{\link[dreamerr]{n_times}} to write integers in words (which usually looks nicer). 15 | 16 | To sum up in a few words, this package was created to enhance the user experience and facilitate package development. 17 | } 18 | \seealso{ 19 | Useful links: 20 | \itemize{ 21 | \item Report bugs at \url{https://github.com/lrberge/dreamerr/issues} 22 | } 23 | 24 | } 25 | \author{ 26 | \strong{Maintainer}: Laurent Berge \email{laurent.berge@u-bordeaux.fr} 27 | 28 | } 29 | -------------------------------------------------------------------------------- /man/enumerate_items.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/misc_funs.R 3 | \name{enumerate_items} 4 | \alias{enumerate_items} 5 | \title{Enumerates the elements of a vector} 6 | \usage{ 7 | enumerate_items( 8 | x, 9 | type, 10 | verb = FALSE, 11 | s = FALSE, 12 | past = FALSE, 13 | or = FALSE, 14 | start_verb = FALSE, 15 | quote = FALSE, 16 | enum = FALSE, 17 | other = "", 18 | nmax = 7 19 | ) 20 | } 21 | \arguments{ 22 | \item{x}{A vector.} 23 | 24 | \item{type}{A single character string, optional. If this argument is used, it supersedes all other arguments. It compactly provides the arguments of the function: it must be like \code{"arg1.arg2.arg3"}, i.e. a list of arguments separated by a point. The arguments are: "s" (to add a starting s if \code{length(x)>1}), "or" (to have "or" instead of "and"), "start" (to place the verb at the start instead of in the end), "quote" (to quote the elements of the vector), "enum" (to make an enumeration), "past" (to put the verb in past tense), a verb (i.e. anything different from the previous codes is a verb). Use \code{other(XX)} to set the argument \code{other} to \code{XX}. See details and examples.} 25 | 26 | \item{verb}{Default is \code{FALSE}. If provided, a verb is added at the end of the string, at the appropriate form. You add the verb at the start of the string using the argument \code{start_verb}. Valid verbs are: "be", "is", "has", "have", and any other verb with a regular form.} 27 | 28 | \item{s}{Logical, default is \code{FALSE}. If \code{TRUE} a \code{s} is added at the beginning of the string if the length of \code{x} is greater than one.} 29 | 30 | \item{past}{Logical, default is \code{FALSE}. If \code{TRUE} the verb is put at the past tense.} 31 | 32 | \item{or}{Logical, default is \code{FALSE}. If \code{TRUE} the two last items of the vector are separated by "or" instead of "and".} 33 | 34 | \item{start_verb}{Logical, default is \code{FALSE}. If \code{TRUE} the verb is placed at the beginning of the string instead of the end.} 35 | 36 | \item{quote}{Logical, default is \code{FALSE}. If \code{TRUE} all items are put in between single quotes.} 37 | 38 | \item{enum}{Logical, default is \code{FALSE}. If provided, an enumeration of the items of \code{x} is created. The possible values are "i", "I", "1", "a" and "A". Example: \code{x = c(5, 3, 12)}, \code{enum = "i"} will lead to "i) 5, ii) 3, and iii) 12".} 39 | 40 | \item{other}{Character scalar, defaults to the empty string: \code{""}. If there are more than \code{nmax} elements, then the character string will end with \code{"and XX others"} with \code{XX} the number of remaining items. Use this argument to change what is between the \code{and} and the \code{XX}. E.g. if \code{other = "any of"}, then you would get \code{"... and any of 15 others"} instead of \code{"... and 15 others"}.} 41 | 42 | \item{nmax}{Integer, default is 7. If \code{x} contains more than \code{nmax} items, then these items are grouped into an "other" group.} 43 | } 44 | \value{ 45 | It returns a character string of lentgh one. 46 | } 47 | \description{ 48 | Transforms a vector into a single character string enumerating the values of the vector. Many options exist to customize the result. The main purpose of this function is to ease the creation of user-level messages. 49 | } 50 | \section{The argument \code{type}}{ 51 | 52 | The argument \code{type} is a "super argument". When provided, it supersedes all other arguments. It offers a compact way to give the arguments to the function. 53 | 54 | Its sytax is as follows: \code{"arg1.arg2.arg2"}, where \code{argX} is an argument code. The codes are "s", "past", "or", "start", "quote", "enum" -- they refer to the function arguments. If you want to add a verb, since it can have a free-form, it is deduced as the argument not equal to the previous codes. For example, if you have \code{type = "s.contain"}, this is identical to calling the function with \code{s = TRUE} and \code{verb = "contain"}. 55 | 56 | A note on \code{enum}. The argument \code{enum} can be equal to "i", "I", "a", "A" or "1". When you include it in \code{type}, by default "i" is used. If you want another one, add it in the code. For example \code{type = "is.enum a.past"} is identical to calling the function with \code{verb = "is"}, \code{past = TRUE} and \code{enum = "a"}. 57 | } 58 | 59 | \examples{ 60 | 61 | # Let's say you write an error/information message to the user 62 | # I just use the "type" argument but you can obtain the 63 | # same results by using regular arguments 64 | 65 | x = c("x1", "height", "width") 66 | message("The variable", enumerate_items(x, "s.is"), " not in the data set.") 67 | # Now just the first item 68 | message("The variable", enumerate_items(x[1], "s.is"), " not in the data set.") 69 | 70 | # Past 71 | message("The variable", enumerate_items(x, "s.is.past"), " not found.") 72 | message("The variable", enumerate_items(x[1], "s.is.past"), " not found.") 73 | 74 | # Verb first 75 | message("The problematic variable", enumerate_items(x, "s.is.start.quote"), ".") 76 | message("The problematic variable", enumerate_items(x[1], "s.is.start.quote"), ".") 77 | 78 | # covid times 79 | todo = c("wash your hands", "stay home", "code") 80 | message("You should: ", enumerate_items(todo[c(1, 1, 2, 3)], "enum 1"), "!") 81 | message("You should: ", enumerate_items(todo, "enum.or"), "?") 82 | 83 | 84 | } 85 | \author{ 86 | Laurent Berge 87 | } 88 | -------------------------------------------------------------------------------- /man/fit_screen.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/misc_funs.R 3 | \name{fit_screen} 4 | \alias{fit_screen} 5 | \title{Nicely fits a message in the current R console} 6 | \usage{ 7 | fit_screen(msg, width = NULL, leading_ws = TRUE, leader = "") 8 | } 9 | \arguments{ 10 | \item{msg}{Text message: character vector.} 11 | 12 | \item{width}{A number between 0 and 1, or an integer. The maximum width of the screen the message should take. 13 | Numbers between 0 and 1 represent a fraction of the screen. You can also refer to the 14 | screen width with the special variable \code{.sw}. Integers represent the number of characters 15 | and cannot be lower than 15. Default is \code{min(120, 0.95*.sw)} (the min between 120 characters and 16 | 90\% of the screen width).} 17 | 18 | \item{leading_ws}{Logical, default is \code{TRUE}. Whether to keep the leading 19 | white spaces when the line is cut.} 20 | 21 | \item{leader}{Character scalar, default is the empty string. If provided, this 22 | value will be placed in front of every line.} 23 | } 24 | \value{ 25 | It returns a single character vector with line breaks at the appropriate width. 26 | } 27 | \description{ 28 | Utility to display long messages with nice formatting. This function cuts the message to fit the current screen width of the R console. Words are never cut in the middle. 29 | } 30 | \details{ 31 | This function does not handle tabulations. 32 | } 33 | \examples{ 34 | 35 | # A long message of two lines with a few leading spaces 36 | msg = enumerate_items(state.name, nmax = Inf) 37 | msg = paste0(" ", gsub("Michigan, ", "\n", msg)) 38 | 39 | # by default the message takes 95\% of the screen 40 | cat(fit_screen(msg)) 41 | 42 | # Now we reduce it to 50\% 43 | cat(fit_screen(msg, 0.5)) 44 | 45 | # we add leading_ws = FALSE to avoid the continuation of leading WS 46 | cat(fit_screen(msg, 0.5, FALSE)) 47 | 48 | # We add "#> " in front of each line 49 | cat(fit_screen(msg, 0.5, leader = "#> ")) 50 | 51 | 52 | } 53 | -------------------------------------------------------------------------------- /man/fsignif.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/misc_funs.R 3 | \docType{data} 4 | \name{fsignif} 5 | \alias{fsignif} 6 | \alias{signif_plus} 7 | \title{Formatting numbers with display of significant digits} 8 | \format{ 9 | An object of class \code{function} of length 1. 10 | } 11 | \usage{ 12 | fsignif(x, s = 2, r = 0, commas = TRUE) 13 | 14 | signif_plus 15 | } 16 | \arguments{ 17 | \item{x}{A numeric vector.} 18 | 19 | \item{s}{The number of significant digits to be displayed. Defaults to 2. All digits not in the decimal are always shown.} 20 | 21 | \item{r}{For large values, the number of digits after the decimals to be displayed (beyond the number of significant digits). Defaults to 0. It is useful to suggest that a number is not an integer.} 22 | 23 | \item{commas}{Whether or not to add commas to separate thousands. Defaults to \code{TRUE}.} 24 | } 25 | \value{ 26 | It returns a character vector of the same length as the input. 27 | } 28 | \description{ 29 | Formatting of numbers, when they are to appear in messages. Displays only significant digits in a "nice way" and adds commas to separate thousands. It does much less than the \code{\link[base]{format}} function, but also a bit more though. 30 | } 31 | \examples{ 32 | 33 | x = rnorm(1e5) 34 | x[sample(1e5, 1e4, TRUE)] = NA 35 | 36 | # Dumb function telling the number of NA values 37 | tell_na = function(x) message("x contains ", fsignif(sum(is.na(x))), " NA values.") 38 | 39 | tell_na(x) 40 | 41 | # Some differences with signif: 42 | show_diff = function(x, d = 2) cat("signif(x, ", d, ") -> ", signif(x, d), 43 | " vs fsignif(x, ", d, ") -> ", 44 | fsignif(x, d), "\n", sep = "") 45 | 46 | # Main difference is for large numbers 47 | show_diff(95123.125) 48 | show_diff(95123.125, 7) 49 | 50 | # Identical for small numbers 51 | show_diff(pi / 500) 52 | 53 | 54 | } 55 | \keyword{datasets} 56 | -------------------------------------------------------------------------------- /man/ifsingle.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/misc_funs.R 3 | \name{ifsingle} 4 | \alias{ifsingle} 5 | \alias{ifunit} 6 | \title{Conditional element selection} 7 | \usage{ 8 | ifsingle(x, yes, no) 9 | 10 | ifunit(x, yes, no) 11 | } 12 | \arguments{ 13 | \item{x}{A vector (\code{ifsingle}) or a numeric of length 1 (\code{ifunit}).} 14 | 15 | \item{yes}{Something of length 1. Result if the condition is fulfilled.} 16 | 17 | \item{no}{Something of length 1. Result if the condition is not fulfilled.} 18 | } 19 | \value{ 20 | Returns something of length 1. 21 | } 22 | \description{ 23 | Tiny functions shorter, and hopefully more explicit, than \code{ifelse}. 24 | } 25 | \details{ 26 | Yes, \code{ifunit} is identical to \code{ifelse(test == 1, yes, no)}. And regarding \code{ifsingle}, it is identical to \code{ifelse(length(test) == 1, yes, no)}. 27 | 28 | Why writing these functions then? Actually, I've found that they make the code more explicit, and this helps! 29 | } 30 | \section{Functions}{ 31 | \itemize{ 32 | \item \code{ifunit()}: Conditional element selection depending on whether \code{x} is equal to unity or not. 33 | 34 | }} 35 | \examples{ 36 | 37 | # Let's create an error message when NAs are present 38 | my_crossprod = function(mat){ 39 | if(anyNA(mat)){ 40 | row_na = which(rowSums(is.na(mat)) > 0) 41 | n_na = length(row_na) 42 | stop("In argument 'mat': ", n_letter(n_na), " row", plural(n_na, "s.contain"), 43 | " NA values (", ifelse(n_na<=3, "", "e.g. "), "row", 44 | enumerate_items(head(row_na, 3), "s"), "). 45 | Please remove ", ifunit(n_na, "it", "them"), " first.") 46 | } 47 | crossprod(mat) 48 | } 49 | 50 | mat = matrix(rnorm(30), 10, 3) 51 | mat4 = mat1 = mat 52 | mat4[c(1, 7, 13, 28)] = NA 53 | mat1[7] = NA 54 | 55 | # Error raised because of NA: informative (and nice) messages 56 | try(my_crossprod(mat4)) 57 | try(my_crossprod(mat1)) 58 | 59 | 60 | } 61 | \author{ 62 | Laurent Berge 63 | } 64 | -------------------------------------------------------------------------------- /man/n_times.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/misc_funs.R 3 | \name{n_times} 4 | \alias{n_times} 5 | \alias{n_th} 6 | \alias{n_letter} 7 | \title{Numbers in letters} 8 | \usage{ 9 | n_times(n) 10 | 11 | n_th(n) 12 | 13 | n_letter(n) 14 | } 15 | \arguments{ 16 | \item{n}{An integer vector.} 17 | } 18 | \value{ 19 | It returns a character vector of length one. 20 | } 21 | \description{ 22 | Set of (tiny) functions that convert integers into words. 23 | } 24 | \section{Functions}{ 25 | \itemize{ 26 | \item \code{n_th()}: Transforms the integer \code{n} to \code{nth} appropiately. 27 | 28 | \item \code{n_letter()}: Transforms small integers to words. 29 | 30 | }} 31 | \examples{ 32 | 33 | find = function(v, x){ 34 | if(x \%in\% v){ 35 | message("The number ", n_letter(x), " appears ", n_times(sum(v == x)), 36 | ", the first occurrence is the ", n_th(which(v==x)[1]), " element.") 37 | } else message("The number ", n_letter(x), " was not found.") 38 | } 39 | 40 | v = sample(100, 500, TRUE) 41 | find(v, 6) 42 | 43 | 44 | 45 | } 46 | \author{ 47 | Laurent Berge 48 | } 49 | -------------------------------------------------------------------------------- /man/package_stats.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/misc_funs.R 3 | \name{package_stats} 4 | \alias{package_stats} 5 | \title{Provides package statistics} 6 | \usage{ 7 | package_stats() 8 | } 9 | \value{ 10 | Doesn't return anything, just a prompt in the console. 11 | } 12 | \description{ 13 | Summary statistics of a packages: number of lines, number of functions, etc... 14 | } 15 | \details{ 16 | This function looks for files in the \code{R/} and \code{src/} folders and gives some stats. If there is no \code{R/} folder directly accessible from the working directory, there will be no stats displayed. 17 | 18 | Why this function? Well, it's just some goodies for package developers trying to be user-friendly! 19 | 20 | The number of documentation lines (and number of words) corresponds to the number of non-empty roxygen documentation lines. So if you don't document your code with roxygen, well, this stat won't prompt. 21 | 22 | Code lines correspond to non-commented, non-empty lines (by non empty: at least one letter must appear). 23 | 24 | Comment lines are non-empty comments. 25 | } 26 | \examples{ 27 | 28 | package_stats() 29 | 30 | } 31 | -------------------------------------------------------------------------------- /man/plural.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/misc_funs.R 3 | \name{plural} 4 | \alias{plural} 5 | \alias{plural_len} 6 | \title{Adds an s and/or a singular/plural verb depending on the argument's length} 7 | \usage{ 8 | plural(x, type, s, verb = FALSE, past = FALSE) 9 | 10 | plural_len(x, type, s, verb = FALSE, past = FALSE) 11 | } 12 | \arguments{ 13 | \item{x}{An integer of length one (\code{plural}) or a vector \code{plural_len}.} 14 | 15 | \item{type}{Character string, default is missing. If \code{type = "s.is.past"} it means that an "s" will be added if \code{x} is greater than 1 (or of length greater than one for \code{plural_len}); it will be followed by the verb "to be" in past tense in singular or plural form depending on \code{x}. This argument must be made of keywords separated by points without space, the keywords are "s", "past" and a verb (i.e. any thing different than "s" and "past"). Missing keywords mean their value is equal to \code{FALSE}.} 16 | 17 | \item{s}{Logical, used only if the argument type is missing. Whether to add an "s" if the form of \code{x} is plural. Default is missing: equals to \code{TRUE} if no other argument is provided, \code{FALSE} otherwise.} 18 | 19 | \item{verb}{Character string or \code{FALSE}, used only if the argument type is missing. The verb to be inserted in singular or plural depending on the value of \code{x}. default is \code{FALSE}.} 20 | 21 | \item{past}{Logical, used only if the argument type is missing. Whether the verb should be in past tense. Default is \code{FALSE}.} 22 | } 23 | \value{ 24 | Returns a character string of length one. 25 | } 26 | \description{ 27 | Utilities to write user-level messages. These functions add an \sQuote{s} or a verb at the appropriate form depending on whether the argument is equal to unity (\code{plural}) or of length one (\code{plural_len}). 28 | } 29 | \section{Functions}{ 30 | \itemize{ 31 | \item \code{plural_len()}: Adds an s and conjugate a verb depending on the length of \code{x} 32 | 33 | }} 34 | \examples{ 35 | 36 | # Let's create an error message when NAs are present 37 | my_crossprod = function(mat){ 38 | if(anyNA(mat)){ 39 | row_na = which(rowSums(is.na(mat)) > 0) 40 | n_na = length(row_na) 41 | stop("In argument 'mat': ", n_letter(n_na), " row", plural(n_na, "s.contain"), 42 | " NA values (", ifelse(n_na<=3, "", "e.g. "), "row", 43 | enumerate_items(head(row_na, 3), "s"), 44 | "). Please remove ", ifunit(n_na, "it", "them"), " first.") 45 | } 46 | crossprod(mat) 47 | } 48 | 49 | mat = matrix(rnorm(30), 10, 3) 50 | mat4 = mat1 = mat 51 | mat4[c(1, 7, 13, 28)] = NA 52 | mat1[7] = NA 53 | 54 | # Error raised because of NA: informative (and nice) messages 55 | try(my_crossprod(mat4)) 56 | try(my_crossprod(mat1)) 57 | 58 | } 59 | \author{ 60 | Laurent Berge 61 | } 62 | -------------------------------------------------------------------------------- /man/setDreamerr_check.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/stop.R 3 | \name{setDreamerr_check} 4 | \alias{setDreamerr_check} 5 | \title{Sets dreamerr argument checking functions on or off} 6 | \usage{ 7 | setDreamerr_check(check = TRUE) 8 | } 9 | \arguments{ 10 | \item{check}{Strict logical: either \code{TRUE} of \code{FALSE}. Default is \code{TRUE}.} 11 | } 12 | \description{ 13 | This function allows to disable, or re-enable, all calls to \code{\link[dreamerr]{check_arg}} within any function. Useful only when running (very) large loops (>100K iter.) over small functions that use dreamerr's \code{\link[dreamerr]{check_arg}}. 14 | } 15 | \examples{ 16 | 17 | # Let's create a small function that returns the argument 18 | # if it is a single character string, and throws an error 19 | # otherwise: 20 | 21 | test = function(x){ 22 | check_arg(x, "scalar character") 23 | x 24 | } 25 | 26 | # works: 27 | test("hey") 28 | # error: 29 | try(test(55)) 30 | 31 | # Now we disable argument checking 32 | setDreamerr_check(FALSE) 33 | # works (although it shouldn't!): 34 | test(55) 35 | 36 | # re-setting argument checking on: 37 | setDreamerr_check(TRUE) 38 | 39 | 40 | } 41 | \author{ 42 | Laurent Berge 43 | } 44 | -------------------------------------------------------------------------------- /man/setDreamerr_dev.mode.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/stop.R 3 | \name{setDreamerr_dev.mode} 4 | \alias{setDreamerr_dev.mode} 5 | \title{Sets the developer mode to help form check_arg calls} 6 | \usage{ 7 | setDreamerr_dev.mode(dev.mode = FALSE) 8 | } 9 | \arguments{ 10 | \item{dev.mode}{A logical, default is \code{FALSE}.} 11 | } 12 | \description{ 13 | Turns on/off a full fledged checking of calls to \code{\link[dreamerr]{check_arg}}. If on, it enables the developer mode which checks extensively calls to check_arg, allowing to find any problem. If a problem is found, it is pinpointed and the associated help is referred to. 14 | } 15 | \details{ 16 | Since this mode ensures a detailed cheking of all \code{\link[dreamerr]{check_arg}} calls, it is thus a strain on performance and should be always turned off otherwise needed. 17 | } 18 | \examples{ 19 | 20 | # If you're new to check_arg, given the many types available, 21 | # it's very common to make mistakes when creating check_arg calls. 22 | # The developer mode ensures that any problematic call is spotted 23 | # and the problem is clearly stated 24 | # 25 | # Note that since this mode ensures a detailed cheking of the call 26 | # it is thus a strain on performance and should be always turned off 27 | # otherwise needed. 28 | # 29 | 30 | # Setting the developer mode on: 31 | setDreamerr_dev.mode(TRUE) 32 | 33 | # Creating some 'wrong' calls => the problem is pinpointed 34 | 35 | test = function(x) check_arg(x, "integer scalar", "numeric vector") 36 | try(test()) 37 | 38 | test = function(...) check_arg("numeric vector", ...) 39 | try(test()) 40 | 41 | test = function(x) check_arg(x$a, "numeric vector") 42 | try(test()) 43 | 44 | test = function(x) check_arg(x, "numeric vector integer") 45 | try(test()) 46 | 47 | test = function(x) check_arg(x, "vector len(,)") 48 | try(test()) 49 | 50 | # etc... 51 | 52 | # Setting the developer mode off: 53 | setDreamerr_dev.mode(FALSE) 54 | 55 | 56 | } 57 | \seealso{ 58 | \code{\link[dreamerr]{check_arg}} 59 | } 60 | \author{ 61 | Laurent Berge 62 | } 63 | -------------------------------------------------------------------------------- /man/setDreamerr_show_stack.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/stop.R 3 | \name{setDreamerr_show_stack} 4 | \alias{setDreamerr_show_stack} 5 | \title{Settings telling whether or not to display the full call stack on errors} 6 | \usage{ 7 | setDreamerr_show_stack(show_full_stack = FALSE) 8 | } 9 | \arguments{ 10 | \item{show_full_stack}{Logical scalar, default is \code{FALSE}. If \code{TRUE}, then 11 | errors generated by dreamerr functions (like \code{\link[=stop_up]{stop_up()}}/\code{\link[=stopi]{stopi()}}) will display 12 | the full call stack.} 13 | } 14 | \description{ 15 | Errors generated with dreamerr functions only shows the call to which 16 | the error should point to. If \code{setDreamerr_show_stack} is set to TRUE, 17 | error will display the full call stack instead. 18 | } 19 | \examples{ 20 | 21 | # Let's create a toy example of a function relying on an internal function 22 | # for the heavy lifting (although here it's pretty light!) 23 | make_sum = function(a, b){ 24 | make_sum_internal(a, b) 25 | } 26 | 27 | make_sum_internal = function(a, b){ 28 | if(!is.numeric(a)) stop_up("arg. 'a' must be numeric!") 29 | a + b 30 | } 31 | 32 | # By default if you feed stg non numeric, the call shown is 33 | # make_sum, and not make_sum_internal, since the user could not 34 | # care less of the internal structure of your functions 35 | 36 | try(make_sum("five", 55)) 37 | 38 | # Now with setDreamerr_show_stack(TRUE), you would get the full call stack 39 | setDreamerr_show_stack(TRUE) 40 | try(make_sum("five", 55)) 41 | 42 | 43 | 44 | } 45 | \author{ 46 | Laurent Berge 47 | } 48 | -------------------------------------------------------------------------------- /man/set_check.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/stop.R 3 | \name{set_check} 4 | \alias{set_check} 5 | \title{Sets argument checking on/off "semi-globally"} 6 | \usage{ 7 | set_check(x) 8 | } 9 | \arguments{ 10 | \item{x}{A logical scalar, no default.} 11 | } 12 | \description{ 13 | You can allow your users to turn off argument checking within your function by using \code{set_check}. Only the functions \code{\link[dreamerr]{check_arg}} nd \code{\link[dreamerr:check_arg]{check_value}} can be turned off that way. 14 | } 15 | \details{ 16 | This function can be useful if you develop a function that may be used in large range loops (>100K). In such situations, it may be good to still check all arguments, but to offer the user to turn this checking off with an extra argument (named \code{arg.check} for instance). Doing so you would achieve the feat of i) having a user-friendly function thanks to argument checking and, ii) still achieve high performance in large loops (although the computational footprint of argument checking is quite low (around 30 micro seconds for missing arguments to 80 micro seconds for non-missing arguments of simple type)). 17 | } 18 | \examples{ 19 | 20 | # Let's give an example 21 | test_check = function(x, y, arg.check = TRUE){ 22 | set_check(arg.check) 23 | check_arg(x, y, "numeric scalar") 24 | x + y 25 | } 26 | 27 | # Works: argument checking on 28 | test_check(1, 2) 29 | 30 | # If mistake, nice error msg 31 | try(test_check(1, "a")) 32 | 33 | # Now argument checking turned off 34 | test_check(1, 2, FALSE) 35 | # But if mistake: "not nice" error message 36 | try(test_check(1, "a", FALSE)) 37 | 38 | 39 | 40 | } 41 | -------------------------------------------------------------------------------- /man/set_up.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/stop.R 3 | \name{set_up} 4 | \alias{set_up} 5 | \title{Sets "semi-globally" the 'up' argument of dreamerr's functions} 6 | \usage{ 7 | set_up(.up = 1) 8 | } 9 | \arguments{ 10 | \item{.up}{An integer greater or equal to 0.} 11 | } 12 | \description{ 13 | When \code{\link[dreamerr]{check_arg}} (or \code{\link[dreamerr]{stop_up}}) is used in non user-level functions, the argument \code{.up} is used to provide an appropriate error message referencing the right function. 14 | } 15 | \details{ 16 | To avoid repeating the argument \code{.up} in each \code{check_arg} call, you can set it (kind of) "globally" with \code{set_up}. 17 | 18 | The function \code{set_up} does not set the argument \code{up} globally, but only for all calls to \code{check_arg} and \code{check_value} within the same function. 19 | } 20 | \examples{ 21 | 22 | # Example with computation being made within a non user-level function 23 | 24 | sum_fun = function(x, y){ 25 | my_internal(x, y, sum = TRUE) 26 | } 27 | 28 | diff_fun = function(x, y){ 29 | my_internal(x, y, sum = FALSE) 30 | } 31 | 32 | my_internal = function(x, y, sum){ 33 | set_up(1) # => errors will be at the user-level function 34 | check_arg(x, y, "numeric scalar mbt") 35 | 36 | # Identical to calling 37 | # check_arg(x, y, "numeric scalar mbt", .up = 1) 38 | 39 | if(sum) return(x + y) 40 | return(x - y) 41 | } 42 | 43 | # we check it works 44 | sum_fun(5, 6) 45 | diff_fun(5, 6) 46 | 47 | # Let's throw some errors 48 | try(sum_fun(5)) 49 | try(sum_fun(5, 1:5)) 50 | 51 | } 52 | -------------------------------------------------------------------------------- /man/sfill.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/misc_funs.R 3 | \name{sfill} 4 | \alias{sfill} 5 | \title{Fills a string vector with a symbol} 6 | \usage{ 7 | sfill(x = "", n = NULL, symbol = " ", right = FALSE, anchor, na = "NA") 8 | } 9 | \arguments{ 10 | \item{x}{A character vector.} 11 | 12 | \item{n}{A positive integer giving the total expected length of each character string. Can be NULL (default). If \code{NULL}, then \code{n} is set to the maximum number of characters in \code{x} (i.e. \code{max(nchar(x))}).} 13 | 14 | \item{symbol}{Character scalar, default to \code{" "}. The symbol used to fill.} 15 | 16 | \item{right}{Logical, default is \code{FALSE}. Whether the character vector should be filled on the left( default) or on the right.} 17 | 18 | \item{anchor}{Character scalar, can be missing. If provided, the filling is done up to this anchor. See examples.} 19 | 20 | \item{na}{Character that will replace any NA value in input. Default is "NA".} 21 | } 22 | \value{ 23 | Returns a character vector of the same length as \code{x}. 24 | } 25 | \description{ 26 | Fills a string vector with a user-provided symbol, up to the required length. 27 | } 28 | \examples{ 29 | 30 | # Some self-explaining examples 31 | x = c("hello", "I", "am", "No-one") 32 | cat(sep = "\n", sfill(x)) 33 | cat(sep = "\n", sfill(x, symbol = ".")) 34 | cat(sep = "\n", sfill(x, symbol = ".", n = 15)) 35 | cat(sep = "\n", sfill(x, symbol = ".", right = TRUE)) 36 | 37 | cat(sep = "\n", paste(sfill(x, symbol = ".", right = TRUE), ":", 1:4)) 38 | 39 | # Argument 'anchor' can be useful when using numeric vectors 40 | x = c(-15.5, 1253, 32.52, 665.542) 41 | cat(sep = "\n", sfill(x)) 42 | cat(sep = "\n", sfill(x, anchor = ".")) 43 | 44 | } 45 | -------------------------------------------------------------------------------- /man/stop_hook.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/stop.R 3 | \name{generate_set_hook} 4 | \alias{generate_set_hook} 5 | \alias{generate_stop_hook} 6 | \alias{generate_warn_hook} 7 | \alias{set_hook} 8 | \alias{generate_get_hook} 9 | \alias{stop_hook} 10 | \alias{warn_hook} 11 | \title{Error displaying a call located at a hook location} 12 | \usage{ 13 | generate_set_hook(namespace) 14 | 15 | generate_stop_hook(namespace) 16 | 17 | generate_warn_hook(namespace) 18 | 19 | set_hook() 20 | 21 | generate_get_hook(namespace) 22 | 23 | stop_hook(..., msg = NULL, envir = parent.frame(), verbatim = FALSE) 24 | 25 | warn_hook(..., envir = parent.frame(), immediate. = FALSE, verbatim = FALSE) 26 | } 27 | \arguments{ 28 | \item{namespace}{Character scalar giving the namespace for which the hooks are valid. Only useful 29 | when hook functions are used in a package.} 30 | 31 | \item{...}{Objects that will be coerced to character and will compose the error message.} 32 | 33 | \item{msg}{A character vector, default is \code{NULL}. If provided, this message will be displayed right under the error message. This is mostly useful when the text contains formatting because the function \code{\link{stop}} used to send the error message erases any formatting.} 34 | 35 | \item{envir}{An environment, default is \code{parent.frame()}. Only relevant if the error/warning message contains 36 | interpolation (interpolation is performed with \href{https://github.com/lrberge/stringmagic}{stringmagic}). It tells 37 | where the variables to be interpolated should be found. In general you should not worry about this argument.} 38 | 39 | \item{verbatim}{Logical scalar, default is \code{FALSE}. By default the error/warning message allows variable 40 | interpolation with \href{https://github.com/lrberge/stringmagic}{stringmagic}. To disable interpolation, 41 | use \code{verbatim = TRUE}.} 42 | 43 | \item{immediate.}{Whether the warning message should be prompted directly. Defaults to \code{FALSE}.} 44 | } 45 | \description{ 46 | When devising complex functions, errors or warnings can be deeply nested in internal 47 | function calls while the user-relevant call is way up the stack. In such cases, these "hook" 48 | functions facilitate the creation of error/warnings informative for the user. 49 | } 50 | \details{ 51 | These functions are useful when developing complex functions relying on nested internal functions. 52 | It is important for the user to know where the errors/warnings come from for quick debugging. 53 | This "_hook" family of functions write the call of the user-level function even if the errors 54 | happen at the level of the internal functions. 55 | 56 | If you need these functions within a package, you need to generate the \code{set_hook}, \code{stop_hook} and 57 | \code{warn_hook} functions so that they set, and look up for, hooks speficic to your function. This ensures that 58 | if other functions outside your package also use hooks, there will be no conflict. The only thing to do 59 | is to write this somewhere in the package files: 60 | 61 | \if{html}{\out{
    }}\preformatted{set_hook = generate_set_hook("pkg_name") 62 | stop_hook = generate_stop_hook("pkg_name") 63 | warn_hook = generate_warn_hook("pkg_name") 64 | }\if{html}{\out{
    }} 65 | } 66 | \section{Functions}{ 67 | \itemize{ 68 | \item \code{generate_set_hook()}: Generates a package specific \code{set_hook} function 69 | 70 | \item \code{generate_stop_hook()}: Generates a package specific \code{stop_hook} function 71 | 72 | \item \code{generate_warn_hook()}: Generates a package specific \code{warn_hook} function 73 | 74 | \item \code{set_hook()}: Marks the function as the hook 75 | 76 | \item \code{generate_get_hook()}: Generates the function giving the number of frames we 77 | need to go up the call stack to find the hooked function 78 | 79 | \item \code{warn_hook()}: Warning with a call located at a hook location 80 | 81 | }} 82 | \examples{ 83 | 84 | # The example needs to be complex since it's about nested functions, sorry 85 | # Let's say you have an internal function that is dispatched into several 86 | # user-level functions 87 | 88 | my_mean = function(x, drop_na = FALSE){ 89 | set_hook() 90 | my_mean_internal(x = x, drop_na = drop_na) 91 | } 92 | 93 | my_mean_skip_na = function(x){ 94 | set_hook() 95 | my_mean_internal(x = x, drop_na = TRUE) 96 | } 97 | 98 | my_mean_internal = function(x, drop_na){ 99 | # simple check 100 | if(!is.numeric(x)){ 101 | # note that we use string interpolation with stringmagic. 102 | stop_hook("The argument `x` must be numeric. PROBLEM: it is of class {enum.bq ? class(x)}.") 103 | } 104 | 105 | if(drop_na){ 106 | return(mean(x, na.rm = TRUE)) 107 | } else { 108 | return(mean(x, na.rm = FALSE)) 109 | } 110 | } 111 | 112 | # Let's run the function with a wrong argument 113 | x = "five" 114 | try(my_mean(x)) 115 | 116 | # => the error message reports that the error comes from my_mean 117 | # and *not* my_mean_internal 118 | 119 | 120 | } 121 | \seealso{ 122 | Regular stop functions with interpolation: \code{\link[=stop_up]{stop_up()}}. Regular argument checking 123 | with \code{\link[=check_arg]{check_arg()}} and \code{\link[=check_set_arg]{check_set_arg()}}. 124 | } 125 | \author{ 126 | Laurent Berge 127 | } 128 | -------------------------------------------------------------------------------- /man/stop_up.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/stop.R 3 | \name{stop_up} 4 | \alias{stop_up} 5 | \alias{stopi} 6 | \alias{warni} 7 | \alias{warn_up} 8 | \title{Stops (or warns in) sub-function execution} 9 | \usage{ 10 | stop_up(..., up = 1, msg = NULL, envir = parent.frame(), verbatim = FALSE) 11 | 12 | stopi(..., envir = parent.frame()) 13 | 14 | warni(..., envir = parent.frame(), immediate. = FALSE) 15 | 16 | warn_up( 17 | ..., 18 | up = 1, 19 | immediate. = FALSE, 20 | envir = parent.frame(), 21 | verbatim = FALSE 22 | ) 23 | } 24 | \arguments{ 25 | \item{...}{Objects that will be coerced to character and will compose the error message.} 26 | 27 | \item{up}{The number of frames up, default is 1. The call in the error message will be based on the function \code{up} frames up the stack. See examples. If you have many calls to \code{stop_up}/\code{warn_up} with a value of \code{up} different than one, you can use \code{\link[dreamerr]{set_up}} to change the default value of \code{up} within the function.} 28 | 29 | \item{msg}{A character vector, default is \code{NULL}. If provided, this message will be displayed right under the error message. This is mostly useful when the text contains formatting because the function \code{\link{stop}} used to send the error message erases any formatting.} 30 | 31 | \item{envir}{An environment, default is \code{parent.frame()}. Only relevant if the error/warning message contains 32 | interpolation (interpolation is performed with \href{https://github.com/lrberge/stringmagic}{stringmagic}). It tells 33 | where the variables to be interpolated should be found. In general you should not worry about this argument.} 34 | 35 | \item{verbatim}{Logical scalar, default is \code{FALSE}. By default the error/warning message allows variable 36 | interpolation with \href{https://github.com/lrberge/stringmagic}{stringmagic}. To disable interpolation, 37 | use \code{verbatim = TRUE}.} 38 | 39 | \item{immediate.}{Whether the warning message should be prompted directly. Defaults to \code{FALSE}.} 40 | } 41 | \description{ 42 | Useful if you employ non-user level sub-functions within user-level functions or 43 | if you want string interpolation in error messages. When an error is thrown in the sub 44 | function, the error message will integrate the call of the user-level function, which 45 | is more informative and appropriate for the user. It offers a similar functionality for \code{warning}. 46 | } 47 | \details{ 48 | These functions are really made for package developers to facilitate the good practice of providing informative user-level error/warning messages. 49 | 50 | The error/warning messages allow variable interpolation by making use of \href{https://github.com/lrberge/stringmagic}{stringmagic}'s interpolation. 51 | } 52 | \section{Functions}{ 53 | \itemize{ 54 | \item \code{stopi()}: Error messages with string interpolation 55 | 56 | \item \code{warni()}: Warnings with string interpolation 57 | 58 | \item \code{warn_up()}: Warnings at the level of user-level functions 59 | 60 | }} 61 | \examples{ 62 | 63 | # We create a main user-level function 64 | # The computation is done by an internal function 65 | # Here we compare stop_up with a regular stop 66 | 67 | main_function = function(x = 1, y = 2){ 68 | my_internal_function(x, y) 69 | } 70 | 71 | my_internal_function = function(x, y){ 72 | if(!is.numeric(x)){ 73 | stop_up("Argument 'x' must be numeric but currently isn't.") 74 | } 75 | 76 | # Now regular stop 77 | if(!is.numeric(y)){ 78 | stop("Argument 'y' must be numeric but currently isn't.") 79 | } 80 | 81 | nx = length(x) 82 | ny = length(y) 83 | if(nx != ny){ 84 | # Note that we use string interpolation with {} 85 | warn_up("The lengths of x and y don't match: {nx} vs {ny}.") 86 | } 87 | 88 | x + y 89 | } 90 | 91 | # Let's compare the two error messages 92 | # stop_up: 93 | try(main_function(x = "a")) 94 | # => the user understands that the problem is with x 95 | 96 | # Now compare with the regular stop: 97 | try(main_function(y = "a")) 98 | # Since the user has no clue of what my_internal_function is, 99 | # s/he will be puzzled of what to do to sort this out 100 | 101 | # Same with the warning => much clearer with warn_up 102 | main_function(1, 1:2) 103 | 104 | 105 | } 106 | \seealso{ 107 | For general argument checking, see \code{\link[=check_arg]{check_arg()}} and \code{\link[=check_set_arg]{check_set_arg()}}. 108 | } 109 | \author{ 110 | Laurent Berge 111 | } 112 | -------------------------------------------------------------------------------- /man/suggest_item.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/misc_funs.R 3 | \name{suggest_item} 4 | \alias{suggest_item} 5 | \title{Suggest the the closest elements from a string vector} 6 | \usage{ 7 | suggest_item( 8 | x, 9 | items, 10 | msg.write = FALSE, 11 | msg.newline = TRUE, 12 | msg.item = "variable" 13 | ) 14 | } 15 | \arguments{ 16 | \item{x}{Character scalar, must be provided. This reference will be compared 17 | to the elements of the string vector in the argument \code{items}.} 18 | 19 | \item{items}{Character vector, must be provided. Elements to which the value in 20 | argument \code{x} will be compared.} 21 | 22 | \item{msg.write}{Logical scalar, default is \code{FALSE}. If \code{TRUE}, a message is returned, 23 | equal to \code{"Maybe you meant {enum.bq.or ? matches}?"} (see \href{https://lrberge.github.io/stringmagic/articles/guide_string_magic.html}{stringmagic} 24 | for information on the interpolation) if there were matches. If no matches were found, 25 | the message is \code{"FYI the {msg.item}{$s, are, enum.bq ? items}."}.} 26 | 27 | \item{msg.newline}{Logical scalar, default is \code{TRUE}. Only used if \code{msg.write = TRUE}. 28 | Whether to add a new line just before the message.} 29 | 30 | \item{msg.item}{Character scalar, default is \code{"variable"}. Only used if \code{msg.write = TRUE}. 31 | What does the \code{items} represent?} 32 | } 33 | \value{ 34 | It returns a vector of matches. If no matches were found 35 | } 36 | \description{ 37 | Compares a character scalar to the elements from a character vector and 38 | returns the elements that are the closest to the input. 39 | } 40 | \details{ 41 | This function is useful when used internally to guide the user to relevant choices. 42 | 43 | The choices to which the user is guided are in decreasing quality. First light mispells 44 | are checked. Then more important mispells. Finally very important mispells. Completely 45 | off potential matches are not reported. 46 | 47 | If the argument \code{msg.write} is \code{TRUE}, then a character scalar is returned containing 48 | a message suggesting the matches. 49 | } 50 | \examples{ 51 | 52 | # function reporting the sum of a variable 53 | sum_var = function(data, var){ 54 | # var: a variable name, should be part of data 55 | if(!var \%in\% names(data)){ 56 | suggestion = suggest_item(var, names(data), msg.write = TRUE) 57 | stopi("The variable `{var}` is not in the data set. {suggestion}") 58 | } 59 | 60 | sum(data[[var]]) 61 | } 62 | 63 | # The error message guides us to a suggestion 64 | try(sum_var(iris, "Petal.Le")) 65 | 66 | } 67 | \author{ 68 | Laurent Berge 69 | } 70 | -------------------------------------------------------------------------------- /man/validate_dots.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/stop.R 3 | \name{validate_dots} 4 | \alias{validate_dots} 5 | \title{Checks the arguments in dots from methods} 6 | \usage{ 7 | validate_dots( 8 | valid_args = c(), 9 | suggest_args = c(), 10 | message, 11 | warn, 12 | stop, 13 | call. = FALSE, 14 | immediate. = TRUE 15 | ) 16 | } 17 | \arguments{ 18 | \item{valid_args}{A character vector, default is missing. Arguments that are not in the definition of the function but which are considered as valid. Typically internal arguments that should not be directly accessed by the user.} 19 | 20 | \item{suggest_args}{A character vector, default is missing. If the user provides invalid arguments, he might not be aware of the main arguments of the function. Use this argument to inform the user of these main arguments.} 21 | 22 | \item{message}{Logical, default is \code{FALSE}. If \code{TRUE}, a standard message is prompted to the user (instead of a warning).} 23 | 24 | \item{warn}{Logical, default is \code{TRUE}. If \code{TRUE}, when the user provides invalid arguments, the function will call \code{\link[base]{warning}} (default). If \code{FALSE} (and so are the other arguments \code{stop} and \code{message}), then no message is prompted to the user, rather it is the only output of the function.} 25 | 26 | \item{stop}{Logical, default is \code{FALSE}. If \code{TRUE}, when the user provides invalid arguments, the function will call \code{\link[base]{stop}} instead of prompting a warning (default).} 27 | 28 | \item{call.}{Logical, default is \code{FALSE}. If \code{TRUE}, when the user provides invalid arguments, then the message will also contain the call to the initial function (by default, only the function name is shown).} 29 | 30 | \item{immediate.}{Logical, default is \code{FALSE}. Can be only used with the argument \code{warn = TRUE}: whether the warning is immediately displayed or not.} 31 | } 32 | \value{ 33 | This function returns the message to be displayed. If no message is to be displayed because all the arguments are valid, then \code{NULL} is returned. 34 | } 35 | \description{ 36 | This function informs the user of arguments passed to a method but which are not used by the method. 37 | } 38 | \examples{ 39 | 40 | # The typical use of this function is within methods 41 | 42 | # Let's create a 'my_class' object and a summary method 43 | my_obj = list() 44 | class(my_obj) = "my_class" 45 | 46 | # In the summary method, we add validate_dots 47 | # to inform the user of invalid arguments 48 | 49 | summary.my_class = function(object, arg_one, arg_two, ...){ 50 | 51 | validate_dots() 52 | # CODE of summary.my_class 53 | invisible(NULL) 54 | } 55 | 56 | # Now let's test it, we add invalid arguments 57 | summary(my_obj, wrong = 3) 58 | summary(my_obj, wrong = 3, info = 5) 59 | 60 | # Now let's : 61 | # i) inform the user that argument arg_one is the main argument 62 | # ii) consider 'info' as a valid argument (but not shown to the user) 63 | # iii) show a message instead of a warning 64 | 65 | summary.my_class = function(object, arg_one, arg_two, ...){ 66 | 67 | validate_dots(valid_args = "info", suggest_args = "arg_one", message = TRUE) 68 | # CODE of summary.my_class 69 | invisible(NULL) 70 | } 71 | 72 | # Let's retest it 73 | summary(my_obj, wrong = 3) # not OK => suggestions 74 | summary(my_obj, info = 5) # OK 75 | 76 | 77 | 78 | } 79 | -------------------------------------------------------------------------------- /tests/tests_dreamerr.R: -------------------------------------------------------------------------------- 1 | #----------------------------------------------# 2 | # Author: Laurent Berge 3 | # Date creation: Mon Aug 31 09:07:52 2020 4 | # ~: test script for dreamerr 5 | #----------------------------------------------# 6 | 7 | 8 | # Two kinds of checks: 9 | # 1) no error when there should be no error 10 | # 2) errors when there should be errors 11 | # 12 | 13 | # To do: 14 | # * add complex calls (multiple types) 15 | # * add check_value 16 | # * check returns from check_arg and check_value 17 | # * specifics from check_set_arg (conv, NULL, etc) 18 | 19 | library(dreamerr) 20 | 21 | test_err = function(x){ 22 | a = try(x, silent = TRUE) 23 | if(!any(class(a) == "try-error")) stop("Expected an error that did not occur.") 24 | invisible(NULL) 25 | } 26 | 27 | 28 | #### 29 | #### Main Types #### 30 | #### 31 | 32 | 33 | #### 34 | #### ...scalar #### 35 | #### 36 | 37 | # To check: types / equality / NA 38 | 39 | test_scalar = function(x1, x2, x3, x4, x5){ 40 | check_arg(x1, "numeric scalar") 41 | check_arg(x2, "integer scalar na ok") 42 | check_arg(x3, "scalar(factor, logical)") 43 | check_arg(x4, "scalar(integer, character, logical)") 44 | check_arg(x5, "integer scalar GT{-3} LE{3}") 45 | invisible(NULL) 46 | } 47 | 48 | # 49 | # Should work 50 | # 51 | 52 | # x1: numeric scalar 53 | test_scalar(x1 = 1) 54 | test_scalar(x1 = -1) 55 | test_scalar(x1 = exp(55)) 56 | 57 | # x2: integer scalar na ok 58 | test_scalar(x2 = 1) 59 | test_scalar(x2 = NA) 60 | 61 | # x3: scalar(factor, logical) 62 | test_scalar(x3 = factor("a", "a")) 63 | test_scalar(x3 = TRUE) 64 | 65 | # x4: scalar(integer, character, logical) 66 | test_scalar(x4 = 5) 67 | test_scalar(x4 = "bon") 68 | test_scalar(x4 = TRUE) 69 | 70 | # x5: integer scalar GT{-3} LE{3} 71 | test_scalar(x5 = -2) 72 | test_scalar(x5 = 3) 73 | 74 | 75 | # 76 | # Should **not** work 77 | # 78 | 79 | # x1: numeric scalar 80 | test_err(test_scalar("5")) 81 | test_err(test_scalar(NA)) 82 | test_err(test_scalar(iris)) 83 | 84 | # x2: integer scalar na ok 85 | test_err(test_scalar(x2 = 1.1)) 86 | test_err(test_scalar(x2 = c(NA, 1))) 87 | 88 | # x3: scalar(factor, logical) 89 | test_err(test_scalar(x3 = "5")) 90 | test_err(test_scalar(x3 = 1)) 91 | 92 | # x4: scalar(integer, character, logical) 93 | test_err(test_scalar(x4 = 5.5)) 94 | 95 | # x5: integer scalar GT{-3} LE{3} 96 | test_err(test_scalar(x5 = -3)) 97 | test_err(test_scalar(x5 = 3.1)) 98 | 99 | 100 | 101 | #### 102 | #### ...vector #### 103 | #### 104 | 105 | # To check: types / equality / NA / len 106 | 107 | test_vec = function(x1, x2, x3, x4, x5, x6){ 108 | check_arg(x1, "integer vector") 109 | check_arg(x2, "numeric vector no na GE{0}") 110 | check_arg(x3, "vector(logical, character)") 111 | check_arg(x4, "vector len(2,5)") 112 | check_arg(x5, "numeric vector len(data)", .data = iris) 113 | check_arg(x6, "integer vector len(value) no na GT{5}", .value = 3) 114 | invisible(NULL) 115 | } 116 | 117 | 118 | # 119 | # should work 120 | # 121 | 122 | # x1: integer vector 123 | test_vec(x1 = 5) 124 | test_vec(x1 = 5:6) 125 | test_vec(x1 = TRUE) 126 | 127 | # x2: numeric vector no na GE{0} 128 | test_vec(x2 = 1.1) 129 | test_vec(x2 = iris$Sepal.Length) 130 | test_vec(x2 = c(55, 32)) 131 | 132 | # x3: vector(logical, character) 133 | test_vec(x3 = c(TRUE, NA, FALSE)) 134 | test_vec(x3 = TRUE) 135 | test_vec(x3 = c("bon", NA, "jour")) 136 | 137 | # x4: vector len(2,5) 138 | test_vec(x4 = c(TRUE, NA)) 139 | test_vec(x4 = c("bon", NA, "jour", NA, NA)) 140 | 141 | # x5: numeric vector len(data) 142 | test_vec(x5 = iris$Sepal.Width) 143 | 144 | # x6: integer vector len(value) no na GT{5} // .value = 3 145 | test_vec(x6 = c(6, 7, 8)) 146 | 147 | # 148 | # should **not** work 149 | # 150 | 151 | # x1: integer vector 152 | test_err(test_vec(x1 = 5.5)) 153 | test_err(test_vec(x1 = 0.5 + 1:2)) 154 | 155 | # x2: numeric vector no na GE{0} 156 | test_err(test_vec(x2 = -1.1)) 157 | test_err(test_vec(x2 = c(NA, 55))) 158 | 159 | # x3: vector(logical, character) 160 | test_err(test_vec(x3 = 55)) 161 | 162 | # x4: vector len(2,5) 163 | test_err(test_vec(x4 = TRUE)) 164 | 165 | # x5: numeric vector len(data) 166 | test_err(test_vec(x5 = iris$Species)) 167 | test_err(test_vec(x5 = 1:5)) 168 | 169 | # x6: integer vector len(value) no na GT{5} // .value = 3 170 | test_err(test_vec(x6 = c(6, NA, 8))) 171 | test_err(test_vec(x6 = c(5, 7, 8))) 172 | test_err(test_vec(x6 = c(7, 8))) 173 | 174 | 175 | #### 176 | #### ...list #### 177 | #### 178 | 179 | # len 180 | 181 | test_list = function(x1, x2, x3){ 182 | check_arg(x1, "list") 183 | check_arg(x2, "list len(2)") 184 | check_arg(x3, "list len(value)", .value = 2) 185 | invisible(NULL) 186 | } 187 | 188 | 189 | # 190 | # should work 191 | # 192 | 193 | # x1: list len 0 194 | test_list(x1 = iris) 195 | test_list(x1 = list()) 196 | 197 | # x2: list len(2) 198 | test_list(x2 = iris[1:2]) 199 | test_list(x2 = list(a = 5, b = 6)) 200 | 201 | # x3: list len(value) 202 | test_list(x3 = list(a = 5, b = 6)) 203 | 204 | 205 | # 206 | # should **not** work 207 | # 208 | 209 | # x1: list 210 | test_err(test_list(x1 = 1:5)) 211 | 212 | # x2: list len(2) 213 | test_err(test_list(x2 = iris[1])) 214 | 215 | # x3: list len(value) 216 | test_err(test_list(x3 = list(a = 5, b = 6, c = 9))) 217 | 218 | 219 | #### 220 | #### ...data.frame #### 221 | #### 222 | 223 | # nrow / ncol / no na / vdata.frame 224 | 225 | test_df = function(x1, x2){ 226 | check_arg(x1, "data.frame nrow(10,) ncol(,2)") 227 | check_arg(x2, "vdata.frame no na") 228 | invisible(NULL) 229 | } 230 | 231 | 232 | # 233 | # should work 234 | # 235 | 236 | # x1: data.frame nrow(10,) ncol(,2) 237 | test_df(x1 = iris[, 1:2]) 238 | test_df(x1 = data.frame(a = 1:10)) 239 | 240 | # x2: vdata.frame no na 241 | test_df(x2 = iris[, 1:2]) 242 | test_df(x2 = 1:5) 243 | test_df(x2 = iris$Sepal.Length) 244 | 245 | 246 | # 247 | # should **not** work 248 | # 249 | 250 | # x1: data.frame nrow(10,) ncol(,2) 251 | test_err(test_df(x1 = iris[1:5, 1:2])) 252 | test_err(test_df(x1 = iris)) 253 | 254 | # x2: vdata.frame no na 255 | test_err(test_df(x2 = data.frame(a = c(NA, 1:5)))) 256 | test_err(test_df(x2 = c(NA, 1:5))) 257 | 258 | 259 | 260 | #### 261 | #### ...matrix #### 262 | #### 263 | 264 | # type / no na / nrow / ncol / square / equality / vmatrix 265 | 266 | test_mat = function(x1, x2, x3, x4, x5){ 267 | check_arg(x1, "square numeric matrix GT{0}") 268 | check_arg(x2, "vmatrix no na nrow(10, )") 269 | invisible(NULL) 270 | } 271 | 272 | 273 | # 274 | # should work 275 | # 276 | 277 | # x1: square numeric matrix GT{0} 278 | test_mat(x1 = matrix(5, 5, 5)) 279 | test_mat(x1 = matrix(c(NA, 5), 6, 6)) 280 | 281 | # x2: vmatrix no na nrow(10, ) 282 | test_mat(x2 = 1:10) 283 | test_mat(x2 = matrix(rnorm(20*25), 20, 25)) 284 | 285 | 286 | # 287 | # should **not** work 288 | # 289 | 290 | # x1: square numeric matrix GT{0} 291 | test_err(test_mat(x1 = matrix(-5, 5, 5))) 292 | test_err(test_mat(x1 = matrix(5, 6, 5))) 293 | test_err(test_mat(x1 = matrix("bonjour", 6, 5))) 294 | test_err(test_mat(x1 = 1)) 295 | 296 | # x2: vmatrix no na nrow(10, ) 297 | test_err(test_mat(x2 = 1:5)) 298 | test_err(test_mat(x2 = c(NA, 1:10))) 299 | test_err(test_mat(x2 = matrix(55, 5, 20))) 300 | 301 | #### 302 | #### ...formula #### 303 | #### 304 | 305 | # os / ts / left / right 306 | 307 | test_fml = function(x1, x2, x3, x4, x5){ 308 | check_arg(x1, "ts formula") 309 | check_arg(x2, "os formula right(2)") 310 | check_arg(x3, "formula left(, 1)") 311 | check_arg(x4, "formula var(data)", .data = iris) 312 | check_arg(x5, "formula var(env)") 313 | invisible(NULL) 314 | } 315 | 316 | 317 | # 318 | # should work 319 | # 320 | 321 | # x1: ts formula 322 | test_fml(x1 = a ~ b + c) 323 | test_fml(x1 = a | b ~ b + c | d + e) 324 | 325 | # x2: os formula right(2) 326 | test_fml(x2 = ~ b + c | d) 327 | 328 | # x3: formula left(, 1) 329 | test_fml(x3 = a ~ b + c) 330 | test_fml(x3 = a ~ 1 | 0 | z) 331 | 332 | # x4: formula var(data), .data = iris 333 | test_fml(x4 = Petal.Length ~ Sepal.Length | Species) 334 | 335 | # x5: formula var(env) 336 | x = y = 5 337 | test_fml(x5 = y ~ x) 338 | 339 | # 340 | # should **not** work 341 | # 342 | 343 | # x1: ts formula 344 | test_err(test_fml(x1 = iris)) 345 | test_err(test_fml(x1 = 1:5)) 346 | test_err(test_fml(x1 = ~ b + c)) 347 | 348 | # x2: os formula right(2) 349 | test_err(test_fml(x2 = ~ b + c | d | e)) 350 | test_err(test_fml(x2 = a ~ b + c | d)) 351 | 352 | # x3: formula left(, 1) 353 | test_err(test_fml(x3 = a | b ~ b + c)) 354 | 355 | # x4: formula var(data), .data = iris 356 | test_err(test_fml(x4 = Petol.Length ~ Sepal.Length | Species)) 357 | test_err(test_fml(x4 = Petol.Length ~ Sepal.Length | species)) 358 | 359 | # x5: formula var(env) 360 | x = y = 5 361 | test_err(test_fml(x5 = y ~ xxx)) 362 | 363 | 364 | #### 365 | #### ...charin #### 366 | #### 367 | 368 | # multi 369 | 370 | test_charin = function(x1, x2){ 371 | check_arg(x1, "charin", .choices = c("bon", "jour", "so", "leil")) 372 | check_arg(x2, "multi charin(bon, jour, so, leil)") 373 | invisible(NULL) 374 | } 375 | 376 | 377 | # 378 | # should work 379 | # 380 | 381 | # x1: charin 382 | test_charin(x1 = "bon") 383 | test_charin(x1 = "jour") 384 | 385 | # x2: strict charin 386 | test_charin(x2 = c("bon", "jour")) 387 | 388 | # 389 | # should **not** work 390 | # 391 | 392 | # x1: charin 393 | test_err(test_charin(x1 = "bonj")) 394 | test_err(test_charin(x1 = "Bon")) 395 | test_err(test_charin(x1 = c("bon", "jour"))) 396 | 397 | # x2: multi charin 398 | test_err(test_charin(x2 = 55)) 399 | 400 | 401 | #### 402 | #### ...match #### 403 | #### 404 | 405 | # strict / multi / different inits 406 | 407 | test_match = function(x1 = c("bon", "jour", "soleil"), x2, x3){ 408 | mc = match.call() 409 | check_set_arg(x1, "match") 410 | if("x1" %in% names(mc)) return(x1) 411 | 412 | check_set_arg(x2, "strict match(bon, jour, soleil)") 413 | if("x2" %in% names(mc)) return(x2) 414 | 415 | check_set_arg(x3, "multi match", .choices = c("bon", "jour", "soleil")) 416 | if("x3" %in% names(mc)) return(x3) 417 | 418 | return(x1) 419 | } 420 | 421 | 422 | # 423 | # should work 424 | # 425 | 426 | # x1: match 427 | test_match() == "bon" 428 | test_match(x1 = "jour") == "jour" 429 | test_match(x1 = "s") == "soleil" 430 | test_match(x1 = "So") == "soleil" 431 | test_match(x1 = "Bo") == "bon" 432 | 433 | # x2: strict match(bon, jour, soleil) 434 | test_match(x2 = "jour") == "jour" 435 | test_match(x2 = "s") == "soleil" 436 | 437 | # x3: multi match, .choices = c("bon", "jour", "soleil") 438 | test_match(x3 = c("jour", "bo")) %in% c("bon", "jour") 439 | 440 | # 441 | # should **not** work 442 | # 443 | 444 | # x1: match 445 | test_err(test_match(x1 = "jouro")) 446 | test_err(test_match(x1 = 55)) 447 | test_err(test_match(x1 = ".+")) 448 | 449 | # x2: strict match(bon, jour, soleil) 450 | test_err(test_match(x2 = "Jour")) 451 | test_err(test_match(x2 = c("jour", "b"))) 452 | 453 | # x3: multi match, .choices = c("bon", "jour", "soleil") 454 | test_err(test_match(x3 = NA)) 455 | 456 | 457 | #### 458 | #### ...NA #### 459 | #### 460 | 461 | test_na = function(x1){ 462 | check_arg(x1, "NA") 463 | invisible(NULL) 464 | } 465 | 466 | 467 | # 468 | # should work 469 | # 470 | 471 | # x1: NA 472 | test_na(x1 = NA) 473 | 474 | # 475 | # should **not** work 476 | # 477 | 478 | # x1: NA 479 | test_err(test_na(x1 = 5)) 480 | test_err(test_na(x1 = 5:55)) 481 | test_err(test_na(x1 = iris)) 482 | test_err(test_na(x1 = c(NA, 2))) 483 | test_err(test_na(x1 = lis(NA))) 484 | 485 | 486 | #### 487 | #### ...function #### 488 | #### 489 | 490 | # arg 491 | 492 | test_fun = function(x1, x2, x3, x4, x5){ 493 | check_arg(x1, "function") 494 | check_arg(x2, "function arg(1,)") 495 | invisible(NULL) 496 | } 497 | 498 | 499 | # 500 | # should work 501 | # 502 | 503 | # x1: function 504 | test_fun(x1 = sum) 505 | 506 | # x2: function arg(1,) 507 | test_fun(x2 = merge) 508 | 509 | # 510 | # should **not** work 511 | # 512 | 513 | # x1: function 514 | test_err(test_fun(x1 = 1:5)) 515 | 516 | # x2: function arg(1,) 517 | test_err(test_fun(x2 = function() 5)) 518 | 519 | 520 | #### 521 | #### len #### 522 | #### 523 | 524 | 525 | test_len = function(x1, x2, x3, x4, x5){ 526 | a = 0 527 | b = 8 528 | check_arg(x1, "numeric vector GT{a} LT{b}") 529 | check_arg(x2, "vector(numeric, character)") 530 | check_arg(x3, "numeric vector len(, 2)") 531 | check_arg(x4, "vector(numeric, character) len(1)") 532 | check_arg(x5, "strict integer vector no na len(1, )") 533 | invisible(NULL) 534 | } 535 | 536 | # no error 537 | test_len(character(0), NULL, integer(0)) 538 | test_len(c(NA, 3, 4), NA_integer_, c(NA_character_, NA_character_)) 539 | test_len(x4 = 5, x5 = 3L) 540 | 541 | # error 542 | 543 | test_err(test_len(x1 = -1)) 544 | test_err(test_len(x3 = 3:8)) 545 | test_err(test_len(x4 = character(0))) 546 | test_err(test_len(x5 = character(0))) 547 | 548 | 549 | 550 | 551 | 552 | 553 | 554 | 555 | 556 | 557 | 558 | 559 | 560 | 561 | 562 | 563 | 564 | 565 | 566 | 567 | 568 | 569 | 570 | 571 | 572 | 573 | 574 | 575 | 576 | 577 | 578 | 579 | 580 | 581 | 582 | 583 | 584 | 585 | 586 | 587 | 588 | 589 | 590 | 591 | 592 | 593 | 594 | 595 | 596 | 597 | 598 | 599 | 600 | 601 | 602 | -------------------------------------------------------------------------------- /vignettes/images/check_arg_call.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lrberge/dreamerr/ee0086ecfeafd932a2d8600511e67862e9c02c08/vignettes/images/check_arg_call.png -------------------------------------------------------------------------------- /vignettes/images/forming_a_type.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/lrberge/dreamerr/ee0086ecfeafd932a2d8600511e67862e9c02c08/vignettes/images/forming_a_type.png --------------------------------------------------------------------------------