diff --git a/DESCRIPTION b/DESCRIPTION index 5759561..d3ae887 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,6 +1,6 @@ Package: REDCapExporter Title: Automated Construction of R Data Packages from REDCap Projects -Version: 0.3.3 +Version: 0.3.4 Authors@R: c( person(given = "Peter", family = "DeWitt", email = "peter.dewitt@cuanschutz.edu", role = c("aut", "cre"), comment = c(ORCID = "0000-0002-6391-0795")) ) @@ -12,8 +12,8 @@ Description: Export all data, including metadata, from a REDCap (Research default reports are generated as vignettes in the resulting package. License: GPL-2 Encoding: UTF-8 -URL: https://github.com/dewittpe/REDCapExporter, http://www.peteredewitt.com/REDCapExporter/ -Language: en-us +URL: https://github.com/dewittpe/REDCapExporter, https://www.peteredewitt.com/REDCapExporter/ +Language: en-US LazyData: true Depends: R (>= 3.5.0) diff --git a/Makefile b/Makefile index a0aeb7f..4604d91 100644 --- a/Makefile +++ b/Makefile @@ -8,7 +8,7 @@ CRAN = "https://cran.rstudio.com" SRC = $(wildcard $(PKG_ROOT)/src/*.cpp) RFILES = $(wildcard $(PKG_ROOT)/R/*.R) EXAMPLES = $(wildcard $(PKG_ROOT)/examples/*.R) -TESTS = $(wildcard $(PKG_ROOT)/tests/testthat/*.R) +TESTS = $(wildcard $(PKG_ROOT)/tests/test-*.R) # Targets VIGNETTES = $(PKG_ROOT)/vignettes/redcap2package.Rmd\ diff --git a/NEWS.md b/NEWS.md index ffdcbfe..c12a0a8 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,3 +1,18 @@ +# Version 0.3.4 + +## Improvements + +* Gate `devtools::document()` in `build_r_data_package()` when devtools is not available. + +## Testing Change + +* Update test-build_r_pkg.R to be robust to platform. +* Update `test-build_r_pkg.R` expectations based on devtools availability. +* Constrain keyring tests to a temporary keyring directory. +* Avoid building/installing a generated package inside the vignette during checks. +* Update test-export to use the REDCapR public dev-2 test endpoint/token and + skip on curl-related failures. + # Version 0.3.3 ## Testing Change diff --git a/R/build_r_data_package.R b/R/build_r_data_package.R index 3176c30..61cfac9 100644 --- a/R/build_r_data_package.R +++ b/R/build_r_data_package.R @@ -130,7 +130,11 @@ build_r_data_package.rcer_rccore <- function(x, path = NULL, author_roles = NULL file = paste(path, "R/datasets.R", sep = "/") ) - devtools::document(path) + if (requireNamespace("devtools", quietly = TRUE)) { + devtools::document(path) + } else { + message("Skipping devtools::document(): 'devtools' is not available.") + } invisible(TRUE) } diff --git a/cran-comments.md b/cran-comments.md index 0a20fc7..483f3b6 100644 --- a/cran-comments.md +++ b/cran-comments.md @@ -1,3 +1,29 @@ +# Version 0.3.4 + +This submission to CRAN is coming shortly after the prior submission because of +new CRAN check failures. + +- Prevent vignette build/install of the generated package (devtools/processx) + during checks. +- Constrain keyring tests to a temporary keyring directory. +- Gate `devtools::document()` inside `build_r_data_package()` when devtools is + not available, and update tests accordingly. +- Update test-export to use the REDCapR public dev-2 test endpoint/token and + skip on curl-related failures. +- Update the personal URL to HTTPS. + +## Testing + +- Local macOS, R 4.5.2 + - R CMD check --as-cran REDCapExporter_0.3.4.tar.gz + - Status: OK (2 NOTEs: no Internet for URL checks, time-stamp check) +- GitHub Actions + - Status: OK +- Windows Builder + - Status: OK +- Rhub + - Status: OK + # Version 0.3.3 - Improve testing suite to account for a resource going offline @@ -247,5 +273,3 @@ be used in the examples and vignettes. > Please fix and resubmit, and document what was changed in the submission > comments. - - diff --git a/man/REDCapExporter-package.Rd b/man/REDCapExporter-package.Rd index 4ba9f77..948ffc2 100644 --- a/man/REDCapExporter-package.Rd +++ b/man/REDCapExporter-package.Rd @@ -21,7 +21,7 @@ Please read the vignette for examples and use cases. Useful links: \itemize{ \item \url{https://github.com/dewittpe/REDCapExporter} - \item \url{http://www.peteredewitt.com/REDCapExporter/} + \item \url{https://www.peteredewitt.com/REDCapExporter/} } } diff --git a/tests/test-as.data.frame.R b/tests/test-as.data.frame.R index 807c9cd..f2987c1 100644 --- a/tests/test-as.data.frame.R +++ b/tests/test-as.data.frame.R @@ -1,37 +1,36 @@ library(REDCapExporter) -# Expect error if the input in not csv or json. the error should come from the -# read_text call, which is not exported. -x <- avs_raw_metadata -attr(x, "Content-Type") <- c("not-csv", "not-json") -x <- tools::assertError(REDCapExporter:::read_text(x)) -stopifnot(identical(x[[1]][["message"]], "Content-Type 'not-csv' is not yet supported.")) - -# Testing coercion of rcer_raw_metadata to data.frame and data.table -DF0 <- as.data.frame(avs_raw_metadata) -DF1 <- as.data.frame(avs_raw_metadata_json) - -stopifnot(all.equal(DF0, DF1)) - -# Testing coercion of rcer_raw_record to data.frame and data.table -rm(list = ls()) - -DF0 <- as.data.frame(avs_raw_record) -DF1 <- as.data.frame(avs_raw_record_json) - -stopifnot(all.equal(DF0, DF1)) - -# Testing coercion of rcer_raw_project to data.frame and data.table -rm(list = ls()) -DF0 <- as.data.frame(avs_raw_project) -DF1 <- as.data.frame(avs_raw_project_json) - -stopifnot(all.equal(DF0, DF1)) - -# Testing coercion of rcer_raw_user to data.frame and data.table -rm(list = ls()) -DF0 <- as.data.frame(avs_raw_user) -DF1 <- as.data.frame(avs_raw_user_json) - -stopifnot(all.equal(DF0, DF1)) +# Unsupported content type should error +x_bad <- avs_raw_metadata +attr(x_bad, "Content-Type") <- c("not-csv", "not-json") + +err <- tryCatch( + REDCapExporter:::read_text(x_bad), + error = function(e) e +) + +stopifnot( + inherits(err, "error"), + grepl("Content-Type .* not yet supported", err$message) +) + +# Metadata coercion +md_csv <- as.data.frame(avs_raw_metadata) +md_json <- as.data.frame(avs_raw_metadata_json) +stopifnot(isTRUE(all.equal(md_csv, md_json))) + +# Record coercion +rec_csv <- as.data.frame(avs_raw_record) +rec_json <- as.data.frame(avs_raw_record_json) +stopifnot(isTRUE(all.equal(rec_csv, rec_json))) + +# Project coercion +proj_csv <- as.data.frame(avs_raw_project) +proj_json <- as.data.frame(avs_raw_project_json) +stopifnot(isTRUE(all.equal(proj_csv, proj_json))) + +# User coercion +usr_csv <- as.data.frame(avs_raw_user) +usr_json <- as.data.frame(avs_raw_user_json) +stopifnot(isTRUE(all.equal(usr_csv, usr_json))) diff --git a/tests/test-build_r_pkg.R b/tests/test-build_r_pkg.R index 7a181c2..c43d3dc 100644 --- a/tests/test-build_r_pkg.R +++ b/tests/test-build_r_pkg.R @@ -1,34 +1,74 @@ library(REDCapExporter) temppath <- tempdir() -build_r_data_package( - x = avs_raw_core, - path = temppath, - author_roles = list(dewittp = c("cre", "aut")), -) -x <- fs::dir_tree(temppath) -x <- unname(sapply(strsplit(x, "rcd14465"), `[`, 2)) -x[is.na(x)] <- "" -x <- sort(paste0("rcd14465", x)) +msgs <- character() +withCallingHandlers( + { + build_r_data_package( + x = avs_raw_core, + path = temppath, + author_roles = list(dewittp = c("cre", "aut")) + ) + }, + message = function(m) { + msgs <<- c(msgs, conditionMessage(m)) + invokeRestart("muffleMessage") + } +) -print(x) +pkgdir <- file.path(temppath, "rcd14465") +# check the DESCRIPTION file for the built package +d <- read.dcf(file.path(pkgdir, "DESCRIPTION")) stopifnot( - identical( - x, - sort( - c("rcd14465", "rcd14465/DESCRIPTION", "rcd14465/LICENSE", "rcd14465/NAMESPACE", - "rcd14465/R", "rcd14465/R/datasets.R", "rcd14465/data", "rcd14465/data/metadata.rda", - "rcd14465/data/project.rda", "rcd14465/data/record.rda", "rcd14465/data/user.rda", - "rcd14465/inst", "rcd14465/inst/raw-data", "rcd14465/inst/raw-data/metadata.rds", - "rcd14465/inst/raw-data/project.rds", "rcd14465/inst/raw-data/record.rds", - "rcd14465/inst/raw-data/user.rds", "rcd14465/man", "rcd14465/man/metadata.Rd", - "rcd14465/man/project.Rd", "rcd14465/man/record.Rd", "rcd14465/man/user.Rd") - ) - ) + d[1, "Package"] == "rcd14465", + grepl("\\d{4}\\.\\d{2}\\.\\d{2}\\.\\d{2}\\.\\d{2}", d[1, "Version"]) ) -stopifnot( - packageDescription(pkg = "rcd14465", lib.loc = temppath)$Package == "rcd14465", - grepl("\\d{4}\\.\\d{2}\\.\\d{2}\\.\\d{2}\\.\\d{2}", packageDescription(pkg = "rcd14465", lib.loc = temppath)$Version) - ) +# check the file structure of the built package +x <- list.files( + path = pkgdir, + all.files = TRUE, + recursive = TRUE, + include.dirs = TRUE, + full.names = FALSE, + no.. = TRUE +) + +# switch slashes from windows to *nix +x <- gsub("\\\\", "/", x) + +expected <- sort(c( + "DESCRIPTION", + "LICENSE", + "R", + "R/datasets.R", + "data", + "data/metadata.rda", + "data/project.rda", + "data/record.rda", + "data/user.rda", + "inst", + "inst/raw-data", + "inst/raw-data/metadata.rds", + "inst/raw-data/project.rds", + "inst/raw-data/record.rds", + "inst/raw-data/user.rds" +)) + +if (requireNamespace("devtools", quietly = TRUE)) { + expected <- sort(c( + expected, + "NAMESPACE", + "man", + "man/metadata.Rd", + "man/project.Rd", + "man/record.Rd", + "man/user.Rd" + )) + stopifnot(!any(grepl("Skipping devtools::document", msgs))) +} else { + stopifnot(any(grepl("Skipping devtools::document", msgs))) +} + +stopifnot(identical(x, expected)) diff --git a/tests/test-export.R b/tests/test-export.R index 809c8bf..6e7baa4 100644 --- a/tests/test-export.R +++ b/tests/test-export.R @@ -1,13 +1,13 @@ library(REDCapExporter) -# Tests rely on publicly available REDCap and tokens published -# https://github.com/redcap-tools/redcap-test-datasets/tree/master +# Tests rely on publicly available REDCap test datasets and tokens. +# The REDCapR project moved its public test credentials from bbmc.ouhsc.edu +# to redcap-dev-2.ouhsc.edu in February 2026 (see REDCapR repo history and +# inst/misc/example.credentials). We follow that public test endpoint here. +# The API tokens below are intended to be public and used for testing. -# project_name token server_url pid server read_only operational notes -# archer 9A81268476645C4E5F03428B8AC3AA7B https://bbmc.ouhsc.edu/redcap/api/ 153 oklahoma-bbmc TRUE TRUE simple structure; read-only -# archer D70F9ACD1EDD6F151C6EA78683944E98 https://bbmc.ouhsc.edu/redcap/api/ 213 oklahoma-bbmc FALSE TRUE simple structure; read & write -# archer 0434F0E9CF53ED0587847AB6E51DE762 https://bbmc.ouhsc.edu/redcap/api/ 212 oklahoma-bbmc TRUE TRUE longitudinal structure; read-only -# archer D72C6485B52FE9F75D27B696977FBA43 https://bbmc.ouhsc.edu/redcap/api/ 268 oklahoma-bbmc TRUE TRUE Russian characters; read-only +# project_name token server_url pid server read_only operational notes +# simple 9A068C425B1341D69E83064A2D273A70 https://redcap-dev-2.ouhsc.edu/redcap/api/ 33 ouhsc-dev-2 TRUE TRUE simple structure; read-only on_cran <- function() { # copied from testthat:::on_cran @@ -22,84 +22,24 @@ on_cran <- function() { if (!on_cran()) { archer01_csv <- tryCatch( - export_core(uri = 'https://bbmc.ouhsc.edu/redcap/api/', token = '9A81268476645C4E5F03428B8AC3AA7B'), + export_core(uri = 'https://redcap-dev-2.ouhsc.edu/redcap/api/', token = '9A068C425B1341D69E83064A2D273A70'), error = function(e) {e} ) - expected_return <- - c( - project_raw = "ERROR: You do not have permissions to use the API", - metadata_raw = "ERROR: You do not have permissions to use the API", - user_raw = "ERROR: You do not have permissions to use the API", - record_raw = "ERROR: You do not have permissions to use the API" - ) - - stopifnot( - !inherits(archer01_csv, "error"), # not an error - a retun happened, but it is not a useful return - length(archer01_csv) == 4L, - inherits(archer01_csv[[1]], "rcer_raw_project"), - inherits(archer01_csv[[2]], "rcer_raw_metadata"), - inherits(archer01_csv[[3]], "rcer_raw_user"), - inherits(archer01_csv[[4]], "rcer_raw_record"), - identical(sapply(archer01_csv, getElement, 1), expected_return) - ) + if (inherits(archer01_csv, "error")) { + if (inherits(archer01_csv, "curl_error")) { + message(sprintf("Skip test-export.R after curl error: %s", archer01_csv$message)) + } else { + stop("in test-export.R a non-curl error occurred when calling export_core") + } + } else { + stopifnot( + length(archer01_csv) == 4L, + inherits(archer01_csv[[1]], "rcer_raw_project"), + inherits(archer01_csv[[2]], "rcer_raw_metadata"), + inherits(archer01_csv[[3]], "rcer_raw_user"), + inherits(archer01_csv[[4]], "rcer_raw_record") + ) + } } -################################################################################ -# OLD TESTS, for version < 0.3.3 these tests were used, but in Feb 2026 the API -# failed and so do the tests. Not a REDCapExporter issue, an RedCap API issue. -# -# Commented out for now until a fix can be made. -# -### -### -### Sys.setenv("REDCap_API_URI" = 'https://bbmc.ouhsc.edu/redcap/api/') -### Sys.setenv("REDCap_API_TOKEN" = '9A81268476645C4E5F03428B8AC3AA7B') -### archer01_json <- tryCatch(export_core(format = "json"), error = function(e) {e}) -### -### if (inherits(archer01_csv, "error") | inherits(archer01_json, "error")) { -### if (inherits(archer01_csv, "curl_error") | inherits(archer01_json, "curl_error")) { -### # skip the rest of the testing -### print(sprintf("Skip test-export.R after curl error: %s", archer01_csv$message)) -### } else { -### stop("in test-export.R an non curl related error occured when initially calling export_core") -### } -### } else { -### -### stopifnot( -### inherits(archer01_csv, "rcer_rccore"), -### inherits(archer01_json, "rcer_rccore"), -### inherits(archer01_csv$project_raw, "rcer_raw_project"), -### inherits(archer01_json$project_raw, "rcer_raw_project"), -### inherits(archer01_csv$metadata_raw, "rcer_raw_metadata"), -### inherits(archer01_json$metadata_raw, "rcer_raw_metadata"), -### inherits(archer01_csv$project_raw, "rcer_raw_project"), -### inherits(archer01_json$project_raw, "rcer_raw_project"), -### inherits(archer01_csv$record_raw, "rcer_raw_record"), -### inherits(archer01_json$record_raw, "rcer_raw_record"), -### grepl("text/csv", attr(archer01_csv$record_raw, "Content-Type")), -### grepl("application/json", attr(archer01_json$record_raw, "Content-Type")) -### ) -### -### a1 <- format_record(archer01_csv) -### a2 <- format_record(archer01_json) -### -### # apparently the end of line characters are exported differently -### a1$address <- gsub('\n', ' ', gsub('\r', '', a1$address)) -### a2$address <- gsub('\n', ' ', gsub('\r', '', a2$address)) -### a1$comments <- gsub('\n', ' ', gsub('\r', '', a1$comments)) -### a2$comments <- gsub('\n', ' ', gsub('\r', '', a2$comments)) -### -### stopifnot(isTRUE(all.equal(a1, a2))) -### -### } -### -### # -### #archer02 <- export_core(uri = 'https://bbmc.ouhsc.edu/redcap/api/', token = 'D70F9ACD1EDD6F151C6EA78683944E98') -### #archer02 <- format_record(archer02) -### # -### #archer03 <- export_core(uri = 'https://bbmc.ouhsc.edu/redcap/api/', token = '0434F0E9CF53ED0587847AB6E51DE762') -### #archer03 <- format_record(archer03) -### # -### #archer04 <- export_core(uri = 'https://bbmc.ouhsc.edu/redcap/api/', token = 'D72C6485B52FE9F75D27B696977FBA43') -### #archer04 <- format_record(archer04) diff --git a/tests/test-format_record.R b/tests/test-format_record.R index e51503e..f6ecdb2 100644 --- a/tests/test-format_record.R +++ b/tests/test-format_record.R @@ -120,14 +120,42 @@ classes[classes == "factor"] <- "character" stopifnot(identical(sapply(DF, class), classes)) stopifnot(!any(sapply(DF, class) == "factor")) +################################################################################ # verify that you can set the timezone for the dates -DF0 <- format_record(avs_raw_core) +# verify that you can set the timezone for the dates +df_date <- format_record(avs_raw_core) + +tz_local <- Sys.timezone() +if (is.na(tz_local) || !nzchar(tz_local)) { + tz_local <- "UTC" +} + +df_local <- format_record( + avs_raw_record, + col_type = col_type( + avs_raw_metadata, + lubridate_args = list(tz = tz_local) + ) +) + +df_utc <- format_record( + avs_raw_record, + col_type = col_type( + avs_raw_metadata, + lubridate_args = list(tz = "UTC") + ) +) + +stopifnot(inherits(df_date$birthdate, "Date")) -# this timezone specification is system and locale specific -#DF1 <- format_record(avs_raw_record, col_type = col_type(avs_raw_metadata, lubridate_args = list(tz = "US/Mountain"))) -DF1 <- format_record(avs_raw_record, col_type = col_type(avs_raw_metadata, lubridate_args = list(tz = Sys.timezone()))) -DF2 <- format_record(avs_raw_record, col_type = col_type(avs_raw_metadata, lubridate_args = list(tz = "UTC"))) +stopifnot( + !inherits(df_local$birthdate, "Date"), + inherits(df_local$birthdate, "POSIXct"), + identical(attr(df_local$birthdate, "tzone"), tz_local) +) -stopifnot(inherits(DF0$birthdate, "Date")) -stopifnot(!inherits(DF1$birthdate, "Date"), inherits(DF1$birthdate, "POSIXct"), isTRUE(attr(DF1$birthdate, "tzone") == Sys.timezone())) -stopifnot(!inherits(DF2$birthdate, "Date"), inherits(DF2$birthdate, "POSIXct"), isTRUE(attr(DF2$birthdate, "tzone") == "UTC")) +stopifnot( + !inherits(df_utc$birthdate, "Date"), + inherits(df_utc$birthdate, "POSIXct"), + identical(attr(df_utc$birthdate, "tzone"), "UTC") +) diff --git a/tests/test-keyring.R b/tests/test-keyring.R index aac5bb9..21915e2 100644 --- a/tests/test-keyring.R +++ b/tests/test-keyring.R @@ -1,60 +1,116 @@ library(REDCapExporter) -# Test if a new keyring can be built +keyring_dir <- file.path(tempdir(), paste0("redcapexporter-keyring-", Sys.getpid())) +dir.create(keyring_dir, showWarnings = FALSE, recursive = TRUE) +op <- options(keyring_file_dir = keyring_dir) +on.exit(options(op), add = TRUE) +on.exit(unlink(keyring_dir, recursive = TRUE, force = TRUE), add = TRUE) + kr <- keyring::backend_file$new() -try(kr$keyring_delete("testingring"), silent = TRUE) -#kr$keyring_create(password = "") -#kr$keyring_list() - -x <- tryCatch(REDCapExporter_keyring_check("testingring"), message = function(m) {m}) -stopifnot(identical(x$message, "File based keyring testingring has been created\n")) -x <- tryCatch(REDCapExporter_keyring_check("testingring"), message = function(m) {m}) -stopifnot(identical(x$message, "File based keyring testingring exists\n")) -stopifnot(isTRUE(REDCapExporter_keyring_check("testingring"))) - -# Expect that this will error because we are not interactive and a password -# prompt cannot be filled in -x <- - tryCatch( - REDCapExporter_add_api_token(project = 'testingproject', keyring = 'testingring'), - error = function(e) e - ) - -stopifnot(inherits(x, "error")) -stopifnot(isTRUE(grepl("Aborted setting keyring key", x$message))) - -# expect the get api token to fail as the token for the testingproject has not -# been set -x <- - tryCatch( - REDCapExporter_get_api_token(project = 'testingproject', keyring = 'testingring'), - error = function(e) e - ) - -stopifnot(inherits(x, "error")) -stopifnot(isTRUE(grepl("specified item could not be found in the keychain", x$message))) - -# create token -kr$set_with_value(service = "testingproject", password = "testingTOKEN", keyring = "testingring") -# verify you can get the token +keyring_name <- paste0("testingring_", Sys.getpid()) +service_name <- paste0("testingproject_", Sys.getpid()) + +# cleanup on exit +try(kr$keyring_delete(keyring_name), silent = TRUE) + +# keyring can be created or verified +msg1 <- NULL +withCallingHandlers( + { + ok1 <- REDCapExporter_keyring_check(keyring_name) + }, + message = function(m) { + msg1 <<- conditionMessage(m) + invokeRestart("muffleMessage") + } +) + stopifnot( - identical( - REDCapExporter_get_api_token(project = 'testingproject', keyring = 'testingring') - , - "testingTOKEN" - )) + isTRUE(ok1), + grepl("File based keyring", msg1), + grepl(keyring_name, msg1), + grepl("created|exists", msg1) +) +msg2 <- NULL +withCallingHandlers( + { + ok2 <- REDCapExporter_keyring_check(keyring_name) + }, + message = function(m) { + msg2 <<- conditionMessage(m) + invokeRestart("muffleMessage") + } +) -# the REDCapExporter_add_api_token should return a message that the token -# already exists stopifnot( - REDCapExporter_add_api_token(project = 'testingproject', keyring = 'testingring') + isTRUE(ok2), + grepl("File based keyring", msg2), + grepl(keyring_name, msg2), + grepl("exists", msg2) ) -x <- tryCatch( - REDCapExporter_add_api_token(project = 'testingproject', keyring = 'testingring'), - message = function(m) {m} +# Adding a token interactively should fail in non-interactive checks +err_add <- tryCatch( + REDCapExporter_add_api_token( + project = service_name, + keyring = keyring_name + ), + error = function(e) e +) + +stopifnot(inherits(err_add, "error")) + +# Missing token should error +err_get_missing <- tryCatch( + REDCapExporter_get_api_token( + project = service_name, + keyring = keyring_name + ), + error = function(e) e +) + +stopifnot(inherits(err_get_missing, "error")) + +# Set token directly through keyring backend +kr$keyring_unlock(keyring = keyring_name, password = "") +kr$set_with_value( + service = service_name, + password = "testingTOKEN", + keyring = keyring_name +) +kr$keyring_lock(keyring = keyring_name) + +# verify you can get the token +stopifnot(identical( + REDCapExporter_get_api_token( + project = service_name, + keyring = keyring_name + ), + "testingTOKEN" +)) + +# verify add_api_token short-circuits when token exists +msg3 <- NULL +withCallingHandlers( + { + ok3 <- REDCapExporter_add_api_token( + project = service_name, + keyring = keyring_name + ) + }, + message = function(m) { + msg3 <<- conditionMessage(m) + invokeRestart("muffleMessage") + } +) + +stopifnot( + isTRUE(ok3), + grepl("API token exists", msg3) ) -stopifnot(isTRUE(grepl("API token exists", x$message))) +# cleanup +try(kr$key_delete(service = service_name, keyring = keyring_name), silent = TRUE) +try(kr$keyring_delete(keyring_name), silent = TRUE) diff --git a/vignettes/redcap2package.Rmd b/vignettes/redcap2package.Rmd index 36627a5..74d2401 100644 --- a/vignettes/redcap2package.Rmd +++ b/vignettes/redcap2package.Rmd @@ -135,7 +135,7 @@ be accessed in an interactive R session. Let's install the package and explore the contents. -```{r} +```{r eval = FALSE} tar_ball <- devtools::build(pkg = prj_dir) tar_ball @@ -146,21 +146,20 @@ install.packages(pkgs = tar_ball, lib = temppath) library(rcd14465, lib.loc = temppath) ``` -```{r include = FALSE} +```{r include = FALSE, eval = FALSE} do.call(library, args = list(package = "rcd14465", character.only = TRUE, lib.loc = temppath)) ``` The available data sets: -```{r} +```{r eval = FALSE} data(package = "rcd14465")$results ``` A simple data analysis question: how many goals were scored by position? -```{r} +```{r eval = FALSE} aggregate(goals ~ position, data = record, FUN = sum) ``` -