mirror of
https://github.com/msberends/AMR.git
synced 2026-03-24 08:42:29 +01:00
* Modernise messaging infrastructure with cli support
Rewrites message_(), warning_(), stop_() to use cli::cli_inform(),
cli::cli_warn(), and cli::cli_abort() when the cli package is available,
with a fully functional plain-text fallback for environments without cli.
Key changes:
- New cli_to_plain() helper converts cli inline markup ({.fun}, {.arg},
{.val}, {.field}, {.cls}, {.pkg}, {.href}, {.url}, etc.) to readable
plain-text equivalents for the non-cli fallback path
- word_wrap() simplified: drops add_fn, ANSI re-index algorithm, RStudio
link injection, and operator spacing hack; returns pasted input unchanged
when cli is available
- stop_() no longer references AMR_env$cli_abort; uses pkg_is_available()
directly; passes sys.call() objects to cli::cli_abort() call= argument
- Removed add_fn parameter from message_(), warning_(), and word_wrap()
- All call sites across R/ updated: add_fn arguments removed, some paste0-
based string construction converted to cli glue syntax ({.fun as.mo},
{.arg col_mo}, {n} results, etc.)
- cli already listed in Suggests; no DESCRIPTION dependency changes needed
https://claude.ai/code/session_01XHWLohiSTdZvCutwD7ag2b
* Replace {.fun} with {.help} for all exported functions in messaging
All function names referenced via {.fun …} in cli-style messages are
exported in NAMESPACE, so {.help …} is the appropriate markup — it
renders as a clickable help link rather than plain function styling.
https://claude.ai/code/session_01XHWLohiSTdZvCutwD7ag2b
* Qualify all {.help} tags with AMR:: and convert backtick ?func references
- Add AMR:: namespace prefix and trailing () to all {.help} cli markup
so they render as clickable help links (e.g. {.help AMR::as.sir}())
- Convert `?funcname` backtick-quoted help references to {.help AMR::funcname}()
in aa_helper_functions.R, custom_eucast_rules.R, interpretive_rules.R,
key_antimicrobials.R, mo.R, plotting.R, resistance_predict.R, and sir.R
- Skipped `?proportion` in sir_calc.R as 'proportion' is not exported
https://claude.ai/code/session_01XHWLohiSTdZvCutwD7ag2b
* Require cli >= 3.0.0 for cli_inform/cli_warn/cli_abort availability checks
cli_inform, cli_warn, and cli_abort were introduced in cli 3.0.0.
Add min_version = "3.0.0" (as character) to all four pkg_is_available("cli")
checks so older cli versions fall back to base R messaging.
https://claude.ai/code/session_01XHWLohiSTdZvCutwD7ag2b
* Implement cli::code_highlight() for R code examples in messages (issue #191)
Add highlight_code() helper that wraps cli::code_highlight() when cli >= 3.0.0
is available, falling back to plain code otherwise. Apply it to all inline
R code examples embedded in message/warning/stop strings across the package.
Also convert remaining backtick-quoted function and argument references in
messaging calls to proper cli markup: {.help AMR::fn}(), {.arg arg},
{.code expr}, and {.pkg pkg} throughout ab.R, ab_from_text.R, av_from_text.R,
amr_selectors.R, count.R, custom_antimicrobials.R, custom_microorganisms.R,
interpretive_rules.R, mo.R, mo_property.R, sir.R, sir_calc.R.
Fixes #191
https://claude.ai/code/session_01XHWLohiSTdZvCutwD7ag2b
* Fix {.help} markup to use correct cli link format [{.fun fn}](AMR::fn)
Replace all instances of {.help AMR::fn}() (incorrect format with manual
parentheses outside the link) with {.help [{.fun fn}](AMR::fn)} which is
the correct cli hyperlink syntax: the display text [{.fun fn}] renders the
function name with parentheses automatically, and (AMR::fn) is the link target.
Also update the plain-text fallback handler in aa_helper_functions.R to
extract the display text from the [text](topic) markdown link format,
so that non-cli environments show just the function name (e.g. `fn()`),
not the raw link markup.
Dynamic cases in amr_selectors.R and mo_property.R also updated.
https://claude.ai/code/session_01XHWLohiSTdZvCutwD7ag2b
* Add {.topic} markup for non-function help page references
Replace {.code ?AMR-options} and backtick-style ?AMR-options / ?AMR-deprecated
references with proper {.topic AMR-options} / {.topic AMR-deprecated} cli markup
in count.R, interpretive_rules.R, proportion.R, and zz_deprecated.R.
Add {.topic} fallback handler to format_message() in aa_helper_functions.R:
plain-text environments render {.topic foo} as ?foo, and the [text](topic)
link form extracts just the display text (same pattern as {.help}).
Also convert remaining backtick function/arg references in proportion.R to
{.help [{.fun ...}](AMR::...)}, {.arg}, and {.code} markup for consistency.
Note: zzz.R intentionally keeps the backtick form since its startup message
goes through packageStartupMessage() which bypasses our cli infrastructure.
https://claude.ai/code/session_01XHWLohiSTdZvCutwD7ag2b
* Fix {.topic} to use required pkg::topic format with display text
{.topic} in cli requires a package-qualified topic reference to generate
a valid x-r-help:pkg::topic URI. Bare {.topic AMR-options} produced a
malformed x-r-help:AMR-options URI (no package prefix).
Use the [display_text](pkg::topic) form throughout:
{.topic [AMR-options](AMR::AMR-options)}
{.topic [AMR-deprecated](AMR::AMR-deprecated)}
The hyphen in the topic name is fine as a URI string even though
AMR::AMR-options is not a valid R symbol expression.
The fallback handler in format_message() already handles the [text](uri)
form by extracting the display text, so plain-text output is unchanged.
https://claude.ai/code/session_01XHWLohiSTdZvCutwD7ag2b
* Fix regexec() calls: remove perl=TRUE unsupported in older R
regexec() only gained the perl argument in R 4.1.0. The CI matrix
covers oldrel-1 through oldrel-4 (R 3.x/4.0.x), so perl=TRUE caused
an 'unused argument' error on every message_() call in those
environments.
All four affected regexec() calls use POSIX-extended compatible
patterns, so dropping perl=TRUE is safe.
https://claude.ai/code/session_01XHWLohiSTdZvCutwD7ag2b
* Slim CI matrix for PRs to ubuntu-latest / r-release only
For pull requests, check-recent now runs a single job (ubuntu-latest,
r-release) via a setup job that emits the matrix as JSON. On push and
schedule the full matrix is unchanged (devel + release on all OSes,
oldrel-1 through oldrel-4).
Also removed the pull_request trigger from check-recent-dev-pkgs; the
dev-packages check only needs to run on push/schedule.
https://claude.ai/code/session_01XHWLohiSTdZvCutwD7ag2b
* Restrict dev-versions and old-tinytest CI to main branch only
Both workflows were triggering on every push to every branch.
Narrowed push trigger to [main] so they only run after merging,
not on every feature/PR branch push.
https://claude.ai/code/session_01XHWLohiSTdZvCutwD7ag2b
* Update NEWS.md to continuous log + add concise style rules to CLAUDE.md
NEWS.md is now a single continuous log under one heading per dev series,
not a new section per version bump. CLAUDE.md documents: only replace
line 1 (heading), append new entries, keep them extremely concise with
no trailing full stop.
Merged 9035 and 9036 entries into one section; condensed verbose 9036
bullets; added CI workflow change entry.
https://claude.ai/code/session_01XHWLohiSTdZvCutwD7ag2b
* Replace single-quoted literals in messaging calls with cli markup
Converted bare 'value' strings inside stop_(), warning_(), message_()
to appropriate cli markup:
- {.val}: option values ('drug', 'dose', 'administration', 'SDD', 'logbook')
- {.cls}: class names ('sir', 'mo')
- {.field}: column names ('mo' in mo_source)
- {.code}: object/dataset names ('clinical_breakpoints')
Files changed: ab_from_text.R, av_from_text.R, sir.R, sir_calc.R, mo_source.R
https://claude.ai/code/session_01XHWLohiSTdZvCutwD7ag2b
* Apply {.topic}, {.cls}, and {.field} markup in sir.R messaging
- 'clinical_breakpoints' (dataset): {.code} -> {.topic [clinical_breakpoints](AMR::clinical_breakpoints)}
- "is of class" context: extract bad_col/bad_cls/exp_cls vars and use {.cls} + {.field} in glue syntax
- Column references in as.sir() messages: font_bold(col) with surrounding quotes -> {.field {col}}
https://claude.ai/code/session_01XHWLohiSTdZvCutwD7ag2b
* Replace glue-style dynamic markup with paste0() construction
{.field {variable}} and {.cls {variable}} patterns rely on glue
evaluation which is not safe in a zero-dependency package. Replace
all four occurrences with paste0("{.field ", var, "}") so the value
is baked into the markup string before reaching message_()/stop_().
https://claude.ai/code/session_01XHWLohiSTdZvCutwD7ag2b
* Limit push trigger to main in check-recent workflow
push: branches: '**' caused both the push event (9-worker matrix) and
the pull_request event (1-worker matrix) to fire simultaneously on every
PR commit. Restricting push to [main] means PR pushes only trigger the
pull_request path (1 worker), while direct pushes to main still get the
full 9-worker matrix.
https://claude.ai/code/session_01XHWLohiSTdZvCutwD7ag2b
* Limit push trigger to main in code-coverage workflow
Same fix as check-recent: push: branches: '**' caused the workflow to
run twice per PR commit (once for push, once for pull_request). Restricting
push to [main] ensures coverage runs only once per PR update.
https://claude.ai/code/session_01XHWLohiSTdZvCutwD7ag2b
* Replace bare backticks with cli inline markup across all messaging calls
- {.arg} for argument names in stop_/warning_/message_ calls
- {.cls} after "of class" text in format_class() and elsewhere
- {.fun} for function names (replaces `fn()` pattern)
- {.pkg} for tidyverse package names (dplyr, ggplot2)
- {.code} for code literals (TRUE, FALSE, expressions)
- Rewrite print.ab: use cli named-vector with * bullets and code
highlighting when cli >= 3.0.0; keep plain-text fallback otherwise
- Fix typo in as.sir(): "of must be" -> "or must be"
- switch sir.R verbose notes from message() to message_()
https://claude.ai/code/session_01XHWLohiSTdZvCutwD7ag2b
* 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
* fixes
* Replace all "in \`funcname()\`:" with {.help [{.fun funcname}](AMR::funcname)}
Converts all "in `funcname()`:" prefixes in warning_()/message_()/stop_()
calls to the full {.help} link format for clickable help in supported
terminals. Also fixes adjacent backtick argument names to {.arg}.
Files changed: ab.R, ab_property.R, av.R, av_property.R, antibiogram.R,
key_antimicrobials.R, mdro.R, mic.R, mo.R, plotting.R
https://claude.ai/code/session_01XHWLohiSTdZvCutwD7ag2b
* fixes
* definitive
* version fix
---------
Co-authored-by: Claude <noreply@anthropic.com>
330 lines
15 KiB
R
Executable File
330 lines
15 KiB
R
Executable File
# ==================================================================== #
|
|
# TITLE: #
|
|
# AMR: An R Package for Working with Antimicrobial Resistance Data #
|
|
# #
|
|
# SOURCE CODE: #
|
|
# https://github.com/msberends/AMR #
|
|
# #
|
|
# PLEASE CITE THIS SOFTWARE AS: #
|
|
# Berends MS, Luz CF, Friedrich AW, et al. (2022). #
|
|
# AMR: An R Package for Working with Antimicrobial Resistance Data. #
|
|
# Journal of Statistical Software, 104(3), 1-31. #
|
|
# https://doi.org/10.18637/jss.v104.i03 #
|
|
# #
|
|
# Developed at the University of Groningen and the University Medical #
|
|
# Center Groningen in The Netherlands, in collaboration with many #
|
|
# colleagues from around the world, see our website. #
|
|
# #
|
|
# This R package is free software; you can freely use and distribute #
|
|
# it for both personal and commercial purposes under the terms of the #
|
|
# GNU General Public License version 2.0 (GNU GPL-2), as published by #
|
|
# the Free Software Foundation. #
|
|
# We created this package for both routine data analysis and academic #
|
|
# research and it was publicly released in the hope that it will be #
|
|
# useful, but it comes WITHOUT ANY WARRANTY OR LIABILITY. #
|
|
# #
|
|
# Visit our website for the full manual and a complete tutorial about #
|
|
# how to conduct AMR data analysis: https://amr-for-r.org #
|
|
# ==================================================================== #
|
|
|
|
#' User-Defined Reference Data Set for Microorganisms
|
|
#'
|
|
#' @description These functions can be used to predefine your own reference to be used in [as.mo()] and consequently all [`mo_*`][mo_property()] functions (such as [mo_genus()] and [mo_gramstain()]).
|
|
#'
|
|
#' This is **the fastest way** to have your organisation (or analysis) specific codes picked up and translated by this package, since you don't have to bother about it again after setting it up once.
|
|
#' @param path Location of your reference file, this can be any text file (comma-, tab- or pipe-separated) or an Excel file (see *Details*). Can also be `""`, `NULL` or `FALSE` to delete the reference file.
|
|
#' @param destination Destination of the compressed data file - the default is the user's home directory.
|
|
#' @rdname mo_source
|
|
#' @name mo_source
|
|
#' @aliases set_mo_source get_mo_source
|
|
#' @details The reference file can be a text file separated with commas (CSV) or tabs or pipes, an Excel file (either 'xls' or 'xlsx' format) or an \R object file (extension '.rds'). To use an Excel file, you will need to have the `readxl` package installed.
|
|
#'
|
|
#' [set_mo_source()] will check the file for validity: it must be a [data.frame], must have a column named `"mo"` which contains values from [`microorganisms$mo`][microorganisms] or [`microorganisms$fullname`][microorganisms] and must have a reference column with your own defined values. If all tests pass, [set_mo_source()] will read the file into \R and will ask to export it to `"~/mo_source.rds"`. The CRAN policy disallows packages to write to the file system, although '*exceptions may be allowed in interactive sessions if the package obtains confirmation from the user*'. For this reason, this function only works in interactive sessions so that the user can **specifically confirm and allow** that this file will be created. The destination of this file can be set with the `destination` argument and defaults to the user's home directory. It can also be set with the package option [`AMR_mo_source`][AMR-options], e.g. `options(AMR_mo_source = "my/location/file.rds")`.
|
|
#'
|
|
#' The created compressed data file `"mo_source.rds"` will be used at default for MO determination (function [as.mo()] and consequently all `mo_*` functions like [mo_genus()] and [mo_gramstain()]). The location and timestamp of the original file will be saved as an [attribute][base::attributes()] to the compressed data file.
|
|
#'
|
|
#' The function [get_mo_source()] will return the data set by reading `"mo_source.rds"` with [readRDS()]. If the original file has changed (by checking the location and timestamp of the original file), it will call [set_mo_source()] to update the data file automatically if used in an interactive session.
|
|
#'
|
|
#' Reading an Excel file (`.xlsx`) with only one row has a size of 8-9 kB. The compressed file created with [set_mo_source()] will then have a size of 0.1 kB and can be read by [get_mo_source()] in only a couple of microseconds (millionths of a second).
|
|
#'
|
|
#' @section How to Setup:
|
|
#'
|
|
#' Imagine this data on a sheet of an Excel file. The first column contains the organisation specific codes, the second column contains valid taxonomic names:
|
|
#'
|
|
#' ```
|
|
#' | A | B |
|
|
#' --|--------------------|-----------------------|
|
|
#' 1 | Organisation XYZ | mo |
|
|
#' 2 | lab_mo_ecoli | Escherichia coli |
|
|
#' 3 | lab_mo_kpneumoniae | Klebsiella pneumoniae |
|
|
#' 4 | | |
|
|
#' ```
|
|
#'
|
|
#' We save it as `"/Users/me/Documents/ourcodes.xlsx"`. Now we have to set it as a source:
|
|
#'
|
|
#' ```
|
|
#' set_mo_source("/Users/me/Documents/ourcodes.xlsx")
|
|
#' #> NOTE: Created mo_source file '/Users/me/mo_source.rds' (0.3 kB) from
|
|
#' #> '/Users/me/Documents/ourcodes.xlsx' (9 kB), columns
|
|
#' #> "Organisation XYZ" and "mo"
|
|
#' ```
|
|
#'
|
|
#' It has now created a file `"~/mo_source.rds"` with the contents of our Excel file. Only the first column with foreign values and the 'mo' column will be kept when creating the RDS file.
|
|
#'
|
|
#' And now we can use it in our functions:
|
|
#'
|
|
#' ```
|
|
#' as.mo("lab_mo_ecoli")
|
|
#' #> Class 'mo'
|
|
#' #> [1] B_ESCHR_COLI
|
|
#'
|
|
#' mo_genus("lab_mo_kpneumoniae")
|
|
#' #> [1] "Klebsiella"
|
|
#'
|
|
#' # other input values still work too
|
|
#' as.mo(c("Escherichia coli", "E. coli", "lab_mo_ecoli"))
|
|
#' #> NOTE: Translation to one microorganism was guessed with uncertainty.
|
|
#' #> Use mo_uncertainties() to review it.
|
|
#' #> Class 'mo'
|
|
#' #> [1] B_ESCHR_COLI B_ESCHR_COLI B_ESCHR_COLI
|
|
#' ```
|
|
#'
|
|
#' If we edit the Excel file by, let's say, adding row 4 like this:
|
|
#'
|
|
#' ```
|
|
#' | A | B |
|
|
#' --|--------------------|-----------------------|
|
|
#' 1 | Organisation XYZ | mo |
|
|
#' 2 | lab_mo_ecoli | Escherichia coli |
|
|
#' 3 | lab_mo_kpneumoniae | Klebsiella pneumoniae |
|
|
#' 4 | lab_Staph_aureus | Staphylococcus aureus |
|
|
#' 5 | | |
|
|
#' ```
|
|
#'
|
|
#' ...any new usage of an MO function in this package will update your data file:
|
|
#'
|
|
#' ```
|
|
#' as.mo("lab_mo_ecoli")
|
|
#' #> NOTE: Updated mo_source file '/Users/me/mo_source.rds' (0.3 kB) from
|
|
#' #> '/Users/me/Documents/ourcodes.xlsx' (9 kB), columns
|
|
#' #> "Organisation XYZ" and "mo"
|
|
#' #> Class 'mo'
|
|
#' #> [1] B_ESCHR_COLI
|
|
#'
|
|
#' mo_genus("lab_Staph_aureus")
|
|
#' #> [1] "Staphylococcus"
|
|
#' ```
|
|
#'
|
|
#' To delete the reference data file, just use `""`, `NULL` or `FALSE` as input for [set_mo_source()]:
|
|
#'
|
|
#' ```
|
|
#' set_mo_source(NULL)
|
|
#' #> Removed mo_source file '/Users/me/mo_source.rds'
|
|
#' ```
|
|
#'
|
|
#' If the original file (in the previous case an Excel file) is moved or deleted, the `mo_source.rds` file will be removed upon the next use of [as.mo()] or any [`mo_*`][mo_property()] function.
|
|
#' @export
|
|
set_mo_source <- function(path, destination = getOption("AMR_mo_source", "~/mo_source.rds")) {
|
|
stop_ifnot(interactive(), "this function can only be used in interactive mode, since it must ask for the user's permission to write a file to their file system.")
|
|
|
|
meet_criteria(path, allow_class = "character", has_length = 1, allow_NULL = TRUE)
|
|
meet_criteria(destination, allow_class = "character", has_length = 1)
|
|
stop_ifnot(destination %like% "[.]rds$", "the {.arg destination} must be a file location with file extension .rds.")
|
|
mo_source_destination <- path.expand(destination)
|
|
|
|
if (is.null(path) || path %in% c(FALSE, "")) {
|
|
AMR_env$mo_source <- NULL
|
|
if (file.exists(mo_source_destination)) {
|
|
unlink(mo_source_destination)
|
|
message_("Removed mo_source file '", font_bold(mo_source_destination), "'",
|
|
as_note = FALSE
|
|
)
|
|
}
|
|
return(invisible())
|
|
}
|
|
|
|
stop_ifnot(file.exists(path), "file not found: ", path)
|
|
|
|
df <- NULL
|
|
if (path %like% "[.]rds$") {
|
|
df <- readRDS_AMR(path)
|
|
} else if (path %like% "[.]xlsx?$") {
|
|
# is Excel file (old or new)
|
|
stop_ifnot_installed("readxl")
|
|
df <- readxl::read_excel(path)
|
|
} else if (path %like% "[.]tsv$") {
|
|
df <- utils::read.table(file = path, header = TRUE, sep = "\t", stringsAsFactors = FALSE)
|
|
} else if (path %like% "[.]csv$") {
|
|
df <- utils::read.table(file = path, header = TRUE, sep = ",", stringsAsFactors = FALSE)
|
|
} else {
|
|
# try comma first
|
|
try(
|
|
df <- utils::read.table(file = path, header = TRUE, sep = ",", stringsAsFactors = FALSE),
|
|
silent = TRUE
|
|
)
|
|
if (!check_validity_mo_source(df, stop_on_error = FALSE)) {
|
|
# try tab
|
|
try(
|
|
df <- utils::read.table(file = path, header = TRUE, sep = "\t", stringsAsFactors = FALSE),
|
|
silent = TRUE
|
|
)
|
|
}
|
|
if (!check_validity_mo_source(df, stop_on_error = FALSE)) {
|
|
# try pipe
|
|
try(
|
|
df <- utils::read.table(file = path, header = TRUE, sep = "|", stringsAsFactors = FALSE),
|
|
silent = TRUE
|
|
)
|
|
}
|
|
}
|
|
|
|
# check integrity
|
|
if (is.null(df)) {
|
|
stop_("the path '", path, "' could not be imported as a dataset.")
|
|
}
|
|
check_validity_mo_source(df)
|
|
|
|
df <- subset(df, !is.na(mo))
|
|
|
|
# keep only first two columns, second must be mo
|
|
if (colnames(df)[1] == "mo") {
|
|
df <- df[, c(colnames(df)[2], "mo")]
|
|
} else {
|
|
df <- df[, c(colnames(df)[1], "mo")]
|
|
}
|
|
|
|
df <- as.data.frame(df, stringAsFactors = FALSE)
|
|
df[, "mo"] <- as.mo(df[, "mo", drop = TRUE])
|
|
|
|
# success
|
|
if (file.exists(mo_source_destination)) {
|
|
action <- "Updated"
|
|
} else {
|
|
action <- "Created"
|
|
# only ask when file is created, not when it is updated
|
|
txt <- paste0(
|
|
word_wrap(paste0(
|
|
"This will write create the new file '",
|
|
mo_source_destination,
|
|
"', for which your permission is required."
|
|
)),
|
|
"\n\n",
|
|
word_wrap("Do you agree that this file will be created?")
|
|
)
|
|
showQuestion <- import_fn("showQuestion", "rstudioapi", error_on_fail = FALSE)
|
|
if (!is.null(showQuestion)) {
|
|
q_continue <- showQuestion("Create new file", txt)
|
|
} else {
|
|
q_continue <- utils::menu(choices = c("OK", "Cancel"), graphics = FALSE, title = txt)
|
|
}
|
|
if (q_continue %in% c(FALSE, 2)) {
|
|
return(invisible())
|
|
}
|
|
}
|
|
attr(df, "mo_source_location") <- path
|
|
attr(df, "mo_source_destination") <- mo_source_destination
|
|
attr(df, "mo_source_timestamp") <- file.mtime(path)
|
|
saveRDS(df, mo_source_destination)
|
|
AMR_env$mo_source <- df
|
|
message_(
|
|
action, " mo_source file '", font_bold(mo_source_destination),
|
|
"' (", formatted_filesize(mo_source_destination),
|
|
") from '", font_bold(path),
|
|
"' (", formatted_filesize(path),
|
|
'), columns "', colnames(df)[1], '" and "', colnames(df)[2], '"'
|
|
)
|
|
}
|
|
|
|
#' @rdname mo_source
|
|
#' @export
|
|
get_mo_source <- function(destination = getOption("AMR_mo_source", "~/mo_source.rds")) {
|
|
if (!file.exists(path.expand(destination))) {
|
|
if (interactive()) {
|
|
# source file might have been deleted, so update reference
|
|
set_mo_source("")
|
|
}
|
|
return(NULL)
|
|
}
|
|
if (destination %unlike% "[.]rds$") {
|
|
current_ext <- regexpr("\\.([[:alnum:]]+)$", destination)
|
|
current_ext <- ifelse(current_ext > -1L, substring(destination, current_ext + 1L), "")
|
|
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.")
|
|
}
|
|
if (is.null(AMR_env$mo_source)) {
|
|
AMR_env$mo_source <- readRDS_AMR(path.expand(destination))
|
|
}
|
|
|
|
old_time <- attributes(AMR_env$mo_source)$mo_source_timestamp
|
|
new_time <- file.mtime(attributes(AMR_env$mo_source)$mo_source_location)
|
|
if (interactive() && !identical(old_time, new_time)) {
|
|
# source file was updated, also update reference
|
|
set_mo_source(attributes(AMR_env$mo_source)$mo_source_location)
|
|
}
|
|
AMR_env$mo_source
|
|
}
|
|
|
|
check_validity_mo_source <- function(x, refer_to_name = "`reference_df`", stop_on_error = TRUE) {
|
|
add_MO_lookup_to_AMR_env()
|
|
|
|
if (paste(deparse(substitute(x)), collapse = "") == "get_mo_source()") {
|
|
return(TRUE)
|
|
}
|
|
if (is.null(AMR_env$mo_source) && (identical(x, get_mo_source()))) {
|
|
return(TRUE)
|
|
}
|
|
if (is.null(x)) {
|
|
if (stop_on_error == TRUE) {
|
|
stop_(refer_to_name, " cannot be NULL", call = FALSE)
|
|
} else {
|
|
return(FALSE)
|
|
}
|
|
}
|
|
if (!is.data.frame(x)) {
|
|
if (stop_on_error == TRUE) {
|
|
stop_(refer_to_name, " must be a data.frame", call = FALSE)
|
|
} else {
|
|
return(FALSE)
|
|
}
|
|
}
|
|
if (!"mo" %in% colnames(x)) {
|
|
if (stop_on_error == TRUE) {
|
|
stop_(refer_to_name, " must contain a column {.field mo}", call = FALSE)
|
|
} else {
|
|
return(FALSE)
|
|
}
|
|
}
|
|
if (!all(x$mo %in% c("", AMR_env$MO_lookup$mo, AMR_env$MO_lookup$fullname), na.rm = TRUE)) {
|
|
if (stop_on_error == TRUE) {
|
|
invalid <- x[which(!x$mo %in% c("", AMR_env$MO_lookup$mo, AMR_env$MO_lookup$fullname)), , drop = FALSE]
|
|
if (nrow(invalid) > 1) {
|
|
plural <- "s"
|
|
} else {
|
|
plural <- ""
|
|
}
|
|
stop_("Value", plural, " ", vector_and(invalid[, 1, drop = TRUE], quotes = TRUE),
|
|
" found in ", tolower(refer_to_name),
|
|
", but with invalid microorganism code", plural, " ", vector_and(invalid$mo, quotes = TRUE),
|
|
call = FALSE
|
|
)
|
|
} else {
|
|
return(FALSE)
|
|
}
|
|
}
|
|
if (colnames(x)[1] != "mo" && nrow(x) > length(unique(x[, 1, drop = TRUE]))) {
|
|
if (stop_on_error == TRUE) {
|
|
stop_(refer_to_name, " contains duplicate values in column '", colnames(x)[1], "'", call = FALSE)
|
|
} else {
|
|
return(FALSE)
|
|
}
|
|
}
|
|
if (colnames(x)[2] != "mo" && nrow(x) > length(unique(x[, 2, drop = TRUE]))) {
|
|
if (stop_on_error == TRUE) {
|
|
stop_(refer_to_name, " contains duplicate values in column '", colnames(x)[2], "'", call = FALSE)
|
|
} else {
|
|
return(FALSE)
|
|
}
|
|
}
|
|
return(TRUE)
|
|
}
|