mirror of
https://github.com/msberends/AMR.git
synced 2026-03-19 19:02:27 +01:00
Pre-evaluate inline expressions, add format_inline_(), fix print.ab
- All bare {variable}/{expression} in message_()/warning_()/stop_() calls
are now pre-evaluated via paste0(), so users without cli/glue never see
raw template syntax (mo_source.R, first_isolate.R, join_microorganisms.R,
antibiogram.R, atc_online.R)
- Add format_inline_() helper: formats a cli-markup string and returns it
(not emits it), using cli::format_inline() when available and cli_to_plain()
otherwise
- Rewrite .onAttach to use format_inline_() for all packageStartupMessage
calls; also adds {.topic} link and {.code} markup for option names
- print.ab: pre-evaluate function_name via paste0 (no .envir needed),
apply highlight_code() to each example bullet for R syntax highlighting
- join_microorganisms: pre-evaluate {type} and {nrow(...)} expressions
https://claude.ai/code/session_01XHWLohiSTdZvCutwD7ag2b
This commit is contained in:
@@ -1,5 +1,5 @@
|
|||||||
Package: AMR
|
Package: AMR
|
||||||
Version: 3.0.1.9037
|
Version: 3.0.1.9038
|
||||||
Date: 2026-03-19
|
Date: 2026-03-19
|
||||||
Title: Antimicrobial Resistance Data Analysis
|
Title: Antimicrobial Resistance Data Analysis
|
||||||
Description: Functions to simplify and standardise antimicrobial resistance (AMR)
|
Description: Functions to simplify and standardise antimicrobial resistance (AMR)
|
||||||
|
|||||||
4
NEWS.md
4
NEWS.md
@@ -1,4 +1,4 @@
|
|||||||
# AMR 3.0.1.9037
|
# AMR 3.0.1.9038
|
||||||
|
|
||||||
### New
|
### New
|
||||||
* Integration with the **tidymodels** framework to allow seamless use of SIR, MIC and disk data in modelling pipelines via `recipes`
|
* Integration with the **tidymodels** framework to allow seamless use of SIR, MIC and disk data in modelling pipelines via `recipes`
|
||||||
@@ -31,6 +31,8 @@
|
|||||||
|
|
||||||
### Updates
|
### Updates
|
||||||
* Replaced all bare backtick-quoted text in `message_()`, `warning_()`, and `stop_()` calls with proper cli inline markup (`{.arg}`, `{.cls}`, `{.fun}`, `{.pkg}`, `{.code}`); rewrote `print.ab` to use a cli named-vector with `*` bullets and code highlighting when cli is available
|
* Replaced all bare backtick-quoted text in `message_()`, `warning_()`, and `stop_()` calls with proper cli inline markup (`{.arg}`, `{.cls}`, `{.fun}`, `{.pkg}`, `{.code}`); rewrote `print.ab` to use a cli named-vector with `*` bullets and code highlighting when cli is available
|
||||||
|
* Added `format_inline_()` helper that formats a cli-markup string and returns it (rather than emitting it), using `cli::format_inline()` when available and `cli_to_plain()` otherwise; used this in `.onAttach` to replace the duplicated cli/non-cli startup message pattern
|
||||||
|
* All inline `{variable}` / `{expression}` in messaging calls are now pre-evaluated via `paste0()`, so users without cli or glue never see raw template syntax
|
||||||
* `mdro()` now infers resistance for a _missing_ base drug column from an _available_ corresponding drug+inhibitor combination showing resistance (e.g., piperacillin is absent but required, while piperacillin/tazobactam available and resistant). Can be set with the new argument `infer_from_combinations`, which defaults to `TRUE` (#209). Note that this can yield a higher MDRO detection (which is a good thing as it has become more reliable).
|
* `mdro()` now infers resistance for a _missing_ base drug column from an _available_ corresponding drug+inhibitor combination showing resistance (e.g., piperacillin is absent but required, while piperacillin/tazobactam available and resistant). Can be set with the new argument `infer_from_combinations`, which defaults to `TRUE` (#209). Note that this can yield a higher MDRO detection (which is a good thing as it has become more reliable).
|
||||||
* `susceptibility()` and `resistance()` gained the argument `guideline`, which defaults to EUCAST, for interpreting the 'I' category correctly.
|
* `susceptibility()` and `resistance()` gained the argument `guideline`, which defaults to EUCAST, for interpreting the 'I' category correctly.
|
||||||
* Added to the `antimicrobials` data set: cefepime/taniborbactam (`FTA`), ceftibuten/avibactam (`CTA`), clorobiocin (`CLB`), kasugamycin (`KAS`), ostreogrycin (`OST`), taniborbactam (`TAN`), thiostrepton (`THS`), xeruborbactam (`XER`), and zorbamycin (`ZOR`)
|
* Added to the `antimicrobials` data set: cefepime/taniborbactam (`FTA`), ceftibuten/avibactam (`CTA`), clorobiocin (`CLB`), kasugamycin (`KAS`), ostreogrycin (`OST`), taniborbactam (`TAN`), thiostrepton (`THS`), xeruborbactam (`XER`), and zorbamycin (`ZOR`)
|
||||||
|
|||||||
@@ -390,6 +390,19 @@ highlight_code <- function(code) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# Format a cli-markup string for output, with a plain-text fallback when cli is
|
||||||
|
# unavailable. Unlike message_() / warning_() / stop_(), this function returns
|
||||||
|
# the formatted string rather than emitting it, so it can be passed to any
|
||||||
|
# output function (e.g. packageStartupMessage()).
|
||||||
|
format_inline_ <- function(...) {
|
||||||
|
msg <- paste0(c(...), collapse = "")
|
||||||
|
if (pkg_is_available("cli", min_version = "3.0.0")) {
|
||||||
|
cli::format_inline(msg)
|
||||||
|
} else {
|
||||||
|
cli_to_plain(msg, envir = parent.frame())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
import_fn <- function(name, pkg, error_on_fail = TRUE) {
|
import_fn <- function(name, pkg, error_on_fail = TRUE) {
|
||||||
if (isTRUE(error_on_fail)) {
|
if (isTRUE(error_on_fail)) {
|
||||||
stop_ifnot_installed(pkg)
|
stop_ifnot_installed(pkg)
|
||||||
|
|||||||
19
R/ab.R
19
R/ab.R
@@ -552,17 +552,14 @@ print.ab <- function(x, ...) {
|
|||||||
if (!is.null(attributes(x)$amr_selector)) {
|
if (!is.null(attributes(x)$amr_selector)) {
|
||||||
function_name <- attributes(x)$amr_selector
|
function_name <- attributes(x)$amr_selector
|
||||||
if (pkg_is_available("cli", min_version = "3.0.0")) {
|
if (pkg_is_available("cli", min_version = "3.0.0")) {
|
||||||
cli::cli_inform(
|
cli::cli_inform(c(
|
||||||
c(
|
"i" = paste0("This {.cls ab} vector was retrieved using {.fun ", function_name, "}, which should normally be used inside a {.pkg dplyr} verb or {.code data.frame} call, e.g.:"),
|
||||||
"i" = "This {.cls ab} vector was retrieved using {.fun {function_name}}, which should normally be used inside a {.pkg dplyr} verb or {.code data.frame} call, e.g.:",
|
"*" = highlight_code(paste0("your_data %>% select(", function_name, "()")),
|
||||||
"*" = "{.code your_data %>% select({function_name}())}",
|
"*" = highlight_code(paste0("your_data %>% select(column_a, column_b, ", function_name, "()")),
|
||||||
"*" = "{.code your_data %>% select(column_a, column_b, {function_name}())}",
|
"*" = highlight_code(paste0("your_data %>% filter(any(", function_name, "() == \"R\"))")),
|
||||||
"*" = "{.code your_data %>% filter(any({function_name}() == \"R\"))}",
|
"*" = highlight_code(paste0("your_data[, ", function_name, "()]")),
|
||||||
"*" = "{.code your_data[, {function_name}()]}",
|
"*" = highlight_code(paste0("your_data[, c(\"column_a\", \"column_b\", ", function_name, "())]"))
|
||||||
"*" = "{.code your_data[, c(\"column_a\", \"column_b\", {function_name}())]}"
|
))
|
||||||
),
|
|
||||||
.envir = environment()
|
|
||||||
)
|
|
||||||
} else {
|
} else {
|
||||||
message(word_wrap(paste0(
|
message(word_wrap(paste0(
|
||||||
"This 'ab' vector was retrieved using `", function_name, "()`, which should normally be used inside a dplyr verb or data.frame call, e.g.:\n",
|
"This 'ab' vector was retrieved using `", function_name, "()`, which should normally be used inside a dplyr verb or data.frame call, e.g.:\n",
|
||||||
|
|||||||
@@ -619,7 +619,7 @@ antibiogram.default <- function(x,
|
|||||||
out$n_susceptible <- out$n_susceptible + out$I + out$SDD
|
out$n_susceptible <- out$n_susceptible + out$I + out$SDD
|
||||||
}
|
}
|
||||||
if (all(out$n_tested < minimum, na.rm = TRUE) && wisca == FALSE) {
|
if (all(out$n_tested < minimum, na.rm = TRUE) && wisca == FALSE) {
|
||||||
warning_("All combinations had less than {.arg minimum} = {minimum} results, returning an empty antibiogram")
|
warning_("All combinations had less than {.arg minimum} = ", minimum, " results, returning an empty antibiogram")
|
||||||
return(as_original_data_class(data.frame(), class(x), extra_class = "antibiogram"))
|
return(as_original_data_class(data.frame(), class(x), extra_class = "antibiogram"))
|
||||||
} else if (any(out$n_tested < minimum, na.rm = TRUE)) {
|
} else if (any(out$n_tested < minimum, na.rm = TRUE)) {
|
||||||
mins <- sum(out$n_tested < minimum, na.rm = TRUE)
|
mins <- sum(out$n_tested < minimum, na.rm = TRUE)
|
||||||
@@ -627,7 +627,7 @@ antibiogram.default <- function(x,
|
|||||||
out <- out %pm>%
|
out <- out %pm>%
|
||||||
subset(n_tested >= minimum)
|
subset(n_tested >= minimum)
|
||||||
if (isTRUE(info) && mins > 0) {
|
if (isTRUE(info) && mins > 0) {
|
||||||
message_("NOTE: {mins} combinations had less than {.arg minimum} = {minimum} results and were ignored")
|
message_("NOTE: ", mins, " combinations had less than {.arg minimum} = ", minimum, " results and were ignored")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -180,7 +180,7 @@ atc_online_property <- function(atc_code,
|
|||||||
colnames(out) <- gsub("^atc.*", "atc", tolower(colnames(out)))
|
colnames(out) <- gsub("^atc.*", "atc", tolower(colnames(out)))
|
||||||
|
|
||||||
if (length(out) == 0) {
|
if (length(out) == 0) {
|
||||||
message_("in {.help [{.fun atc_online_property}](AMR::atc_online_property)}: no properties found for ATC ", atc_code[i], ". Please check {.href {atc_url} this WHOCC webpage}.")
|
message_("in {.help [{.fun atc_online_property}](AMR::atc_online_property)}: no properties found for ATC ", atc_code[i], ". Please check {.href ", atc_url, " this WHOCC webpage}.")
|
||||||
returnvalue[i] <- NA
|
returnvalue[i] <- NA
|
||||||
next
|
next
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -373,7 +373,7 @@ first_isolate <- function(x = NULL,
|
|||||||
if (!is.null(specimen_group)) {
|
if (!is.null(specimen_group)) {
|
||||||
check_columns_existance(col_specimen, x)
|
check_columns_existance(col_specimen, x)
|
||||||
if (isTRUE(info) && message_not_thrown_before("first_isolate", "excludingspecimen")) {
|
if (isTRUE(info) && message_not_thrown_before("first_isolate", "excludingspecimen")) {
|
||||||
message_("Excluding other than specimen group '{specimen_group}'")
|
message_("Excluding other than specimen group '", specimen_group, "'")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!is.null(col_keyantimicrobials)) {
|
if (!is.null(col_keyantimicrobials)) {
|
||||||
@@ -430,7 +430,8 @@ first_isolate <- function(x = NULL,
|
|||||||
}
|
}
|
||||||
if (length(c(row.start:row.end)) == pm_n_distinct(x[c(row.start:row.end), col_mo, drop = TRUE])) {
|
if (length(c(row.start:row.end)) == pm_n_distinct(x[c(row.start:row.end), col_mo, drop = TRUE])) {
|
||||||
if (isTRUE(info)) {
|
if (isTRUE(info)) {
|
||||||
message_("=> Found {.strong {length(c(row.start:row.end))} first isolates}, as all isolates were different microbial species",
|
n_rows <- length(c(row.start:row.end))
|
||||||
|
message_("=> Found {.strong ", n_rows, " first isolates}, as all isolates were different microbial species",
|
||||||
as_note = FALSE
|
as_note = FALSE
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -537,7 +538,7 @@ first_isolate <- function(x = NULL,
|
|||||||
paste0('"', x, '"')
|
paste0('"', x, '"')
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
message_("\nGroup: {toString(paste0(names(group), ' = ', group))}\n",
|
message_("\nGroup: ", toString(paste0(names(group), " = ", group)), "\n",
|
||||||
as_note = FALSE
|
as_note = FALSE
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -145,7 +145,7 @@ join_microorganisms <- function(type, x, by, suffix, ...) {
|
|||||||
} else {
|
} else {
|
||||||
stop_if(is.null(by), "no column with microorganism names or codes found, set this column with {.arg by}", call = -2)
|
stop_if(is.null(by), "no column with microorganism names or codes found, set this column with {.arg by}", call = -2)
|
||||||
}
|
}
|
||||||
message_('Joining, by = "{by}"', as_note = FALSE) # message same as dplyr::join functions
|
message_("Joining, by = \"", by, "\"", as_note = FALSE) # message same as dplyr::join functions
|
||||||
}
|
}
|
||||||
if (!all(x[, by, drop = TRUE] %in% AMR_env$MO_lookup$mo, na.rm = TRUE)) {
|
if (!all(x[, by, drop = TRUE] %in% AMR_env$MO_lookup$mo, na.rm = TRUE)) {
|
||||||
x$join.mo <- as.mo(x[, by, drop = TRUE])
|
x$join.mo <- as.mo(x[, by, drop = TRUE])
|
||||||
@@ -185,7 +185,7 @@ join_microorganisms <- function(type, x, by, suffix, ...) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (type %like% "full|left|right|inner" && NROW(joined) > NROW(x)) {
|
if (type %like% "full|left|right|inner" && NROW(joined) > NROW(x)) {
|
||||||
warning_("in {.fun {type}_microorganisms}: the newly joined data set contains {nrow(joined) - nrow(x)} rows more than the number of rows of {.arg x}.")
|
warning_("in {.fun ", type, "_microorganisms}: the newly joined data set contains ", nrow(joined) - nrow(x), " rows more than the number of rows of {.arg x}.")
|
||||||
}
|
}
|
||||||
|
|
||||||
as_original_data_class(joined, class(x.bak)) # will remove tibble groups
|
as_original_data_class(joined, class(x.bak)) # will remove tibble groups
|
||||||
|
|||||||
@@ -249,7 +249,7 @@ get_mo_source <- function(destination = getOption("AMR_mo_source", "~/mo_source.
|
|||||||
current_ext <- regexpr("\\.([[:alnum:]]+)$", destination)
|
current_ext <- regexpr("\\.([[:alnum:]]+)$", destination)
|
||||||
current_ext <- ifelse(current_ext > -1L, substring(destination, current_ext + 1L), "")
|
current_ext <- ifelse(current_ext > -1L, substring(destination, current_ext + 1L), "")
|
||||||
vowel <- ifelse(current_ext %like% "^[AEFHILMNORSX]", "n", "")
|
vowel <- ifelse(current_ext %like% "^[AEFHILMNORSX]", "n", "")
|
||||||
stop_("The AMR mo source must be an RDS file, not a{vowel} {toupper(current_ext)} file. If \"{basename(destination)}\" was meant as your input file, use {.help [{.fun set_mo_source}](AMR::set_mo_source)} on this file. In any case, the option {.code AMR_mo_source} must be set to another path.")
|
stop_("The AMR mo source must be an RDS file, not a", vowel, " ", toupper(current_ext), " file. If \"", basename(destination), "\" was meant as your input file, use {.help [{.fun set_mo_source}](AMR::set_mo_source)} on this file. In any case, the option {.code AMR_mo_source} must be set to another path.")
|
||||||
}
|
}
|
||||||
if (is.null(AMR_env$mo_source)) {
|
if (is.null(AMR_env$mo_source)) {
|
||||||
AMR_env$mo_source <- readRDS_AMR(path.expand(destination))
|
AMR_env$mo_source <- readRDS_AMR(path.expand(destination))
|
||||||
|
|||||||
20
R/zzz.R
20
R/zzz.R
@@ -116,42 +116,40 @@ AMR_env$cross_icon <- if (isTRUE(base::l10n_info()$`UTF-8`)) "\u00d7" else "x"
|
|||||||
|
|
||||||
.onAttach <- function(libname, pkgname) {
|
.onAttach <- function(libname, pkgname) {
|
||||||
if (interactive() && is.null(getOption("AMR_guideline"))) {
|
if (interactive() && is.null(getOption("AMR_guideline"))) {
|
||||||
packageStartupMessage(
|
packageStartupMessage(format_inline_(
|
||||||
word_wrap(
|
"Assuming ", AMR::clinical_breakpoints$guideline[1], " as the default AMR guideline, see {.topic [AMR-options](AMR::AMR-options)} to change this."
|
||||||
"Assuming ", AMR::clinical_breakpoints$guideline[1], " as the default AMR guideline, see `?AMR-options` to change this."
|
))
|
||||||
)
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
# if custom ab option is available, load it
|
# if custom ab option is available, load it
|
||||||
if (!is.null(getOption("AMR_custom_ab")) && file.exists(getOption("AMR_custom_ab", default = ""))) {
|
if (!is.null(getOption("AMR_custom_ab")) && file.exists(getOption("AMR_custom_ab", default = ""))) {
|
||||||
if (getOption("AMR_custom_ab") %unlike% "[.]rds$") {
|
if (getOption("AMR_custom_ab") %unlike% "[.]rds$") {
|
||||||
packageStartupMessage("The file with custom antimicrobials must be an RDS file. Set the option `AMR_custom_ab` to another path.")
|
packageStartupMessage(format_inline_("The file with custom antimicrobials must be an RDS file. Set the option {.code AMR_custom_ab} to another path."))
|
||||||
} else {
|
} else {
|
||||||
packageStartupMessage("Adding custom antimicrobials from '", getOption("AMR_custom_ab"), "'...", appendLF = FALSE)
|
packageStartupMessage(format_inline_("Adding custom antimicrobials from '", getOption("AMR_custom_ab"), "'..."), appendLF = FALSE)
|
||||||
x <- readRDS_AMR(getOption("AMR_custom_ab"))
|
x <- readRDS_AMR(getOption("AMR_custom_ab"))
|
||||||
tryCatch(
|
tryCatch(
|
||||||
{
|
{
|
||||||
suppressWarnings(suppressMessages(add_custom_antimicrobials(x)))
|
suppressWarnings(suppressMessages(add_custom_antimicrobials(x)))
|
||||||
packageStartupMessage("OK.")
|
packageStartupMessage("OK.")
|
||||||
},
|
},
|
||||||
error = function(e) packageStartupMessage("Failed: ", conditionMessage(e))
|
error = function(e) packageStartupMessage(format_inline_("Failed: ", conditionMessage(e)))
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
# if custom mo option is available, load it
|
# if custom mo option is available, load it
|
||||||
if (!is.null(getOption("AMR_custom_mo")) && file.exists(getOption("AMR_custom_mo", default = ""))) {
|
if (!is.null(getOption("AMR_custom_mo")) && file.exists(getOption("AMR_custom_mo", default = ""))) {
|
||||||
if (getOption("AMR_custom_mo") %unlike% "[.]rds$") {
|
if (getOption("AMR_custom_mo") %unlike% "[.]rds$") {
|
||||||
packageStartupMessage("The file with custom microorganisms must be an RDS file. Set the option `AMR_custom_mo` to another path.")
|
packageStartupMessage(format_inline_("The file with custom microorganisms must be an RDS file. Set the option {.code AMR_custom_mo} to another path."))
|
||||||
} else {
|
} else {
|
||||||
packageStartupMessage("Adding custom microorganisms from '", getOption("AMR_custom_mo"), "'...", appendLF = FALSE)
|
packageStartupMessage(format_inline_("Adding custom microorganisms from '", getOption("AMR_custom_mo"), "'..."), appendLF = FALSE)
|
||||||
x <- readRDS_AMR(getOption("AMR_custom_mo"))
|
x <- readRDS_AMR(getOption("AMR_custom_mo"))
|
||||||
tryCatch(
|
tryCatch(
|
||||||
{
|
{
|
||||||
suppressWarnings(suppressMessages(add_custom_microorganisms(x)))
|
suppressWarnings(suppressMessages(add_custom_microorganisms(x)))
|
||||||
packageStartupMessage("OK.")
|
packageStartupMessage("OK.")
|
||||||
},
|
},
|
||||||
error = function(e) packageStartupMessage("Failed: ", conditionMessage(e))
|
error = function(e) packageStartupMessage(format_inline_("Failed: ", conditionMessage(e)))
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user