spsUtil


SPS framework come with a plenty of useful general R utility functions, like pretty logging, package namespace checking, URL checking, and more.

Since SPS 1.1, these functions are separated into a supporting package called spsUtil (systemPipeShiny Utility). You can install it from CRAN.

Installation

Read the developer tools main page, not repeating here.

Functions reference manual

In documents, we only highlight some important functions. Please read the reference manuals for details of every function.

Function highlights

library(spsUtil)

logging with msg

basic

Often times in an R function, we want to use some text to inform users the status and message. We can use functions like message, warning, stop to generate different levels of information.

{spsUtil} provides some more informative and prettier ways to generate these kind of messages.

msg("my message")
## [INFO] 2021-04-12 11:49:35 my message

You can see it starts with a level information, then a time stamp, and follows the actual message. By default, it uses the INFO level, and you can change to whatever level you want. However, there are 3 keywords that have special meaning.

Levels

  • INFO: equals message method in native R
  • WARNING: generates warnings the same as warning function
  • ERROR: generates error the same as stop function and will prevent downstream code get evaluated.

If the level is other than these 3, there is no special meaning in R, just cat the message out.

msg("I am info", level = "INFO")
## [INFO] 2021-04-12 11:49:35 I am info
msg("I am warning", level = "warning") # not case sensitive
## Warning: [WARNING] 2021-04-12 11:49:35 I am warning
msg("I am error", level = "ERROR")
## Error: 
[ERROR] 2021-04-12 11:49:35 I am error
msg("I am random level", level = "MY LEVEL")
## [MY LEVEL] 2021-04-12 11:49:35 I am random level

Prefix

For the 3 key levels, you can specify the prefix in front of the level text to over write the default level text INFO, WARNING, or ERROR

msg("I am info", level = "INFO", info_text = "NEW-INFO")
## [NEW-INFO] 2021-04-12 11:49:35 I am info
msg("I am warning", level = "warning", warning_text = "MY-WARNING")
## Warning: [MY-WARNING] 2021-04-12 11:49:35 I am warning
msg("I am error", level = "ERROR", error_text = "STOP")
## Error: 
[STOP] 2021-04-12 11:49:35 I am error

Colors

Colors are automatically enabled if it is supported. If you try all code above in your terminal or Rstudio, they all have colors. In Rmd, to enable the color, you need to add the following code chunk. You also need to install the fansi package.

```{r echo=FALSE, results='asis'} 
options(crayon.enabled = TRUE)
old_hooks <- fansi::set_knit_hooks(knitr::knit_hooks, which = c("output", "message", "error", "warning"))
```
msg("I am info", level = "INFO", info_text = "NEW-INFO")
## [NEW-INFO] 2021-04-12 11:49:35 I am info

The 3 key levels has default colors:

  • INFO: blue
  • WARNING: orange
  • ERROR: red

You can specify colors for your own levels

msg("I am warning", level = "warning") ## not super orange in Rmd translation -_-=
## Warning: [WARNING] 2021-04-12 11:49:35 I am warning
msg("I am error", level = "error")
## Error: 
[ERROR] 2021-04-12 11:49:35 I am error
msg("oh yeah", level = "SUCCESS", .other_color = "green")
## [SUCCESS] 2021-04-12 11:49:35 oh yeah
msg("oh no", level = "FAIL", .other_color = "purple")
## [FAIL] 2021-04-12 11:49:35 oh no

Wrapper

You can use this logging function in your own projects by wrapping it inside a upper level function, like what we do for spsinfo, spswarn, spserror. They have SPS- prefix added, and have some SPS global settings appended.

spsOption('use_crayon', TRUE)
spsinfo("info", verbose = TRUE) ## default `verbose` mute the message
## [SPS-INFO] 2021-04-12 11:49:35 info
spswarn("warning")
## Warning: [SPS-WARNING] 2021-04-12 11:49:35 warning
spserror("stop")
## Error: 
[SPS-ERROR] 2021-04-12 11:49:35 stop

To create a simple one for project is very easy. Assume your project is named “My Project”. You can create logging as:

mpInfo <- function(text){
  spsUtil::msg(text, info_text = "MP-INFO")
}
mpWarn <- function(text){
  spsUtil::msg(text, level = "warning", warning_text  = "MP-WARNING")
}
mpErr <- function(text){
  spsUtil::msg(text, level = "error", error_text = "MP-ERROR")
}
mpInfo("info")
## [MP-INFO] 2021-04-12 11:49:35 info
mpWarn("warning")
## Warning: [MP-WARNING] 2021-04-12 11:49:35 warning
mpErr("error")
## Error: 
[MP-ERROR] 2021-04-12 11:49:35 error

mute message with quiet

