diff --git a/DESCRIPTION b/DESCRIPTION index 7b8339c..554d254 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,6 +1,6 @@ Package: epidict Title: Epidemiology Data Dictionaries and Random Data Generators -Version: 0.1.0 +Version: 0.2.0 Authors@R: c( person("Alexander", "Spina", , "aspina@appliedepi.org", role = c("aut", "cre"), comment = c(ORCID = "0000-0001-8425-1867")), @@ -40,6 +40,7 @@ Suggests: knitr, matchmaker, rmarkdown, + sitrep, testthat (>= 2.1.0), withr VignetteBuilder: @@ -47,4 +48,4 @@ VignetteBuilder: Encoding: UTF-8 LazyData: true Roxygen: list(markdown = TRUE) -RoxygenNote: 7.3.2 +RoxygenNote: 7.3.3 diff --git a/NAMESPACE b/NAMESPACE index 1825987..a84b412 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -3,6 +3,7 @@ export(dict_rename_helper) export(gen_data) export(msf_dict) +export(msf_dict_rename_helper) export(read_dict) importFrom(clipr,write_clip) importFrom(dplyr,bind_rows) diff --git a/NEWS.md b/NEWS.md index e32d040..52db5c0 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,3 +1,6 @@ +# epidict 0.2.0 +* Reinstate msf_dict_rename_helper() with sitrep in DESCRIPTION suggests + # epidict 0.1.0 * First CRAN release * Separated out functions for reading dictionaries diff --git a/R/msf_dict_rename_helper.R b/R/msf_dict_rename_helper.R index cf17bc4..b615cc3 100644 --- a/R/msf_dict_rename_helper.R +++ b/R/msf_dict_rename_helper.R @@ -1,66 +1,66 @@ -#' #' Helper for aligning your data to MSF standardised dictionaries and analysis templates. -#' #' -#' #' @param dictionary Specify which MSF dictionary you would like to use. -#' #' See [msf_dict()] for options. -#' #' -#' #' @param copy_to_clipboard if `TRUE` (default), the rename template will be -#' #' copied to the user's clipboard with [clipr::write_clip()]. If `FALSE`, the -#' #' rename template will be printed to the user's console. -#' #' -#' #' @return A dplyr command used to rename columns in your data frame according -#' #' to the dictionary -#' #' -#' #' @importFrom readxl read_excel -#' #' -#' #' @export +#' Helper for aligning your data to MSF standardised dictionaries and analysis templates. #' -#' msf_dict_rename_helper <- function(dictionary, -#' copy_to_clipboard = TRUE) { +#' @param dictionary Specify which MSF dictionary you would like to use. +#' See [msf_dict()] for options. #' -#' # just add dict as "empty" if not defined (for checking errors) -#' if (missing("dictionary")) { -#' dictionary <- "empty" -#' } +#' @param copy_to_clipboard if `TRUE` (default), the rename template will be +#' copied to the user's clipboard with [clipr::write_clip()]. If `FALSE`, the +#' rename template will be printed to the user's console. #' -#' # define dictionary types -#' dict <- get_dictionary(dictionary, org = "MSF") -#' disease <- unlist(dict, use.names = FALSE) -#' is_survey <- length(dict$survey) == 1 -#' format <- ifelse(is_survey | grepl("_intersectional", disease), -#' "ODK", "DHIS2") +#' @return A dplyr command used to rename columns in your data frame according +#' to the dictionary #' -#' # get dictionary -#' dat_dict <- msf_dict(dictionary = disease, compact = TRUE) -#' -#' # define the dictionary columns for variable names and variable type -#' varnames <- ifelse(format == "ODK", "name", "data_element_shortname") -#' varnames_type <- ifelse(format == "ODK", "type", "data_element_valuetype") -#' -#' # remove long and short from vaccination (only one template with 2 dicts) -#' if (disease == "vaccination_short" | disease == "vaccination_long") { -#' disease <- "vaccination" -#' } -#' -#' # only call sitrep if it's installed -#' if (!requireNamespace("sitrep", quietly = TRUE)) { -#' stop( -#' "The 'sitrep' package is required for this function but is not installed.\n", -#' "Please install it from GitHub: R4EPI/sitrep" -#' ) -#' } -#' -#' # get the outbreak Rmd to check if the variable is optional or required -#' outbreak_file <- sitrep::available_sitrep_templates(recursive = TRUE, pattern = ".Rmd", full.names = TRUE) -#' outbreak_file <- grep(tolower(disease), outbreak_file, value = TRUE)[[1]] -#' -#' # call the dict_rename_helper function -#' dict_rename_helper( -#' dictionary = dat_dict, -#' varnames = varnames, -#' varnames_type = varnames_type, -#' rmd = outbreak_file, -#' copy_to_clipboard = copy_to_clipboard -#' ) -#' -#' } +#' @importFrom readxl read_excel #' +#' @export + +msf_dict_rename_helper <- function(dictionary, + copy_to_clipboard = TRUE) { + + # just add dict as "empty" if not defined (for checking errors) + if (missing("dictionary")) { + dictionary <- "empty" + } + + # define dictionary types + dict <- get_dictionary(dictionary, org = "MSF") + disease <- unlist(dict, use.names = FALSE) + is_survey <- length(dict$survey) == 1 + format <- ifelse(is_survey | grepl("_intersectional", disease), + "ODK", "DHIS2") + + # get dictionary + dat_dict <- msf_dict(dictionary = disease, compact = TRUE) + + # define the dictionary columns for variable names and variable type + varnames <- ifelse(format == "ODK", "name", "data_element_shortname") + varnames_type <- ifelse(format == "ODK", "type", "data_element_valuetype") + + # remove long and short from vaccination (only one template with 2 dicts) + if (disease == "vaccination_short" | disease == "vaccination_long") { + disease <- "vaccination" + } + + # only call sitrep if it's installed + if (!requireNamespace("sitrep", quietly = TRUE)) { + stop( + "The 'sitrep' package is required for this function but is not installed.\n", + "Please install it using install.packages('sitrep)" + ) + } + + # get the outbreak Rmd to check if the variable is optional or required + outbreak_file <- sitrep::available_sitrep_templates(recursive = TRUE, pattern = ".Rmd", full.names = TRUE) + outbreak_file <- grep(tolower(disease), outbreak_file, value = TRUE)[[1]] + + # call the dict_rename_helper function + dict_rename_helper( + dictionary = dat_dict, + varnames = varnames, + varnames_type = varnames_type, + rmd = outbreak_file, + copy_to_clipboard = copy_to_clipboard + ) + +} + diff --git a/cran-comments.md b/cran-comments.md index e42d83e..31805b8 100644 --- a/cran-comments.md +++ b/cran-comments.md @@ -7,17 +7,8 @@ ## R CMD check results -0 errors | 0 warnings | 1 note +0 errors | 0 warnings | 0 note -* This is a new submission to CRAN.* - -All URLs and metadata issues noted in the previous submission have been corrected: -- Updated Title field to title case. -- possible misspelled words in DESCRIPTION are correct as is. -- Updated all URLs to canonical HTTPS versions with trailing slashes. -- Updated lifecycle badge link to https://lifecycle.r-lib.org/articles/stages.html#maturing. -- Spelled out acronyms. -- description spacing fixed and link added to describe methods -- value descriptions added to functions +- new function added for a minor release diff --git a/man/msf_dict_rename_helper.Rd b/man/msf_dict_rename_helper.Rd new file mode 100644 index 0000000..82888ff --- /dev/null +++ b/man/msf_dict_rename_helper.Rd @@ -0,0 +1,23 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/msf_dict_rename_helper.R +\name{msf_dict_rename_helper} +\alias{msf_dict_rename_helper} +\title{Helper for aligning your data to MSF standardised dictionaries and analysis templates.} +\usage{ +msf_dict_rename_helper(dictionary, copy_to_clipboard = TRUE) +} +\arguments{ +\item{dictionary}{Specify which MSF dictionary you would like to use. +See \code{\link[=msf_dict]{msf_dict()}} for options.} + +\item{copy_to_clipboard}{if \code{TRUE} (default), the rename template will be +copied to the user's clipboard with \code{\link[clipr:write_clip]{clipr::write_clip()}}. If \code{FALSE}, the +rename template will be printed to the user's console.} +} +\value{ +A dplyr command used to rename columns in your data frame according +to the dictionary +} +\description{ +Helper for aligning your data to MSF standardised dictionaries and analysis templates. +} diff --git a/tests/testthat/test-rename_helper.R b/tests/testthat/test-rename_helper.R index f2ce156..162efc5 100644 --- a/tests/testthat/test-rename_helper.R +++ b/tests/testthat/test-rename_helper.R @@ -268,149 +268,149 @@ test_that("dict_rename_helper handles clipboard operations gracefully", { # Test msf_dict_rename_helper --------------------------------------------------- -# test_that("msf_dict_rename_helper validates dictionary input", { -# skip_if_not_installed("clipr") -# skip_if_not_installed("sitrep") -# -# expect_error( -# msf_dict_rename_helper( -# dictionary = "nonexistent_disease", -# copy_to_clipboard = FALSE -# ), -# "'dictionary' must be one of: 'Cholera', 'Measles', 'Meningitis', 'AJS', 'Cholera_intersectional', 'Measles_intersectional', 'Meningitis_intersectional', 'AJS_intersectional', 'Diphtheria_intersectional', 'Mortality', 'Nutrition', 'Vaccination_long', 'Vaccination_short', 'ebs'" -# ) -# }) -# -# test_that("msf_dict_rename_helper works with valid outbreak dictionaries", { -# skip_if_not_installed("clipr") -# skip_if_not_installed("sitrep") -# skip_on_cran() -# -# # Test with a known outbreak dictionary -# outbreak_dicts <- c("Cholera", "Measles", "AJS", "Meningitis") -# -# for (dict in outbreak_dicts) { -# # Check it runs without error -# expect_no_error( -# msf_dict_rename_helper( -# dictionary = dict, -# copy_to_clipboard = FALSE -# ) -# ) -# } -# }) -# -# test_that("msf_dict_rename_helper works with intersectional outbreak dictionaries", { -# skip_if_not_installed("clipr") -# skip_if_not_installed("sitrep") -# skip_on_cran() -# -# # Test with intersectional dictionaries -# expect_no_error( -# msf_dict_rename_helper( -# dictionary = "Cholera_intersectional", -# copy_to_clipboard = FALSE -# ) -# ) -# }) -# -# test_that("msf_dict_rename_helper works with survey dictionaries", { -# skip_if_not_installed("clipr") -# skip_if_not_installed("sitrep") -# skip_on_cran() -# -# # Test with survey dictionaries -# survey_dicts <- c("Mortality", "Nutrition", "Vaccination_long", "Vaccination_short") -# -# for (dict in survey_dicts) { -# expect_no_error( -# msf_dict_rename_helper( -# dictionary = dict, -# copy_to_clipboard = FALSE -# ) -# ) -# } -# }) -# -# test_that("msf_dict_rename_helper uses correct varnames for format", { -# skip_if_not_installed("clipr") -# skip_if_not_installed("sitrep") -# skip_on_cran() -# -# # Capture output for DHIS2 format (e.g., Cholera) -# output_dhis <- capture.output( -# msf_dict_rename_helper( -# dictionary = "Cholera", -# copy_to_clipboard = FALSE -# ) -# ) -# -# # For DHIS2, should use data_element_shortname as variable names -# # We can't directly check the internal workings, but we can verify it runs -# expect_true(length(output_dhis) > 0) -# -# # Capture output for ODK format (e.g., Mortality) -# output_odk <- capture.output( -# msf_dict_rename_helper( -# dictionary = "Mortality", -# copy_to_clipboard = FALSE -# ) -# ) -# -# # For ODK, should use name as variable names -# expect_true(length(output_odk) > 0) -# }) -# -# test_that("msf_dict_rename_helper handles vaccination dictionaries specially", { -# skip_if_not_installed("clipr") -# skip_if_not_installed("sitrep") -# skip_on_cran() -# -# # Both vaccination_long and vaccination_short should work -# expect_no_error( -# msf_dict_rename_helper( -# dictionary = "Vaccination_long", -# copy_to_clipboard = FALSE -# ) -# ) -# -# expect_no_error( -# msf_dict_rename_helper( -# dictionary = "Vaccination_short", -# copy_to_clipboard = FALSE -# ) -# ) -# }) -# -# test_that("msf_dict_rename_helper produces valid rename syntax", { -# skip_if_not_installed("clipr") -# skip_if_not_installed("sitrep") -# skip_on_cran() -# -# output <- capture.output( -# msf_dict_rename_helper( -# dictionary = "Cholera", -# copy_to_clipboard = FALSE -# ) -# ) -# -# output_text <- paste(output, collapse = "\n") -# -# # Check for standard rename structure -# expect_match(output_text, "rename\\(linelist_cleaned,") -# expect_match(output_text, "REQUIRED|optional") -# }) -# -# test_that("msf_dict_rename_helper handles missing dictionary parameter", { -# skip_if_not_installed("clipr") -# skip_if_not_installed("sitrep") -# -# # Should error when dictionary is missing -# expect_error( -# msf_dict_rename_helper(copy_to_clipboard = FALSE), -# "'dictionary' must be one of: 'Cholera', 'Measles', 'Meningitis', 'AJS', 'Cholera_intersectional', 'Measles_intersectional', 'Meningitis_intersectional', 'AJS_intersectional', 'Diphtheria_intersectional', 'Mortality', 'Nutrition', 'Vaccination_long', 'Vaccination_short', 'ebs'" -# ) -# }) +test_that("msf_dict_rename_helper validates dictionary input", { + skip_if_not_installed("clipr") + skip_if_not_installed("sitrep") + + expect_error( + msf_dict_rename_helper( + dictionary = "nonexistent_disease", + copy_to_clipboard = FALSE + ), + "'dictionary' must be one of: 'Cholera', 'Measles', 'Meningitis', 'AJS', 'Cholera_intersectional', 'Measles_intersectional', 'Meningitis_intersectional', 'AJS_intersectional', 'Diphtheria_intersectional', 'Mortality', 'Nutrition', 'Vaccination_long', 'Vaccination_short', 'ebs'" + ) +}) + +test_that("msf_dict_rename_helper works with valid outbreak dictionaries", { + skip_if_not_installed("clipr") + skip_if_not_installed("sitrep") + skip_on_cran() + + # Test with a known outbreak dictionary + outbreak_dicts <- c("Cholera", "Measles", "AJS", "Meningitis") + + for (dict in outbreak_dicts) { + # Check it runs without error + expect_no_error( + msf_dict_rename_helper( + dictionary = dict, + copy_to_clipboard = FALSE + ) + ) + } +}) + +test_that("msf_dict_rename_helper works with intersectional outbreak dictionaries", { + skip_if_not_installed("clipr") + skip_if_not_installed("sitrep") + skip_on_cran() + + # Test with intersectional dictionaries + expect_no_error( + msf_dict_rename_helper( + dictionary = "Cholera_intersectional", + copy_to_clipboard = FALSE + ) + ) +}) + +test_that("msf_dict_rename_helper works with survey dictionaries", { + skip_if_not_installed("clipr") + skip_if_not_installed("sitrep") + skip_on_cran() + + # Test with survey dictionaries + survey_dicts <- c("Mortality", "Nutrition", "Vaccination_long", "Vaccination_short") + + for (dict in survey_dicts) { + expect_no_error( + msf_dict_rename_helper( + dictionary = dict, + copy_to_clipboard = FALSE + ) + ) + } +}) + +test_that("msf_dict_rename_helper uses correct varnames for format", { + skip_if_not_installed("clipr") + skip_if_not_installed("sitrep") + skip_on_cran() + + # Capture output for DHIS2 format (e.g., Cholera) + output_dhis <- capture.output( + msf_dict_rename_helper( + dictionary = "Cholera", + copy_to_clipboard = FALSE + ) + ) + + # For DHIS2, should use data_element_shortname as variable names + # We can't directly check the internal workings, but we can verify it runs + expect_true(length(output_dhis) > 0) + + # Capture output for ODK format (e.g., Mortality) + output_odk <- capture.output( + msf_dict_rename_helper( + dictionary = "Mortality", + copy_to_clipboard = FALSE + ) + ) + + # For ODK, should use name as variable names + expect_true(length(output_odk) > 0) +}) + +test_that("msf_dict_rename_helper handles vaccination dictionaries specially", { + skip_if_not_installed("clipr") + skip_if_not_installed("sitrep") + skip_on_cran() + + # Both vaccination_long and vaccination_short should work + expect_no_error( + msf_dict_rename_helper( + dictionary = "Vaccination_long", + copy_to_clipboard = FALSE + ) + ) + + expect_no_error( + msf_dict_rename_helper( + dictionary = "Vaccination_short", + copy_to_clipboard = FALSE + ) + ) +}) + +test_that("msf_dict_rename_helper produces valid rename syntax", { + skip_if_not_installed("clipr") + skip_if_not_installed("sitrep") + skip_on_cran() + + output <- capture.output( + msf_dict_rename_helper( + dictionary = "Cholera", + copy_to_clipboard = FALSE + ) + ) + + output_text <- paste(output, collapse = "\n") + + # Check for standard rename structure + expect_match(output_text, "rename\\(linelist_cleaned,") + expect_match(output_text, "REQUIRED|optional") +}) + +test_that("msf_dict_rename_helper handles missing dictionary parameter", { + skip_if_not_installed("clipr") + skip_if_not_installed("sitrep") + + # Should error when dictionary is missing + expect_error( + msf_dict_rename_helper(copy_to_clipboard = FALSE), + "'dictionary' must be one of: 'Cholera', 'Measles', 'Meningitis', 'AJS', 'Cholera_intersectional', 'Measles_intersectional', 'Meningitis_intersectional', 'AJS_intersectional', 'Diphtheria_intersectional', 'Mortality', 'Nutrition', 'Vaccination_long', 'Vaccination_short', 'ebs'" + ) +}) # Integration tests --------------------------------------------------------------