In R, you can easily mute message and warnings with suppressMessages(), and suppressWarnings(), but not so easy with print or cat methods. spsUtil::quiet enables you to mute all these methods or choose what to mute.

{
# muted
quiet(warning(123))
quiet(message(123))
quiet(print(123))
quiet(cat(123))
# not muted
quiet(warning(123), warning = FALSE)
quiet(message(123), message = FALSE)
quiet(print(123), print_cat = FALSE)
quiet(cat(123), print_cat = FALSE)
}
## Warning in force(x): 123
## 123
## [1] 123
## 123

check “empty” values with emptyIsFalse

In R, values like NA, "", NULL, length(0) is not very meaningful in condition judgment and will give you errors. Yet, R does not have a native method to handle these “empty” values in if like other languages. They are meaningful in other ways, but in conditions, we may want to turn them to FALSE.

if("") TRUE else FALSE
## Error in if ("") TRUE else FALSE: argument is not interpretable as logical
if(NULL) TRUE else FALSE
## Error in if (NULL) TRUE else FALSE: argument is of length zero
if(character(0)) TRUE else FALSE
## Error in if (character(0)) TRUE else FALSE: argument is of length zero
if(NA) TRUE else FALSE
## Error in if (NA) TRUE else FALSE: missing value where TRUE/FALSE needed

You can see they all give errors. In other languages (javascript in this example), these values are often treated as FALSE.

if (NaN) true; else false
//> false
if (undefined) true; else false
//> false
if ("") true; else false
//> false
if (null) true; else false
//> false

This is how emptyIsFalse work. If the input is one of these values, return FALSE, else TRUE

if(emptyIsFalse("")) TRUE else FALSE
## [1] FALSE
if(emptyIsFalse(NULL)) TRUE else FALSE
## [1] FALSE
if(emptyIsFalse(character(0))) TRUE else FALSE
## [1] FALSE
if(emptyIsFalse(NA)) TRUE else FALSE
## [1] FALSE

check missing packages checkNameSpace

In our functions, sometimes we want to have the users to install certain packages to enable more functionalities, like the DESeq2::lfcShrink function. Or like in a Rmd source code, before other people can rerender the document, they must install certain packages. checkNameSpace checks all required packages and returns the missing names.

checkNameSpace("random_pkg")
## Warning: [WARNING] 2021-04-12 11:49:35 These packages are missing from
## CRAN: random_pkg
## [1] "random_pkg"

You can add it to your function to or on the top of your Rmd document to inform your users the missing packages and where to install.

pkgs <- list(
  CRAN = c("pkg1", "pkg2"),
  Bioconductor = c("bio_pkg1", "bio_pkg2")
)

missing_pkg <- checkNameSpace(pkgs[[1]], from =  names(pkgs)[1])
## Warning: [WARNING] 2021-04-12 11:49:35 These packages are missing from
## CRAN: pkg1,pkg2
missing_pkg <- c(missing_pkg, checkNameSpace(pkgs[[2]], from =  names(pkgs)[2]))
## Warning: [WARNING] 2021-04-12 11:49:35 These packages are missing from
## Bioconductor: bio_pkg1,bio_pkg2
if(emptyIsFalse(missing_pkg)) stop("Install packages")
## Error in eval(expr, envir, enclos): Install packages

Or write your custom warning message:

{
missing_pkg <- mapply(function(pkg, from) {
  checkNameSpace(pkg, quietly = TRUE, from)
}, pkg = pkgs, from = names(pkgs), SIMPLIFY = FALSE)


cat(
  "Use `install.packages(c('", 
  paste0(missing_pkg[['CRAN']], collapse = "','"), 
  "'))` to install CRAN packages\n", 
  sep = ""
)
cat(
  "Use `BiocManager::install(c('", 
  paste0(missing_pkg[['Bioconductor']], collapse = "','"), 
  "'))` to install Bioconductor packages\n", 
  sep = ""
)
if(emptyIsFalse(unlist(missing_pkg))) stop("Install packages")
}
## Use `install.packages(c('pkg1','pkg2'))` to install CRAN packages
## Use `BiocManager::install(c('bio_pkg1','bio_pkg2'))` to install Bioconductor packages
## Error in eval(expr, envir, enclos): Install packages

check a URL is reachable with checkUrl

Useful if you need make some big HTTP requests.

checkUrl("https://google.com")
## [1] TRUE
checkUrl("https://randomwebsite123.com", timeout = 1)
## Warning: [WARNING] 2021-04-12 11:49:37 Bad url https://
## randomwebsite123.com
## Warning: [WARNING] 2021-04-12 11:49:37 Timeout was reached:

[randomwebsite123.com] Connection timed out after 1001 milliseconds

## [1] FALSE
Last modified 2021-03-03: updates for subpkgs no_render (56f34d5)