diff --git a/.Rbuildignore b/.Rbuildignore index bfe1b3c..f39102a 100644 --- a/.Rbuildignore +++ b/.Rbuildignore @@ -11,4 +11,4 @@ README.Rmd ^pkgdown$ cran-comments.md .Rprofile - +meta_data.yaml diff --git a/.Renviron b/.Renviron deleted file mode 100644 index 60035e7..0000000 --- a/.Renviron +++ /dev/null @@ -1 +0,0 @@ -LOCAL=FALSE diff --git a/.gitignore b/.gitignore index a4309f0..e036162 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,5 @@ inst/doc docs .Rprofile +*.Rcheck +*.tar.gz diff --git a/DESCRIPTION b/DESCRIPTION index cb90a98..8c17aa3 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,7 +1,7 @@ Package: cohortBuilder Type: Package Title: Data Source Agnostic Filtering Tools -Version: 0.2.0 +Version: 0.3.0 Authors@R: c(person('Krystian', 'Igras', email = 'krystian8207@gmail.com', @@ -30,6 +30,7 @@ Imports: KeepSource: true RoxygenNote: 7.2.3 Suggests: + queryBuilder, testthat (>= 3.0.0), shiny, knitr, diff --git a/NAMESPACE b/NAMESPACE index 3036b60..d52987b 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -14,6 +14,8 @@ S3method(.post_binding,default) S3method(.post_filtering,default) S3method(.pre_filtering,default) S3method(.pre_filtering,tblist) +S3method(.print_filter,default) +S3method(.print_filter,query) S3method(.repro_code_tweak,tblist) S3method(.run_binding,default) S3method(.run_binding,tblist) @@ -27,12 +29,14 @@ S3method(cb_filter.date_range,tblist) S3method(cb_filter.discrete,tblist) S3method(cb_filter.discrete_text,tblist) S3method(cb_filter.multi_discrete,tblist) +S3method(cb_filter.query,tblist) S3method(cb_filter.range,tblist) S3method(filter,character) S3method(filter,date_range) S3method(filter,discrete) S3method(filter,discrete_text) S3method(filter,multi_discrete) +S3method(filter,query) S3method(filter,range) S3method(rm_filter,Cohort) S3method(rm_filter,Source) @@ -55,6 +59,7 @@ export(.init_step) export(.post_binding) export(.post_filtering) export(.pre_filtering) +export(.print_filter) export(.repro_code_tweak) export(.run_binding) export(Source) @@ -70,6 +75,7 @@ export(cb_filter.date_range) export(cb_filter.discrete) export(cb_filter.discrete_text) export(cb_filter.multi_discrete) +export(cb_filter.query) export(cb_filter.range) export(code) export(cohort) diff --git a/NEWS.md b/NEWS.md index 7f2038f..16f5150 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,3 +1,8 @@ +# cohortBuilder 0.3.0 + +* Add new filter of type `"query"` that allows to configure complex filtering rules with `queryBuilder` package. +* Add filter-focused `.print_filter` method responsible for printing filter values when calling `sum_up` on cohort. + # cohortBuilder 0.2.0 * Changed the way reproducible code is returned. Now more flexibility is allowed with using e.g. `.repro_code_tweak` method. diff --git a/R/bind_keys.R b/R/bind_keys.R index 06665bb..e757938 100644 --- a/R/bind_keys.R +++ b/R/bind_keys.R @@ -63,22 +63,22 @@ primary_keys <- function(...) { #' #' In order to understand binding keys concept we need to describe the following functions: #' \itemize{ -#' \item{\link{data_key}}{ Defines which table column should be used to describe relation.} -#' \item{bind_key}{ Defines what relation occur between datasets.} -#' \item{bind_keys}{ If needed, allows to define more than one relation.} +#' \item{\link{data_key} - Defines which table column should be used to describe relation.} +#' \item{\code{bind_key} - Defines what relation occur between datasets.} +#' \item{\code{bind_keys} - If needed, allows to define more than one relation.} #' } #' #' - `data_key` - requires to provide two parameters: #' \itemize{ -#' \item{dataset}{ Name of the dataset existing in Source.} -#' \item{key}{ Single character string or vector storing column names that are keys, which should be used to describe relation.} +#' \item{\code{dataset} - Name of the dataset existing in Source.} +#' \item{\code{key} - Single character string or vector storing column names that are keys, which should be used to describe relation.} #' } #' For example `data_key('books', 'author_id')`. #' #' - `bind_key` - requires to provide two obligatory parameters #' \itemize{ -#' \item{update}{ Data key describing which table should be updated.} -#' \item{...}{ \strong{Triggering data keys}. One or more data keys describing on which dataset(s) the one in `update` is dependent.} +#' \item{\code{update} - Data key describing which table should be updated.} +#' \item{\code{...} - \strong{Triggering data keys}. One or more data keys describing on which dataset(s) the one in `update` is dependent.} #' } #' The output of `bind_key` function is named \strong{binding key}. #' `bind_key` offers two extra parameters `post` and `activate`. @@ -97,8 +97,8 @@ primary_keys <- function(...) { #' #' You may achieve more flexibility with two parameters: #' \itemize{ -#' \item{activate}{} -#' \item{post}{} +#' \item{\code{activate}} +#' \item{\code{post}} #' } #' #' \strong{Active tables and `activate` parameter} diff --git a/R/cohort_methods.R b/R/cohort_methods.R index d0a8dd7..30deab1 100644 --- a/R/cohort_methods.R +++ b/R/cohort_methods.R @@ -338,6 +338,7 @@ Cohort <- R6::R6Class( for (step_state in state) { for (filter_state in step_state$filters) { if (filter_state$type == "date_range") { + filter_state$range <- na_fix(filter_state$range) filter_state$range <- as.Date(filter_state$range) } add_filter( @@ -870,14 +871,14 @@ cohort <- function(source, ..., run_flow = FALSE, #' The list of methods designed for managing the Cohort configuration and state. #' #' \itemize{ -#' \item{\link{add_source}}{ Add source to Cohort object.} -#' \item{\link{update_source}}{ Update Cohort object source.} -#' \item{\link{add_step}}{ Add step to Cohort object.} -#' \item{\link{rm_step}}{ Remove step from Cohort object.} -#' \item{\link{add_filter}}{ Add filter to Cohort step.} -#' \item{\link{rm_filter}}{ Remove filter from Cohort step.} -#' \item{\link{update_filter}}{ Update filter configuration.} -#' \item{\link{run}}{ Run data filtering.} +#' \item{\link{add_source} - Add source to Cohort object.} +#' \item{\link{update_source} - Update Cohort object source.} +#' \item{\link{add_step} - Add step to Cohort object.} +#' \item{\link{rm_step} - Remove step from Cohort object.} +#' \item{\link{add_filter} - Add filter to Cohort step.} +#' \item{\link{rm_filter} - Remove filter from Cohort step.} +#' \item{\link{update_filter} - Update filter configuration.} +#' \item{\link{run} - Run data filtering.} #' } #' #' @return The object of class `Cohort` having the modified configuration dependent on the used method. @@ -1063,15 +1064,15 @@ run <- function(x, min_step_id, step_id) { #' The list of methods designed for getting Cohort-related details. #' #' \itemize{ -#' \item{\link{plot_data}}{ Plot filter related Cohort data.} -#' \item{\link{stat}}{ Get Cohort related statistics.} -#' \item{\link{code}}{ Return reproducible data filtering code.} -#' \item{\link{get_data}}{ Get step related data.} -#' \item{\link{sum_up}}{ Sum up Cohort state.} -#' \item{\link{get_state}}{ Save Cohort state.} -#' \item{\link{restore}}{ Restore Cohort state.} -#' \item{\link{attrition}}{ Show attrition plot.} -#' \item{\link{description}}{ Show Source or filter related description.} +#' \item{\link{plot_data} - Plot filter related Cohort data.} +#' \item{\link{stat} - Get Cohort related statistics.} +#' \item{\link{code} - Return reproducible data filtering code.} +#' \item{\link{get_data} - Get step related data.} +#' \item{\link{sum_up} - Sum up Cohort state.} +#' \item{\link{get_state} - Save Cohort state.} +#' \item{\link{restore} - Restore Cohort state.} +#' \item{\link{attrition} - Show attrition plot.} +#' \item{\link{description} - Show Source or filter related description.} #' } #' #' @return Various type outputs dependent on the selected method. diff --git a/R/data.R b/R/data.R index 02eed79..f50a616 100644 --- a/R/data.R +++ b/R/data.R @@ -6,32 +6,32 @@ #' #' \strong{books} - books on store #' \describe{ -#' \item{isbn}{book ISBN number} -#' \item{title}{book title} -#' \item{genre}{comma separated book genre} -#' \item{publisher}{name of book publisher} -#' \item{author}{name of book author} -#' \item{copies}{total number of book copies on store} +#' \item{\code{isbn}}{book ISBN number} +#' \item{\code{title}}{book title} +#' \item{\code{genre}}{comma separated book genre} +#' \item{\code{publisher}}{name of book publisher} +#' \item{\code{author}}{name of book author} +#' \item{\code{copies}}{total number of book copies on store} #' } #' \strong{borrowers} - registered library members #' \describe{ -#' \item{id}{member unique id} -#' \item{registered}{date the member joined library} -#' \item{address}{member address} -#' \item{name}{full member name} -#' \item{phone_number}{member phone number} -#' \item{program}{membership program type (standard, premium or vip)} +#' \item{\code{id}}{member unique id} +#' \item{\code{registered}}{date the member joined library} +#' \item{\code{address}}{member address} +#' \item{\code{name}}{full member name} +#' \item{\code{phone_number}}{member phone number} +#' \item{\code{program}}{membership program type (standard, premium or vip)} #' } #' \strong{issues} - borrowed books events #' \describe{ -#' \item{id}{unique event id} -#' \item{borrower_id}{id of the member that borrowed the book} -#' \item{isbn}{is of the borrowed book} -#' \item{date}{date of borrow event} +#' \item{\code{id}}{unique event id} +#' \item{\code{borrower_id}}{id of the member that borrowed the book} +#' \item{\code{isbn}}{is of the borrowed book} +#' \item{\code{date}}{date of borrow event} #' } #' \strong{returns} - returned books events #' \describe{ -#' \item{id}{event id equal to borrow issue id} -#' \item{date}{date of return event} +#' \item{\code{id}}{event id equal to borrow issue id} +#' \item{\code{date}}{date of return event} #' } "librarian" diff --git a/R/filter.R b/R/filter.R index 260fb12..d3719fb 100644 --- a/R/filter.R +++ b/R/filter.R @@ -109,7 +109,17 @@ new_filter <- function(filter_type, source_type, input_param = "value", extra_pa utils::file.edit(file) } -print_filter <- function(filter, data_objects) { +#' Method for printing filter details +#' +#' @param filter The defined filter object. +#' @param data_objects List of data objects for the underlying filtering step. +#' @export +.print_filter <- function(filter, data_objects) { + UseMethod(".print_filter", filter) +} + +#' @export +.print_filter.default <- function(filter, data_objects) { meta <- filter$get_params() params <- meta[setdiff(names(meta), static_params)] cat(glue::glue("-> Filter ID: {filter$id}"), sep = "\n") @@ -321,3 +331,44 @@ filter.multi_discrete <- function(type, id, name, ..., description = NULL, cb_filter.multi_discrete <- function(source, ...) { UseMethod("cb_filter.multi_discrete", source) } + +#' @rdname filter-types +#' @export +filter.query <- function(type, id, name, ..., active = getOption("cb_active_filter", default = TRUE)) { + args <- append( + environment() %>% as.list() %>% purrr::keep(~ !is.symbol(.x)), + list(...) + ) + + .as_constructor( + function(source) { + do.call( + cb_filter.query, + append(list(source = source), args) + ) + } + ) +} + +#' @rdname filter-source-types +#' @export +cb_filter.query <- function(source, ...) { + UseMethod("cb_filter.query", source) +} + +#' @export +.print_filter.query <- function(filter, data_objects) { + meta <- filter$get_params() + params <- meta[setdiff(names(meta), static_params)] + cat(glue::glue("-> Filter ID: {filter$id}"), sep = "\n") + cat(glue::glue(" Filter Type: {filter$type}"), sep = "\n") + cat(" Filter Parameters:", sep = "\n") + for (param_name in names(params)) { + if (param_name == "value") { + cat(glue::glue(" {param_name}: {deparse(queryBuilder::queryToExpr(params[[param_name]]))}"), sep = "\n") + } else { + cat(glue::glue(" {param_name}: {paste(params[[param_name]], collapse = ', ')}"), sep = "\n") + } + } +} + diff --git a/R/hooks.R b/R/hooks.R index 77135ea..2a51414 100644 --- a/R/hooks.R +++ b/R/hooks.R @@ -9,8 +9,8 @@ #' #' Each `hook` is a function of two obligatory parameters: #' \itemize{ -#' \item{public}{ Cohort object.} -#' \item{private}{ Private environment of Cohort object.} +#' \item{\code{public} - Cohort object.} +#' \item{\code{private} - Private environment of Cohort object.} #' } #' #' When Cohort method, for which hook is defined, allow to pass custom parameters, @@ -18,9 +18,9 @@ #' #' For example `Cohort$remove_step` has three parameters: #' \itemize{ -#' \item{step_id}{} -#' \item{run_flow}{} -#' \item{hook}{} +#' \item{\code{step_id}} +#' \item{\code{run_flow}} +#' \item{\code{hook}} #' } #' By the implementation, the parameters that we should skip are `run_flow` and `hook`, #' so the hook should have three parameters `public`, `private` and `step_id`. @@ -40,7 +40,13 @@ #' } #' #' 'Pre' hooks are defined with 'pre__hook' and 'Post' ones as 'post__hook'. -#' As a result calling `add_hook("pre_remove_step_hook", function(public, private, step_id) {...})` +#' As a result calling: +#' \preformatted{ +#' add_hook( +#' "pre_remove_step_hook", +#' function(public, private, step_id) {...} +#' ) +#' } #' will result with specifying a new pre-hook for `remove_step` method. #' #' You may add as many hooks as you want. diff --git a/R/source_methods.R b/R/source_methods.R index af6e383..4e9a53a 100644 --- a/R/source_methods.R +++ b/R/source_methods.R @@ -237,23 +237,23 @@ set_source <- function(dtconn, ..., primary_keys = NULL, binding_keys = NULL, #' In order to make new source type layer functioning, the following list of methods #' should be defined: #' \itemize{ -#' \item{.init_source}{ Defines how to extract data object from source. +#' \item{\code{.init_source} - Defines how to extract data object from source. #' Each filtering step assumes to be operating on resulting data object #' (further named data_object) and returns object of the same type and structure.} -#' \item{.collect_data}{ Defines how to collect data (into R memory) from `data_object`.} -#' \item{.get_stats}{ Defines what `data_object` statistics should be +#' \item{\code{.collect_data} - Defines how to collect data (into R memory) from `data_object`.} +#' \item{\code{.get_stats} - Defines what `data_object` statistics should be #' calculated and how. When provided the stats can be extracted using \link{stat}.} -#' \item{.pre_filtering}{ (optional) Defines what operation on `data_object` should be +#' \item{\code{.pre_filtering} - (optional) Defines what operation on `data_object` should be #' performed before applying filtering in the step.} -#' \item{.post_filtering}{ (optional) Defines what operation on `data_object` should be +#' \item{\code{.post_filtering} - (optional) Defines what operation on `data_object` should be #' performed after applying filtering in the step (before running binding).} -#' \item{.post_binding}{ (optional) Defines what operation on `data_object` should be +#' \item{\code{.post_binding} - (optional) Defines what operation on `data_object` should be #' performed after applying binding in the step.} -#' \item{.run_binding}{ (optional) Defines how to handle post filtering data binding. +#' \item{\code{.run_binding} - (optional) Defines how to handle post filtering data binding. #' See more about binding keys at \link{binding-keys}.} -#' \item{.get_attrition_count and .get_attrition_label}{ Methods defining how to +#' \item{\code{.get_attrition_count and .get_attrition_label} - Methods defining how to #' get statistics and labels for attrition plot.} -#' \item{.repro_code_tweak}{ (optional) Default method passed as a `modifier` +#' \item{\code{.repro_code_tweak} - (optional) Default method passed as a `modifier` #' argument of \link{code} function. Aims to modify reproducible code into the final format.} #' } #' Except from the above methods, you may extend the existing or new source with providing @@ -335,11 +335,11 @@ NULL #' The list of methods designed for managing the Source configuration and state. #' #' \itemize{ -#' \item{\link{add_step}}{ Add step to Source object.} -#' \item{\link{rm_step}}{ Remove step from Source object.} -#' \item{\link{add_filter}}{ Add filter to Source step.} -#' \item{\link{rm_filter}}{ Remove filter from Source step.} -#' \item{\link{update_filter}}{ Update filter configuration.} +#' \item{\link{add_step} - Add step to Source object.} +#' \item{\link{rm_step} - Remove step from Source object.} +#' \item{\link{add_filter} - Add filter to Source step.} +#' \item{\link{rm_filter} - Remove filter from Source step.} +#' \item{\link{update_filter} - Update filter configuration.} #' } #' #' @name managing-source diff --git a/R/source_tblist.R b/R/source_tblist.R index 47a0a20..e4227d9 100644 --- a/R/source_tblist.R +++ b/R/source_tblist.R @@ -636,7 +636,7 @@ cb_filter.multi_discrete.tblist <- function( return(params) }, get_data = function(data_object) { - data_object[[dataset]][[variables]] + data_object[[dataset]][, variables] }, get_defaults = function(data_object, cache_object) { list(values = names(cache_object$choices)) @@ -644,6 +644,89 @@ cb_filter.multi_discrete.tblist <- function( ) } +#' @rdname filter-source-types +#' @param dataset Dataset name to be used for filtering. +#' @param variables Dataset variables used for filtering. +#' @param value Value(s) to be used for filtering. +#' @param description Filter description (optional). +#' @param keep_na If `TRUE`, NA values are included. +#' @export +cb_filter.query.tblist <- function( + source, type = "query", id = .gen_id(), name = id, variables, value = NA, + dataset, keep_na = TRUE, ..., description = NULL, active = TRUE) { + args <- list(...) + + def_filter( + type = type, + id = id, + name = name, + input_param = "value", + filter_data = function(data_object) { + if (keep_na && !identical(value, NA)) { + # keep_na !value_na start + data_object[[dataset]] <- data_object[[dataset]] %>% + dplyr::filter(!!queryBuilder::queryToExpr(value, keep_na = keep_na)) + # keep_na !value_na end + } + if (!keep_na && !identical(value, NA)) { + # !keep_na !value_na start + data_object[[dataset]] <- data_object[[dataset]] %>% + dplyr::filter(!!queryBuilder::queryToExpr(value)) + # !keep_na !value_na end + } + attr(data_object[[dataset]], "filtered") <- TRUE # code include + data_object + }, + get_stats = function(data_object, name) { + if (missing(name)) { + name <- c("n_data", "specs", "n_missing") + } + variables <- unlist(variables) + stat_from_column <- base::get("stat_from_column", envir = asNamespace("queryBuilder"), inherits = FALSE) + stats <- list( + specs = if ("specs" %in% name) data_object[[dataset]][variables] %>% purrr::imap(stat_from_column), + n_data = if ("n_data" %in% name) data_object[[dataset]][variables] %>% nrow(), + n_missing = if ("n_missing" %in% name) data_object[[dataset]][variables] %>% is.na() %>% colSums() %>% as.list() + ) + if (length(name) == 1) { + return(stats[[name]]) + } else { + return(stats[name]) + } + }, + plot_data = function(data_object) { + if (nrow(data_object[[dataset]])) { + data_object[[dataset]][variables] %>% + purrr::map(table) %>% + purrr::imap_dfc(group_stats) %>% + as.matrix() %>% + graphics::barplot() + } else { + graphics::barplot(0, ylim = c(0, 0.1), main = "No data") + } + }, + get_params = function(name) { + params <- list( + dataset = dataset, + variables = variables, + value = value, + keep_na = keep_na, + description = description, + active = active, + ... + ) + if (!missing(name)) return(params[[name]]) + return(params) + }, + get_data = function(data_object) { + data_object[[dataset]][, variables, drop = FALSE] + }, + get_defaults = function(data_object, cache_object) { + list(value = names(cache_object$choices)) + } + ) +} + #' @export .run_binding.tblist <- function(source, binding_key, data_object_pre, data_object_post, ...) { binding_dataset <- binding_key$update$dataset diff --git a/R/step.R b/R/step.R index b98ce5e..3f663bf 100644 --- a/R/step.R +++ b/R/step.R @@ -106,7 +106,7 @@ next_step <- function(idx) { print_step <- function(step) { cat(glue::glue(">> Step ID: {step$id}"), sep = "\n") step$filters %>% - purrr::walk(print_filter, data_objects = NULL) + purrr::walk(.print_filter, data_objects = NULL) } #' Create filtering step diff --git a/README.md b/README.md index ef8598e..0ada011 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # cohortBuilder -[![version](https://img.shields.io/static/v1.svg?label=github.com&message=v.0.2.0&color=ff69b4)](https://r-world-devs.github.io/cohortBuilder/) +[![version](https://img.shields.io/static/v1.svg?label=github.com&message=v.0.3.0&color=ff69b4)](https://r-world-devs.github.io/cohortBuilder/) [![lifecycle](https://img.shields.io/badge/lifecycle-experimental-orange.svg)](https://lifecycle.r-lib.org/articles/stages.html#experimental) ## Overview @@ -115,7 +115,7 @@ get_data(coh) #> 3 Mr. Brandan Oberbrunner 568-044-7463 vip #> 4 Lloyd Adams III 001-017-0211 standard #> 5 Randy Ziemann 895-995-2326 premium -#> # … with 3 more rows +#> # ℹ 3 more rows #> #> $issues #> # A tibble: 50 × 4 @@ -126,7 +126,7 @@ get_data(coh) #> 3 000003 000016 0-09-177373-3 2014-09-28 #> 4 000004 000005 0-224-06252-2 2005-11-14 #> 5 000005 000004 0-340-89696-5 2006-03-19 -#> # … with 45 more rows +#> # ℹ 45 more rows #> #> $returns #> # A tibble: 30 × 2 @@ -137,7 +137,7 @@ get_data(coh) #> 3 000004 2005-12-29 #> 4 000005 2006-03-26 #> 5 000006 2016-08-30 -#> # … with 25 more rows +#> # ℹ 25 more rows #> #> attr(,"class") #> [1] "tblist" @@ -196,7 +196,7 @@ get_data(coh, step_id = 1) #> 3 Mr. Brandan Oberbrunner 568-044-7463 vip #> 4 Lloyd Adams III 001-017-0211 standard #> 5 Randy Ziemann 895-995-2326 premium -#> # … with 3 more rows +#> # ℹ 3 more rows #> #> $issues #> # A tibble: 50 × 4 @@ -207,7 +207,7 @@ get_data(coh, step_id = 1) #> 3 000003 000016 0-09-177373-3 2014-09-28 #> 4 000004 000005 0-224-06252-2 2005-11-14 #> 5 000005 000004 0-340-89696-5 2006-03-19 -#> # … with 45 more rows +#> # ℹ 45 more rows #> #> $returns #> # A tibble: 30 × 2 @@ -218,7 +218,7 @@ get_data(coh, step_id = 1) #> 3 000004 2005-12-29 #> 4 000005 2006-03-26 #> 5 000006 2016-08-30 -#> # … with 25 more rows +#> # ℹ 25 more rows #> #> attr(,"class") #> [1] "tblist" @@ -253,7 +253,7 @@ get_data(coh, step_id = 2) #> 3 Mr. Brandan Oberbrunner 568-044-7463 vip #> 4 Lloyd Adams III 001-017-0211 standard #> 5 Randy Ziemann 895-995-2326 premium -#> # … with 3 more rows +#> # ℹ 3 more rows #> #> $issues #> # A tibble: 50 × 4 @@ -264,7 +264,7 @@ get_data(coh, step_id = 2) #> 3 000003 000016 0-09-177373-3 2014-09-28 #> 4 000004 000005 0-224-06252-2 2005-11-14 #> 5 000005 000004 0-340-89696-5 2006-03-19 -#> # … with 45 more rows +#> # ℹ 45 more rows #> #> $returns #> # A tibble: 30 × 2 @@ -275,7 +275,7 @@ get_data(coh, step_id = 2) #> 3 000004 2005-12-29 #> 4 000005 2006-03-26 #> 5 000006 2016-08-30 -#> # … with 25 more rows +#> # ℹ 25 more rows #> #> attr(,"class") #> [1] "tblist" @@ -316,7 +316,7 @@ get_data(coh, step_id = 2) #> 3 Mr. Brandan Oberbrunner 568-044-7463 vip #> 4 Lloyd Adams III 001-017-0211 standard #> 5 Randy Ziemann 895-995-2326 premium -#> # … with 3 more rows +#> # ℹ 3 more rows #> #> $issues #> # A tibble: 50 × 4 @@ -327,7 +327,7 @@ get_data(coh, step_id = 2) #> 3 000003 000016 0-09-177373-3 2014-09-28 #> 4 000004 000005 0-224-06252-2 2005-11-14 #> 5 000005 000004 0-340-89696-5 2006-03-19 -#> # … with 45 more rows +#> # ℹ 45 more rows #> #> $returns #> # A tibble: 30 × 2 @@ -338,7 +338,7 @@ get_data(coh, step_id = 2) #> 3 000004 2005-12-29 #> 4 000005 2006-03-26 #> 5 000006 2016-08-30 -#> # … with 25 more rows +#> # ℹ 25 more rows #> #> attr(,"class") #> [1] "tblist" diff --git a/cran-comments.md b/cran-comments.md deleted file mode 100644 index ee57621..0000000 --- a/cran-comments.md +++ /dev/null @@ -1,59 +0,0 @@ -## Test environments -* local check - Ubuntu 20.04.5 LTS, R 4.1.2 (2021-11-01) -* win-builder - R version 4.1.3 (2022-03-10) - R version 4.2.2 (2022-10-31 ucrt) - R Under development (unstable) (2023-02-27 r83911 ucrt) - -## `R CMD check cohortBuilder_0.2.0.tar.gz --as-cran` results - -``` -* using log directory ‘/home/krystian/projects/cohortBuilder.Rcheck’ -* using R version 4.2.1 (2022-06-23) -* using platform: x86_64-pc-linux-gnu (64-bit) -... -Status: OK -``` - -## `devtools::check()` results - -``` -0 errors ✓ | 0 warnings ✓ | 0 notes ✓ -``` - -## win-builder result - -``` -* using log directory 'd:/RCompile/CRANguest/R-oldrelease/cohortBuilder.Rcheck' -* using R version 4.1.3 (2022-03-10) -* using platform: x86_64-w64-mingw32 (64-bit) -* using session charset: ISO8859-1 -... -* checking CRAN incoming feasibility ... Note_to_CRAN_maintainers -Maintainer: 'Krystian Igras ' -... -Status: OK -``` - -``` -* using log directory 'd:/RCompile/CRANguest/R-release/cohortBuilder.Rcheck' -* using R version 4.2.2 (2022-10-31 ucrt) -* using platform: x86_64-w64-mingw32 (64-bit) -... -* checking CRAN incoming feasibility ... Note_to_CRAN_maintainers -Maintainer: 'Krystian Igras ' -... -Status: OK -``` - -``` -* using log directory 'd:/RCompile/CRANguest/R-devel/cohortBuilder.Rcheck' -* using R Under development (unstable) (2023-02-27 r83911 ucrt) -* using platform: x86_64-w64-mingw32 (64-bit) -... -* checking CRAN incoming feasibility ... [10s] Note_to_CRAN_maintainers -Maintainer: 'Krystian Igras ' -... -Status: OK -``` diff --git a/examples/query-filter.R b/examples/query-filter.R new file mode 100644 index 0000000..a5ccca6 --- /dev/null +++ b/examples/query-filter.R @@ -0,0 +1,49 @@ +library(queryBuilder) +library(cohortBuilder) +library(magrittr) + +my_query <- queryGroup( + condition = "AND", + queryRule("Sepal.Length", "greater", 5), + queryGroup( + condition = "OR", + queryRule( + field = "Petal.Length", + operator = "greater", + value = 3 + ), + queryRule( + field = "Petal.Width", + operator = "less", + value = 1 + ) + ) +) +queryToExpr(my_query) + +coh <- cohort( + source = set_source( + tblist( + iris = iris, mtcars = mtcars + ) + ) +) %>% + add_filter( + filter("discrete", id = "species", dataset = "iris", variable = "Species", value = c("setosa", "versicolor")) + ) %>% + add_filter( + filter( + "query", id = "gen_query", dataset = "iris", variables = c("Sepal.Length", "Petal.Length", "Petal.Width"), + value = my_query, keep_na = FALSE + ) + ) + +coh$sum_up_state() +sum_up(coh) + +coh <- coh %>% run() + +coh %>% code(include_methods = NULL) + +get_data(coh, 1, state = "post") + diff --git a/man/binding-keys.Rd b/man/binding-keys.Rd index 7f0e3be..c946dff 100644 --- a/man/binding-keys.Rd +++ b/man/binding-keys.Rd @@ -64,22 +64,22 @@ As a result, whenever `books` or `authors` is filtered, the other table will be In order to understand binding keys concept we need to describe the following functions: \itemize{ - \item{\link{data_key}}{ Defines which table column should be used to describe relation.} - \item{bind_key}{ Defines what relation occur between datasets.} - \item{bind_keys}{ If needed, allows to define more than one relation.} + \item{\link{data_key} - Defines which table column should be used to describe relation.} + \item{\code{bind_key} - Defines what relation occur between datasets.} + \item{\code{bind_keys} - If needed, allows to define more than one relation.} } - `data_key` - requires to provide two parameters: \itemize{ - \item{dataset}{ Name of the dataset existing in Source.} - \item{key}{ Single character string or vector storing column names that are keys, which should be used to describe relation.} + \item{\code{dataset} - Name of the dataset existing in Source.} + \item{\code{key} - Single character string or vector storing column names that are keys, which should be used to describe relation.} } For example `data_key('books', 'author_id')`. - `bind_key` - requires to provide two obligatory parameters \itemize{ - \item{update}{ Data key describing which table should be updated.} - \item{...}{ \strong{Triggering data keys}. One or more data keys describing on which dataset(s) the one in `update` is dependent.} + \item{\code{update} - Data key describing which table should be updated.} + \item{\code{...} - \strong{Triggering data keys}. One or more data keys describing on which dataset(s) the one in `update` is dependent.} } The output of `bind_key` function is named \strong{binding key}. `bind_key` offers two extra parameters `post` and `activate`. @@ -98,8 +98,8 @@ sequentially, taking into account returned data from the previous bindings. You may achieve more flexibility with two parameters: \itemize{ - \item{activate}{} - \item{post}{} + \item{\code{activate}} + \item{\code{post}} } \strong{Active tables and `activate` parameter} diff --git a/man/cohort-methods.Rd b/man/cohort-methods.Rd index c13d38d..f9b58e2 100644 --- a/man/cohort-methods.Rd +++ b/man/cohort-methods.Rd @@ -11,14 +11,14 @@ Various type outputs dependent on the selected method. The list of methods designed for getting Cohort-related details. \itemize{ - \item{\link{plot_data}}{ Plot filter related Cohort data.} - \item{\link{stat}}{ Get Cohort related statistics.} - \item{\link{code}}{ Return reproducible data filtering code.} - \item{\link{get_data}}{ Get step related data.} - \item{\link{sum_up}}{ Sum up Cohort state.} - \item{\link{get_state}}{ Save Cohort state.} - \item{\link{restore}}{ Restore Cohort state.} - \item{\link{attrition}}{ Show attrition plot.} - \item{\link{description}}{ Show Source or filter related description.} + \item{\link{plot_data} - Plot filter related Cohort data.} + \item{\link{stat} - Get Cohort related statistics.} + \item{\link{code} - Return reproducible data filtering code.} + \item{\link{get_data} - Get step related data.} + \item{\link{sum_up} - Sum up Cohort state.} + \item{\link{get_state} - Save Cohort state.} + \item{\link{restore} - Restore Cohort state.} + \item{\link{attrition} - Show attrition plot.} + \item{\link{description} - Show Source or filter related description.} } } diff --git a/man/dot-print_filter.Rd b/man/dot-print_filter.Rd new file mode 100644 index 0000000..928d01b --- /dev/null +++ b/man/dot-print_filter.Rd @@ -0,0 +1,16 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/filter.R +\name{.print_filter} +\alias{.print_filter} +\title{Method for printing filter details} +\usage{ +.print_filter(filter, data_objects) +} +\arguments{ +\item{filter}{The defined filter object.} + +\item{data_objects}{List of data objects for the underlying filtering step.} +} +\description{ +Method for printing filter details +} diff --git a/man/figures/README-unnamed-chunk-8-1.png b/man/figures/README-unnamed-chunk-8-1.png index 1df7b15..216989a 100644 Binary files a/man/figures/README-unnamed-chunk-8-1.png and b/man/figures/README-unnamed-chunk-8-1.png differ diff --git a/man/filter-source-types.Rd b/man/filter-source-types.Rd index bf040dc..58b1b4c 100644 --- a/man/filter-source-types.Rd +++ b/man/filter-source-types.Rd @@ -7,11 +7,13 @@ \alias{cb_filter.range} \alias{cb_filter.date_range} \alias{cb_filter.multi_discrete} +\alias{cb_filter.query} \alias{cb_filter.discrete.tblist} \alias{cb_filter.discrete_text.tblist} \alias{cb_filter.range.tblist} \alias{cb_filter.date_range.tblist} \alias{cb_filter.multi_discrete.tblist} +\alias{cb_filter.query.tblist} \title{Filter Source types methods} \usage{ cb_filter.discrete(source, ...) @@ -24,6 +26,8 @@ cb_filter.date_range(source, ...) cb_filter.multi_discrete(source, ...) +cb_filter.query(source, ...) + \method{cb_filter.discrete}{tblist}( source, type = "discrete", @@ -92,6 +96,20 @@ cb_filter.multi_discrete(source, ...) description = NULL, active = TRUE ) + +\method{cb_filter.query}{tblist}( + source, + type = "query", + id = .gen_id(), + name = id, + variables, + value = NA, + dataset, + keep_na = TRUE, + ..., + description = NULL, + active = TRUE +) } \arguments{ \item{source}{Source object.} @@ -121,7 +139,7 @@ cb_filter.multi_discrete(source, ...) \item{values}{Named list of values to be applied in filtering. The names should relate to the ones included in `variables` parameter.} -\item{variables}{Vector of variable names to be used in filtering.} +\item{variables}{Dataset variables used for filtering.} } \value{ List of filter-specific metadata and methods - result of evaluation of diff --git a/man/filter-types.Rd b/man/filter-types.Rd index 07a1063..c44689e 100644 --- a/man/filter-types.Rd +++ b/man/filter-types.Rd @@ -7,6 +7,7 @@ \alias{filter.range} \alias{filter.date_range} \alias{filter.multi_discrete} +\alias{filter.query} \title{Filter types} \usage{ \method{filter}{discrete}( @@ -52,6 +53,14 @@ description = NULL, active = getOption("cb_active_filter", default = TRUE) ) + +\method{filter}{query}( + type, + id, + name, + ..., + active = getOption("cb_active_filter", default = TRUE) +) } \arguments{ \item{type}{Character string defining filter type (having class of the same value as type).} diff --git a/man/hooks.Rd b/man/hooks.Rd index 32e0737..2ce688e 100644 --- a/man/hooks.Rd +++ b/man/hooks.Rd @@ -29,8 +29,8 @@ storing functions (hooks) executed before and after the method is run respective Each `hook` is a function of two obligatory parameters: \itemize{ - \item{public}{ Cohort object.} - \item{private}{ Private environment of Cohort object.} + \item{\code{public} - Cohort object.} + \item{\code{private} - Private environment of Cohort object.} } When Cohort method, for which hook is defined, allow to pass custom parameters, @@ -38,9 +38,9 @@ the ones should be also available in hook definition (with some exclusions, see For example `Cohort$remove_step` has three parameters: \itemize{ - \item{step_id}{} - \item{run_flow}{} - \item{hook}{} + \item{\code{step_id}} + \item{\code{run_flow}} + \item{\code{hook}} } By the implementation, the parameters that we should skip are `run_flow` and `hook`, so the hook should have three parameters `public`, `private` and `step_id`. @@ -60,7 +60,13 @@ remove_step = function(step_id, run_flow = FALSE, } 'Pre' hooks are defined with 'pre__hook' and 'Post' ones as 'post__hook'. -As a result calling `add_hook("pre_remove_step_hook", function(public, private, step_id) {...})` +As a result calling: +\preformatted{ +add_hook( + "pre_remove_step_hook", + function(public, private, step_id) {...} +) +} will result with specifying a new pre-hook for `remove_step` method. You may add as many hooks as you want. diff --git a/man/librarian.Rd b/man/librarian.Rd index 95c3692..79e1190 100644 --- a/man/librarian.Rd +++ b/man/librarian.Rd @@ -9,33 +9,33 @@ A list of four data frames: \strong{books} - books on store \describe{ - \item{isbn}{book ISBN number} - \item{title}{book title} - \item{genre}{comma separated book genre} - \item{publisher}{name of book publisher} - \item{author}{name of book author} - \item{copies}{total number of book copies on store} + \item{\code{isbn}}{book ISBN number} + \item{\code{title}}{book title} + \item{\code{genre}}{comma separated book genre} + \item{\code{publisher}}{name of book publisher} + \item{\code{author}}{name of book author} + \item{\code{copies}}{total number of book copies on store} } \strong{borrowers} - registered library members \describe{ - \item{id}{member unique id} - \item{registered}{date the member joined library} - \item{address}{member address} - \item{name}{full member name} - \item{phone_number}{member phone number} - \item{program}{membership program type (standard, premium or vip)} + \item{\code{id}}{member unique id} + \item{\code{registered}}{date the member joined library} + \item{\code{address}}{member address} + \item{\code{name}}{full member name} + \item{\code{phone_number}}{member phone number} + \item{\code{program}}{membership program type (standard, premium or vip)} } \strong{issues} - borrowed books events \describe{ - \item{id}{unique event id} - \item{borrower_id}{id of the member that borrowed the book} - \item{isbn}{is of the borrowed book} - \item{date}{date of borrow event} + \item{\code{id}}{unique event id} + \item{\code{borrower_id}}{id of the member that borrowed the book} + \item{\code{isbn}}{is of the borrowed book} + \item{\code{date}}{date of borrow event} } \strong{returns} - returned books events \describe{ - \item{id}{event id equal to borrow issue id} - \item{date}{date of return event} + \item{\code{id}}{event id equal to borrow issue id} + \item{\code{date}}{date of return event} } } \usage{ diff --git a/man/managing-cohort.Rd b/man/managing-cohort.Rd index 20e5010..c4d6266 100644 --- a/man/managing-cohort.Rd +++ b/man/managing-cohort.Rd @@ -10,13 +10,13 @@ The object of class `Cohort` having the modified configuration dependent on the The list of methods designed for managing the Cohort configuration and state. \itemize{ - \item{\link{add_source}}{ Add source to Cohort object.} - \item{\link{update_source}}{ Update Cohort object source.} - \item{\link{add_step}}{ Add step to Cohort object.} - \item{\link{rm_step}}{ Remove step from Cohort object.} - \item{\link{add_filter}}{ Add filter to Cohort step.} - \item{\link{rm_filter}}{ Remove filter from Cohort step.} - \item{\link{update_filter}}{ Update filter configuration.} - \item{\link{run}}{ Run data filtering.} + \item{\link{add_source} - Add source to Cohort object.} + \item{\link{update_source} - Update Cohort object source.} + \item{\link{add_step} - Add step to Cohort object.} + \item{\link{rm_step} - Remove step from Cohort object.} + \item{\link{add_filter} - Add filter to Cohort step.} + \item{\link{rm_filter} - Remove filter from Cohort step.} + \item{\link{update_filter} - Update filter configuration.} + \item{\link{run} - Run data filtering.} } } diff --git a/man/managing-source.Rd b/man/managing-source.Rd index aa93f87..31c9b55 100644 --- a/man/managing-source.Rd +++ b/man/managing-source.Rd @@ -10,11 +10,11 @@ The object of class `Source` having the modified configuration dependent on the The list of methods designed for managing the Source configuration and state. \itemize{ - \item{\link{add_step}}{ Add step to Source object.} - \item{\link{rm_step}}{ Remove step from Source object.} - \item{\link{add_filter}}{ Add filter to Source step.} - \item{\link{rm_filter}}{ Remove filter from Source step.} - \item{\link{update_filter}}{ Update filter configuration.} + \item{\link{add_step} - Add step to Source object.} + \item{\link{rm_step} - Remove step from Source object.} + \item{\link{add_filter} - Add filter to Source step.} + \item{\link{rm_filter} - Remove filter from Source step.} + \item{\link{update_filter} - Update filter configuration.} } } \seealso{ diff --git a/man/source-layer.Rd b/man/source-layer.Rd index a48e3e8..5605f33 100644 --- a/man/source-layer.Rd +++ b/man/source-layer.Rd @@ -108,23 +108,23 @@ or API service that allows to access and operate on data. In order to make new source type layer functioning, the following list of methods should be defined: \itemize{ - \item{.init_source}{ Defines how to extract data object from source. + \item{\code{.init_source} - Defines how to extract data object from source. Each filtering step assumes to be operating on resulting data object (further named data_object) and returns object of the same type and structure.} - \item{.collect_data}{ Defines how to collect data (into R memory) from `data_object`.} - \item{.get_stats}{ Defines what `data_object` statistics should be + \item{\code{.collect_data} - Defines how to collect data (into R memory) from `data_object`.} + \item{\code{.get_stats} - Defines what `data_object` statistics should be calculated and how. When provided the stats can be extracted using \link{stat}.} - \item{.pre_filtering}{ (optional) Defines what operation on `data_object` should be + \item{\code{.pre_filtering} - (optional) Defines what operation on `data_object` should be performed before applying filtering in the step.} - \item{.post_filtering}{ (optional) Defines what operation on `data_object` should be + \item{\code{.post_filtering} - (optional) Defines what operation on `data_object` should be performed after applying filtering in the step (before running binding).} - \item{.post_binding}{ (optional) Defines what operation on `data_object` should be + \item{\code{.post_binding} - (optional) Defines what operation on `data_object` should be performed after applying binding in the step.} - \item{.run_binding}{ (optional) Defines how to handle post filtering data binding. + \item{\code{.run_binding} - (optional) Defines how to handle post filtering data binding. See more about binding keys at \link{binding-keys}.} - \item{.get_attrition_count and .get_attrition_label}{ Methods defining how to + \item{\code{.get_attrition_count and .get_attrition_label} - Methods defining how to get statistics and labels for attrition plot.} - \item{.repro_code_tweak}{ (optional) Default method passed as a `modifier` + \item{\code{.repro_code_tweak} - (optional) Default method passed as a `modifier` argument of \link{code} function. Aims to modify reproducible code into the final format.} } Except from the above methods, you may extend the existing or new source with providing diff --git a/meta_data.yaml b/meta_data.yaml new file mode 100644 index 0000000..5a694c7 --- /dev/null +++ b/meta_data.yaml @@ -0,0 +1,18 @@ +Name: '' +Maintainer: + Name: '' + Email: '' +Description: '' +Contributors: '' +Main Link: https://github.com/r-world-devs/cohortBuilder +Product Stage: stable +Development Stage: maintained +Business Point of Contact: + Name: Krystian Igras + Email: krystian8207@gmail.com +Tags: +- RWD +- RWD Insights Engineering +- R package +- filter +- opensource diff --git a/renv.lock b/renv.lock index 36a02fa..9bee7b3 100644 --- a/renv.lock +++ b/renv.lock @@ -9,99 +9,151 @@ ] }, "Packages": { + "KernSmooth": { + "Package": "KernSmooth", + "Version": "2.23-22", + "Source": "Repository", + "Repository": "RSPM", + "Requirements": [ + "R", + "stats" + ], + "Hash": "2fecebc3047322fa5930f74fae5de70f" + }, "MASS": { "Package": "MASS", "Version": "7.3-58.2", "Source": "Repository", "Repository": "CRAN", - "Hash": "e02d1a0f6122fd3e634b25b433704344", - "Requirements": [] + "Requirements": [ + "R", + "grDevices", + "graphics", + "methods", + "stats", + "utils" + ], + "Hash": "e02d1a0f6122fd3e634b25b433704344" }, "Matrix": { "Package": "Matrix", "Version": "1.5-3", "Source": "Repository", "Repository": "CRAN", - "Hash": "4006dffe49958d2dd591c17e61e60591", "Requirements": [ - "lattice" - ] + "R", + "graphics", + "grid", + "lattice", + "methods", + "stats", + "utils" + ], + "Hash": "4006dffe49958d2dd591c17e61e60591" }, "NCmisc": { "Package": "NCmisc", "Version": "1.2.0", "Source": "Repository", "Repository": "CRAN", - "Hash": "57805bff69b9ca137e70fb83bf0e35f9", - "Requirements": [] + "Requirements": [ + "R", + "grDevices", + "graphics", + "methods", + "stats", + "tools", + "utils" + ], + "Hash": "57805bff69b9ca137e70fb83bf0e35f9" }, "R6": { "Package": "R6", "Version": "2.5.1", "Source": "Repository", "Repository": "CRAN", - "Hash": "470851b6d5d0ac559e9d01bb352b4021", - "Requirements": [] + "Requirements": [ + "R" + ], + "Hash": "470851b6d5d0ac559e9d01bb352b4021" }, "RColorBrewer": { "Package": "RColorBrewer", "Version": "1.1-3", "Source": "Repository", "Repository": "RSPM", - "Hash": "45f0398006e83a5b10b72a90663d8d8c", - "Requirements": [] + "Requirements": [ + "R" + ], + "Hash": "45f0398006e83a5b10b72a90663d8d8c" }, "Rcpp": { "Package": "Rcpp", "Version": "1.0.10", "Source": "Repository", "Repository": "CRAN", - "Hash": "e749cae40fa9ef469b6050959517453c", - "Requirements": [] + "Requirements": [ + "methods", + "utils" + ], + "Hash": "e749cae40fa9ef469b6050959517453c" }, "askpass": { "Package": "askpass", "Version": "1.1", "Source": "Repository", - "Repository": "CRAN", - "Hash": "e8a22846fff485f0be3770c2da758713", + "Repository": "RSPM", "Requirements": [ "sys" - ] + ], + "Hash": "e8a22846fff485f0be3770c2da758713" }, "base64enc": { "Package": "base64enc", "Version": "0.1-3", "Source": "Repository", "Repository": "CRAN", - "Hash": "543776ae6848fde2f48ff3816d0628bc", - "Requirements": [] + "Requirements": [ + "R" + ], + "Hash": "543776ae6848fde2f48ff3816d0628bc" + }, + "boot": { + "Package": "boot", + "Version": "1.3-28.1", + "Source": "Repository", + "Repository": "RSPM", + "Requirements": [ + "R", + "graphics", + "stats" + ], + "Hash": "9a052fbcbe97a98ceb18dbfd30ebd96e" }, "brew": { "Package": "brew", "Version": "1.0-8", "Source": "Repository", "Repository": "CRAN", - "Hash": "d69a786e85775b126bddbee185ae6084", - "Requirements": [] + "Hash": "d69a786e85775b126bddbee185ae6084" }, "brio": { "Package": "brio", "Version": "1.1.3", "Source": "Repository", "Repository": "CRAN", - "Hash": "976cf154dfb043c012d87cddd8bca363", - "Requirements": [] + "Hash": "976cf154dfb043c012d87cddd8bca363" }, "bslib": { "Package": "bslib", "Version": "0.4.2", "Source": "Repository", "Repository": "CRAN", - "Hash": "a7fbf03946ad741129dc81098722fca1", "Requirements": [ + "R", "base64enc", "cachem", + "grDevices", "htmltools", "jquerylib", "jsonlite", @@ -109,119 +161,176 @@ "mime", "rlang", "sass" - ] + ], + "Hash": "a7fbf03946ad741129dc81098722fca1" }, "cachem": { "Package": "cachem", "Version": "1.0.6", "Source": "Repository", - "Repository": "CRAN", - "Hash": "648c5b3d71e6a37e3043617489a0a0e9", + "Repository": "RSPM", "Requirements": [ "fastmap", "rlang" - ] + ], + "Hash": "648c5b3d71e6a37e3043617489a0a0e9" }, "callr": { "Package": "callr", "Version": "3.7.3", "Source": "Repository", "Repository": "CRAN", - "Hash": "9b2191ede20fa29828139b9900922e51", "Requirements": [ + "R", "R6", - "processx" - ] + "processx", + "utils" + ], + "Hash": "9b2191ede20fa29828139b9900922e51" + }, + "class": { + "Package": "class", + "Version": "7.3-22", + "Source": "Repository", + "Repository": "RSPM", + "Requirements": [ + "MASS", + "R", + "stats", + "utils" + ], + "Hash": "f91f6b29f38b8c280f2b9477787d4bb2" }, "cli": { "Package": "cli", - "Version": "3.6.0", + "Version": "3.6.2", "Source": "Repository", - "Repository": "CRAN", - "Hash": "3177a5a16c243adc199ba33117bd9657", - "Requirements": [] + "Repository": "RSPM", + "Requirements": [ + "R", + "utils" + ], + "Hash": "1216ac65ac55ec0058a6f75d7ca0fd52" }, "clipr": { "Package": "clipr", "Version": "0.8.0", "Source": "Repository", "Repository": "RSPM", - "Hash": "3f038e5ac7f41d4ac41ce658c85e3042", - "Requirements": [] + "Requirements": [ + "utils" + ], + "Hash": "3f038e5ac7f41d4ac41ce658c85e3042" + }, + "cluster": { + "Package": "cluster", + "Version": "2.1.4", + "Source": "Repository", + "Repository": "RSPM", + "Requirements": [ + "R", + "grDevices", + "graphics", + "stats", + "utils" + ], + "Hash": "5edbbabab6ce0bf7900a74fd4358628e" + }, + "codetools": { + "Package": "codetools", + "Version": "0.2-19", + "Source": "Repository", + "Repository": "CRAN", + "Requirements": [ + "R" + ], + "Hash": "c089a619a7fae175d149d89164f8c7d8" }, "colorspace": { "Package": "colorspace", "Version": "2.1-0", "Source": "Repository", "Repository": "CRAN", - "Hash": "f20c47fd52fae58b4e377c37bb8c335b", - "Requirements": [] + "Requirements": [ + "R", + "grDevices", + "graphics", + "methods", + "stats" + ], + "Hash": "f20c47fd52fae58b4e377c37bb8c335b" }, "commonmark": { "Package": "commonmark", "Version": "1.8.1", "Source": "Repository", "Repository": "CRAN", - "Hash": "b6e3e947d1d7ebf3d2bdcea1bde63fe7", - "Requirements": [] + "Hash": "b6e3e947d1d7ebf3d2bdcea1bde63fe7" }, "cpp11": { "Package": "cpp11", "Version": "0.4.3", "Source": "Repository", "Repository": "CRAN", - "Hash": "ed588261931ee3be2c700d22e94a29ab", - "Requirements": [] + "Hash": "ed588261931ee3be2c700d22e94a29ab" }, "crayon": { "Package": "crayon", "Version": "1.5.2", "Source": "Repository", "Repository": "CRAN", - "Hash": "e8a1e41acf02548751f45c718d55aa6a", - "Requirements": [] + "Requirements": [ + "grDevices", + "methods", + "utils" + ], + "Hash": "e8a1e41acf02548751f45c718d55aa6a" }, "credentials": { "Package": "credentials", "Version": "1.3.2", "Source": "Repository", "Repository": "RSPM", - "Hash": "93762d0a34d78e6a025efdbfb5c6bb41", "Requirements": [ "askpass", "curl", "jsonlite", "openssl", "sys" - ] + ], + "Hash": "93762d0a34d78e6a025efdbfb5c6bb41" }, "curl": { "Package": "curl", "Version": "5.0.0", "Source": "Repository", "Repository": "CRAN", - "Hash": "e4f97056611e8e6b8b852d13b7400cf1", - "Requirements": [] + "Requirements": [ + "R" + ], + "Hash": "e4f97056611e8e6b8b852d13b7400cf1" }, "desc": { "Package": "desc", "Version": "1.4.2", "Source": "Repository", "Repository": "CRAN", - "Hash": "6b9602c7ebbe87101a9c8edb6e8b6d21", "Requirements": [ + "R", "R6", "cli", - "rprojroot" - ] + "rprojroot", + "utils" + ], + "Hash": "6b9602c7ebbe87101a9c8edb6e8b6d21" }, "devtools": { "Package": "devtools", "Version": "2.4.5", "Source": "Repository", "Repository": "CRAN", - "Hash": "ea5bc8b4a6a01e4f12d98b58329930bb", "Requirements": [ + "R", "cli", "desc", "ellipsis", @@ -239,37 +348,49 @@ "roxygen2", "rversions", "sessioninfo", + "stats", "testthat", + "tools", "urlchecker", "usethis", + "utils", "withr" - ] + ], + "Hash": "ea5bc8b4a6a01e4f12d98b58329930bb" }, "diffobj": { "Package": "diffobj", "Version": "0.3.5", "Source": "Repository", "Repository": "CRAN", - "Hash": "bcaa8b95f8d7d01a5dedfd959ce88ab8", "Requirements": [ - "crayon" - ] + "R", + "crayon", + "methods", + "stats", + "tools", + "utils" + ], + "Hash": "bcaa8b95f8d7d01a5dedfd959ce88ab8" }, "digest": { "Package": "digest", "Version": "0.6.31", "Source": "Repository", "Repository": "CRAN", - "Hash": "8b708f296afd9ae69f450f9640be8990", - "Requirements": [] + "Requirements": [ + "R", + "utils" + ], + "Hash": "8b708f296afd9ae69f450f9640be8990" }, "downlit": { "Package": "downlit", "Version": "0.4.2", "Source": "Repository", "Repository": "CRAN", - "Hash": "79bf3f66590752ffbba20f8d2da94c7c", "Requirements": [ + "R", "brio", "desc", "digest", @@ -280,111 +401,142 @@ "vctrs", "withr", "yaml" - ] + ], + "Hash": "79bf3f66590752ffbba20f8d2da94c7c" }, "dplyr": { "Package": "dplyr", - "Version": "1.1.0", + "Version": "1.1.4", "Source": "Repository", - "Repository": "CRAN", - "Hash": "d3c34618017e7ae252d46d79a1b9ec32", + "Repository": "RSPM", "Requirements": [ + "R", "R6", "cli", "generics", "glue", "lifecycle", "magrittr", + "methods", "pillar", "rlang", "tibble", "tidyselect", + "utils", "vctrs" - ] + ], + "Hash": "fedd9d00c2944ff00a0e2696ccf048ec" }, "ellipsis": { "Package": "ellipsis", "Version": "0.3.2", "Source": "Repository", "Repository": "CRAN", - "Hash": "bb0eec2fe32e88d9e2836c2f73ea2077", "Requirements": [ + "R", "rlang" - ] + ], + "Hash": "bb0eec2fe32e88d9e2836c2f73ea2077" }, "evaluate": { "Package": "evaluate", "Version": "0.20", "Source": "Repository", "Repository": "CRAN", - "Hash": "4b68aa51edd89a0e044a66e75ae3cc6c", - "Requirements": [] + "Requirements": [ + "R", + "methods" + ], + "Hash": "4b68aa51edd89a0e044a66e75ae3cc6c" }, "fansi": { "Package": "fansi", - "Version": "1.0.4", + "Version": "1.0.6", "Source": "Repository", - "Repository": "CRAN", - "Hash": "1d9e7ad3c8312a192dea7d3db0274fde", - "Requirements": [] + "Repository": "RSPM", + "Requirements": [ + "R", + "grDevices", + "utils" + ], + "Hash": "962174cf2aeb5b9eea581522286a911f" }, "farver": { "Package": "farver", "Version": "2.1.1", "Source": "Repository", "Repository": "RSPM", - "Hash": "8106d78941f34855c440ddb946b8f7a5", - "Requirements": [] + "Hash": "8106d78941f34855c440ddb946b8f7a5" }, "fastmap": { "Package": "fastmap", "Version": "1.1.0", "Source": "Repository", "Repository": "RSPM", - "Hash": "77bd60a6157420d4ffa93b27cf6a58b8", - "Requirements": [] + "Hash": "77bd60a6157420d4ffa93b27cf6a58b8" }, "fontawesome": { "Package": "fontawesome", "Version": "0.5.0", "Source": "Repository", "Repository": "CRAN", - "Hash": "e80750aec5717dedc019ad7ee40e4a7c", "Requirements": [ + "R", "htmltools", "rlang" - ] + ], + "Hash": "e80750aec5717dedc019ad7ee40e4a7c" + }, + "foreign": { + "Package": "foreign", + "Version": "0.8-85", + "Source": "Repository", + "Repository": "CRAN", + "Requirements": [ + "R", + "methods", + "stats", + "utils" + ], + "Hash": "26a24dde1722321b78f10d3bf42538d6" }, "formatR": { "Package": "formatR", "Version": "1.14", "Source": "Repository", "Repository": "CRAN", - "Hash": "63cb26d12517c7863f5abb006c5e0f25", - "Requirements": [] + "Requirements": [ + "R" + ], + "Hash": "63cb26d12517c7863f5abb006c5e0f25" }, "fs": { "Package": "fs", "Version": "1.6.1", "Source": "Repository", "Repository": "CRAN", - "Hash": "f4dcd23b67e33d851d2079f703e8b985", - "Requirements": [] + "Requirements": [ + "R", + "methods" + ], + "Hash": "f4dcd23b67e33d851d2079f703e8b985" }, "generics": { "Package": "generics", "Version": "0.1.3", "Source": "Repository", "Repository": "CRAN", - "Hash": "15e9634c0fcd294799e9b2e929ed1b86", - "Requirements": [] + "Requirements": [ + "R", + "methods" + ], + "Hash": "15e9634c0fcd294799e9b2e929ed1b86" }, "gert": { "Package": "gert", "Version": "1.9.2", "Source": "Repository", - "Repository": "CRAN", - "Hash": "9122b3958e749badb5c939f498038b57", + "Repository": "RSPM", "Requirements": [ "askpass", "credentials", @@ -392,322 +544,395 @@ "rstudioapi", "sys", "zip" - ] + ], + "Hash": "9122b3958e749badb5c939f498038b57" }, "ggplot2": { "Package": "ggplot2", "Version": "3.4.1", "Source": "Repository", "Repository": "CRAN", - "Hash": "d494daf77c4aa7f084dbbe6ca5dcaca7", "Requirements": [ "MASS", + "R", "cli", "glue", + "grDevices", + "grid", "gtable", "isoband", "lifecycle", "mgcv", "rlang", "scales", + "stats", "tibble", "vctrs", "withr" - ] + ], + "Hash": "d494daf77c4aa7f084dbbe6ca5dcaca7" }, "gh": { "Package": "gh", "Version": "1.3.1", "Source": "Repository", "Repository": "CRAN", - "Hash": "b6a12054ee13dce0f6696c019c10e539", "Requirements": [ + "R", "cli", "gitcreds", "httr", "ini", "jsonlite" - ] + ], + "Hash": "b6a12054ee13dce0f6696c019c10e539" }, "gitcreds": { "Package": "gitcreds", "Version": "0.1.2", "Source": "Repository", "Repository": "CRAN", - "Hash": "ab08ac61f3e1be454ae21911eb8bc2fe", - "Requirements": [] + "Requirements": [ + "R" + ], + "Hash": "ab08ac61f3e1be454ae21911eb8bc2fe" }, "glue": { "Package": "glue", - "Version": "1.6.2", + "Version": "1.7.0", "Source": "Repository", - "Repository": "CRAN", - "Hash": "4f2596dfb05dac67b9dc558e5c6fba2e", - "Requirements": [] + "Repository": "RSPM", + "Requirements": [ + "R", + "methods" + ], + "Hash": "e0b3a53876554bd45879e596cdb10a52" }, "gtable": { "Package": "gtable", "Version": "0.3.1", "Source": "Repository", "Repository": "RSPM", - "Hash": "36b4265fb818f6a342bed217549cd896", - "Requirements": [] + "Requirements": [ + "R", + "grid" + ], + "Hash": "36b4265fb818f6a342bed217549cd896" }, "highr": { "Package": "highr", "Version": "0.10", "Source": "Repository", "Repository": "CRAN", - "Hash": "06230136b2d2b9ba5805e1963fa6e890", "Requirements": [ + "R", "xfun" - ] + ], + "Hash": "06230136b2d2b9ba5805e1963fa6e890" }, "htmltools": { "Package": "htmltools", "Version": "0.5.4", "Source": "Repository", "Repository": "CRAN", - "Hash": "9d27e99cc90bd701c0a7a63e5923f9b7", "Requirements": [ + "R", "base64enc", "digest", "ellipsis", "fastmap", - "rlang" - ] + "grDevices", + "rlang", + "utils" + ], + "Hash": "9d27e99cc90bd701c0a7a63e5923f9b7" }, "htmlwidgets": { "Package": "htmlwidgets", "Version": "1.6.1", "Source": "Repository", "Repository": "CRAN", - "Hash": "b677ee5954471eaa974c0d099a343a1a", "Requirements": [ + "grDevices", "htmltools", "jsonlite", "knitr", "rmarkdown", "yaml" - ] + ], + "Hash": "b677ee5954471eaa974c0d099a343a1a" }, "httpuv": { "Package": "httpuv", "Version": "1.6.9", "Source": "Repository", "Repository": "CRAN", - "Hash": "1046aa31a57eae8b357267a56a0b6d8b", "Requirements": [ + "R", "R6", "Rcpp", "later", - "promises" - ] + "promises", + "utils" + ], + "Hash": "1046aa31a57eae8b357267a56a0b6d8b" }, "httr": { "Package": "httr", "Version": "1.4.4", "Source": "Repository", "Repository": "CRAN", - "Hash": "57557fac46471f0dbbf44705cc6a5c8c", "Requirements": [ + "R", "R6", "curl", "jsonlite", "mime", "openssl" - ] + ], + "Hash": "57557fac46471f0dbbf44705cc6a5c8c" }, "ini": { "Package": "ini", "Version": "0.3.1", "Source": "Repository", "Repository": "RSPM", - "Hash": "6154ec2223172bce8162d4153cda21f7", - "Requirements": [] + "Hash": "6154ec2223172bce8162d4153cda21f7" }, "isoband": { "Package": "isoband", "Version": "0.2.7", "Source": "Repository", "Repository": "RSPM", - "Hash": "0080607b4a1a7b28979aecef976d8bc2", - "Requirements": [] + "Requirements": [ + "grid", + "utils" + ], + "Hash": "0080607b4a1a7b28979aecef976d8bc2" }, "jquerylib": { "Package": "jquerylib", "Version": "0.1.4", "Source": "Repository", - "Repository": "CRAN", - "Hash": "5aab57a3bd297eee1c1d862735972182", + "Repository": "RSPM", "Requirements": [ "htmltools" - ] + ], + "Hash": "5aab57a3bd297eee1c1d862735972182" }, "jsonlite": { "Package": "jsonlite", "Version": "1.8.4", "Source": "Repository", "Repository": "CRAN", - "Hash": "a4269a09a9b865579b2635c77e572374", - "Requirements": [] + "Requirements": [ + "methods" + ], + "Hash": "a4269a09a9b865579b2635c77e572374" }, "knitr": { "Package": "knitr", "Version": "1.42", "Source": "Repository", "Repository": "CRAN", - "Hash": "8329a9bcc82943c8069104d4be3ee22d", "Requirements": [ + "R", "evaluate", "highr", + "methods", + "tools", "xfun", "yaml" - ] + ], + "Hash": "8329a9bcc82943c8069104d4be3ee22d" }, "labeling": { "Package": "labeling", "Version": "0.4.2", "Source": "Repository", "Repository": "RSPM", - "Hash": "3d5108641f47470611a32d0bdf357a72", - "Requirements": [] + "Requirements": [ + "graphics", + "stats" + ], + "Hash": "3d5108641f47470611a32d0bdf357a72" }, "later": { "Package": "later", "Version": "1.3.0", "Source": "Repository", "Repository": "RSPM", - "Hash": "7e7b457d7766bc47f2a5f21cc2984f8e", "Requirements": [ "Rcpp", "rlang" - ] + ], + "Hash": "7e7b457d7766bc47f2a5f21cc2984f8e" }, "lattice": { "Package": "lattice", "Version": "0.20-45", "Source": "Repository", "Repository": "CRAN", - "Hash": "b64cdbb2b340437c4ee047a1f4c4377b", - "Requirements": [] + "Requirements": [ + "R", + "grDevices", + "graphics", + "grid", + "stats", + "utils" + ], + "Hash": "b64cdbb2b340437c4ee047a1f4c4377b" }, "lifecycle": { "Package": "lifecycle", - "Version": "1.0.3", + "Version": "1.0.4", "Source": "Repository", - "Repository": "CRAN", - "Hash": "001cecbeac1cff9301bdc3775ee46a86", + "Repository": "RSPM", "Requirements": [ + "R", "cli", "glue", "rlang" - ] + ], + "Hash": "b8552d117e1b808b09a832f589b79035" }, "magrittr": { "Package": "magrittr", "Version": "2.0.3", "Source": "Repository", "Repository": "CRAN", - "Hash": "7ce2733a9826b3aeb1775d56fd305472", - "Requirements": [] + "Requirements": [ + "R" + ], + "Hash": "7ce2733a9826b3aeb1775d56fd305472" }, "markdown": { "Package": "markdown", "Version": "1.5", "Source": "Repository", "Repository": "CRAN", - "Hash": "d209cfd1f4ff7260eae5a7f07da3aa4f", "Requirements": [ + "R", "commonmark", + "utils", "xfun" - ] + ], + "Hash": "d209cfd1f4ff7260eae5a7f07da3aa4f" }, "memoise": { "Package": "memoise", "Version": "2.0.1", "Source": "Repository", - "Repository": "CRAN", - "Hash": "e2817ccf4a065c5d9d7f2cfbe7c1d78c", + "Repository": "RSPM", "Requirements": [ "cachem", "rlang" - ] + ], + "Hash": "e2817ccf4a065c5d9d7f2cfbe7c1d78c" }, "mgcv": { "Package": "mgcv", "Version": "1.8-41", "Source": "Repository", "Repository": "RSPM", - "Hash": "6b3904f13346742caa3e82dd0303d4ad", "Requirements": [ "Matrix", - "nlme" - ] + "R", + "graphics", + "methods", + "nlme", + "splines", + "stats", + "utils" + ], + "Hash": "6b3904f13346742caa3e82dd0303d4ad" }, "mime": { "Package": "mime", "Version": "0.12", "Source": "Repository", "Repository": "CRAN", - "Hash": "18e9c28c1d3ca1560ce30658b22ce104", - "Requirements": [] + "Requirements": [ + "tools" + ], + "Hash": "18e9c28c1d3ca1560ce30658b22ce104" }, "miniUI": { "Package": "miniUI", "Version": "0.1.1.1", "Source": "Repository", "Repository": "CRAN", - "Hash": "fec5f52652d60615fdb3957b3d74324a", "Requirements": [ "htmltools", - "shiny" - ] + "shiny", + "utils" + ], + "Hash": "fec5f52652d60615fdb3957b3d74324a" }, "munsell": { "Package": "munsell", "Version": "0.5.0", "Source": "Repository", "Repository": "RSPM", - "Hash": "6dfe8bf774944bd5595785e3229d8771", "Requirements": [ - "colorspace" - ] + "colorspace", + "methods" + ], + "Hash": "6dfe8bf774944bd5595785e3229d8771" }, "nlme": { "Package": "nlme", "Version": "3.1-162", "Source": "Repository", "Repository": "CRAN", - "Hash": "0984ce8da8da9ead8643c5cbbb60f83e", "Requirements": [ - "lattice" - ] + "R", + "graphics", + "lattice", + "stats", + "utils" + ], + "Hash": "0984ce8da8da9ead8643c5cbbb60f83e" + }, + "nnet": { + "Package": "nnet", + "Version": "7.3-19", + "Source": "Repository", + "Repository": "RSPM", + "Requirements": [ + "R", + "stats", + "utils" + ], + "Hash": "2c797b46eea7fb58ede195bc0b1f1138" }, "openssl": { "Package": "openssl", "Version": "2.0.5", "Source": "Repository", - "Repository": "CRAN", - "Hash": "b04c27110bf367b4daa93f34f3d58e75", + "Repository": "RSPM", "Requirements": [ "askpass" - ] + ], + "Hash": "b04c27110bf367b4daa93f34f3d58e75" }, "packrat": { "Package": "packrat", "Version": "0.9.0", "Source": "Repository", "Repository": "CRAN", - "Hash": "2735eb4b51c302014f53acbb3c80a65f", - "Requirements": [] + "Requirements": [ + "R", + "tools", + "utils" + ], + "Hash": "2735eb4b51c302014f53acbb3c80a65f" }, "pillar": { "Package": "pillar", - "Version": "1.8.1", + "Version": "1.9.0", "Source": "Repository", "Repository": "CRAN", - "Hash": "f2316df30902c81729ae9de95ad5a608", "Requirements": [ "cli", "fansi", @@ -715,16 +940,18 @@ "lifecycle", "rlang", "utf8", + "utils", "vctrs" - ] + ], + "Hash": "15da5a8412f317beeee6175fbc76f4bb" }, "pkgbuild": { "Package": "pkgbuild", "Version": "1.4.0", "Source": "Repository", "Repository": "CRAN", - "Hash": "d6c3008d79653a0f267703288230105e", "Requirements": [ + "R", "R6", "callr", "cli", @@ -734,23 +961,26 @@ "processx", "rprojroot", "withr" - ] + ], + "Hash": "d6c3008d79653a0f267703288230105e" }, "pkgconfig": { "Package": "pkgconfig", "Version": "2.0.3", "Source": "Repository", "Repository": "CRAN", - "Hash": "01f28d4278f15c76cddbea05899c5d6f", - "Requirements": [] + "Requirements": [ + "utils" + ], + "Hash": "01f28d4278f15c76cddbea05899c5d6f" }, "pkgdown": { "Package": "pkgdown", "Version": "2.0.7", "Source": "Repository", "Repository": "CRAN", - "Hash": "16fa15449c930bf3a7761d3c68f8abf9", "Requirements": [ + "R", "bslib", "callr", "cli", @@ -771,132 +1001,157 @@ "withr", "xml2", "yaml" - ] + ], + "Hash": "16fa15449c930bf3a7761d3c68f8abf9" }, "pkgload": { "Package": "pkgload", "Version": "1.3.2", "Source": "Repository", "Repository": "CRAN", - "Hash": "6b0c222c5071efe0f3baf3dae9aa40e2", "Requirements": [ + "R", "cli", "crayon", "desc", "fs", "glue", + "methods", "rlang", "rprojroot", + "utils", "withr" - ] + ], + "Hash": "6b0c222c5071efe0f3baf3dae9aa40e2" }, "praise": { "Package": "praise", "Version": "1.0.0", "Source": "Repository", "Repository": "RSPM", - "Hash": "a555924add98c99d2f411e37e7d25e9f", - "Requirements": [] + "Hash": "a555924add98c99d2f411e37e7d25e9f" }, "prettyunits": { "Package": "prettyunits", "Version": "1.1.1", "Source": "Repository", "Repository": "RSPM", - "Hash": "95ef9167b75dde9d2ccc3c7528393e7e", - "Requirements": [] + "Hash": "95ef9167b75dde9d2ccc3c7528393e7e" }, "processx": { "Package": "processx", "Version": "3.8.0", "Source": "Repository", "Repository": "CRAN", - "Hash": "a33ee2d9bf07564efb888ad98410da84", "Requirements": [ + "R", "R6", - "ps" - ] + "ps", + "utils" + ], + "Hash": "a33ee2d9bf07564efb888ad98410da84" }, "proftools": { "Package": "proftools", "Version": "0.99-3", "Source": "Repository", "Repository": "RSPM", - "Hash": "ac0e388f63fd6aeff975706618e7c758", - "Requirements": [] + "Hash": "ac0e388f63fd6aeff975706618e7c758" }, "profvis": { "Package": "profvis", "Version": "0.3.7", "Source": "Repository", "Repository": "CRAN", - "Hash": "e9d21e79848e02e524bea6f5bd53e7e4", "Requirements": [ + "R", "htmlwidgets", "stringr" - ] + ], + "Hash": "e9d21e79848e02e524bea6f5bd53e7e4" }, "promises": { "Package": "promises", "Version": "1.2.0.1", "Source": "Repository", "Repository": "RSPM", - "Hash": "4ab2c43adb4d4699cf3690acd378d75d", "Requirements": [ "R6", "Rcpp", "later", "magrittr", - "rlang" - ] + "rlang", + "stats" + ], + "Hash": "4ab2c43adb4d4699cf3690acd378d75d" }, "ps": { "Package": "ps", "Version": "1.7.2", "Source": "Repository", "Repository": "CRAN", - "Hash": "68dd03d98a5efd1eb3012436de45ba83", - "Requirements": [] + "Requirements": [ + "R", + "utils" + ], + "Hash": "68dd03d98a5efd1eb3012436de45ba83" }, "purrr": { "Package": "purrr", - "Version": "1.0.1", + "Version": "1.0.2", "Source": "Repository", "Repository": "CRAN", - "Hash": "d71c815267c640f17ddbf7f16144b4bb", "Requirements": [ + "R", "cli", "lifecycle", "magrittr", "rlang", "vctrs" - ] + ], + "Hash": "1cba04a4e9414bdefc9dcaa99649a8dc" + }, + "queryBuilder": { + "Package": "queryBuilder", + "Version": "0.1.0", + "Source": "Repository", + "Repository": "CRAN", + "Requirements": [ + "dplyr", + "glue", + "magrittr", + "purrr", + "rlang", + "utils" + ], + "Hash": "d512ed2cb4dbbb7b4a5884f4e009876a" }, "ragg": { "Package": "ragg", "Version": "1.2.5", "Source": "Repository", "Repository": "CRAN", - "Hash": "690bc058ea2b1b8a407d3cfe3dce3ef9", "Requirements": [ "systemfonts", "textshaping" - ] + ], + "Hash": "690bc058ea2b1b8a407d3cfe3dce3ef9" }, "rappdirs": { "Package": "rappdirs", "Version": "0.3.3", "Source": "Repository", "Repository": "CRAN", - "Hash": "5e3c5dc0b071b21fa128676560dbe94d", - "Requirements": [] + "Requirements": [ + "R" + ], + "Hash": "5e3c5dc0b071b21fa128676560dbe94d" }, "rcmdcheck": { "Package": "rcmdcheck", "Version": "1.4.0", "Source": "Repository", "Repository": "CRAN", - "Hash": "8f25ebe2ec38b1f2aef3b0d2ef76f6c4", "Requirements": [ "R6", "callr", @@ -908,75 +1163,87 @@ "prettyunits", "rprojroot", "sessioninfo", + "utils", "withr", "xopen" - ] + ], + "Hash": "8f25ebe2ec38b1f2aef3b0d2ef76f6c4" }, "rematch2": { "Package": "rematch2", "Version": "2.1.2", "Source": "Repository", - "Repository": "CRAN", - "Hash": "76c9e04c712a05848ae7a23d2f170a40", + "Repository": "RSPM", "Requirements": [ "tibble" - ] + ], + "Hash": "76c9e04c712a05848ae7a23d2f170a40" }, "remotes": { "Package": "remotes", "Version": "2.4.2", "Source": "Repository", "Repository": "CRAN", - "Hash": "227045be9aee47e6dda9bb38ac870d67", - "Requirements": [] + "Requirements": [ + "R", + "methods", + "stats", + "tools", + "utils" + ], + "Hash": "227045be9aee47e6dda9bb38ac870d67" }, "renv": { "Package": "renv", - "Version": "0.15.4-4", - "Source": "GitHub", - "RemoteType": "github", - "RemoteHost": "api.github.com", - "RemoteUsername": "rstudio", - "RemoteRepo": "renv", - "RemoteRef": "0.15.4-4", - "RemoteSha": "7243b4810f58d4fc11025a1eedf8e9ca8e21fe94", - "Hash": "4550413885e5598c957fe56913718df0", - "Requirements": [] + "Version": "1.0.7", + "Source": "Repository", + "Repository": "RSPM", + "Requirements": [ + "utils" + ], + "Hash": "397b7b2a265bc5a7a06852524dabae20" }, "rlang": { "Package": "rlang", - "Version": "1.0.6", + "Version": "1.1.4", "Source": "Repository", "Repository": "CRAN", - "Hash": "4ed1f8336c8d52c3e750adcdc57228a7", - "Requirements": [] + "Requirements": [ + "R", + "utils" + ], + "Hash": "3eec01f8b1dee337674b2e34ab1f9bc1" }, "rmarkdown": { "Package": "rmarkdown", "Version": "2.20", "Source": "Repository", "Repository": "CRAN", - "Hash": "716fde5382293cc94a71f68c85b78d19", "Requirements": [ + "R", "bslib", "evaluate", "htmltools", "jquerylib", "jsonlite", "knitr", + "methods", "stringr", "tinytex", + "tools", + "utils", "xfun", "yaml" - ] + ], + "Hash": "716fde5382293cc94a71f68c85b78d19" }, "roxygen2": { "Package": "roxygen2", "Version": "7.2.3", "Source": "Repository", "Repository": "CRAN", - "Hash": "7b153c746193b143c14baa072bae4e27", "Requirements": [ + "R", "R6", "brew", "cli", @@ -984,79 +1251,99 @@ "cpp11", "desc", "knitr", + "methods", "pkgload", "purrr", "rlang", "stringi", "stringr", + "utils", "withr", "xml2" - ] + ], + "Hash": "7b153c746193b143c14baa072bae4e27" + }, + "rpart": { + "Package": "rpart", + "Version": "4.1.21", + "Source": "Repository", + "Repository": "CRAN", + "Requirements": [ + "R", + "grDevices", + "graphics", + "stats" + ], + "Hash": "d5bc1a16e01e50e08581f0c362d3955d" }, "rprojroot": { "Package": "rprojroot", "Version": "2.0.3", "Source": "Repository", "Repository": "CRAN", - "Hash": "1de7ab598047a87bba48434ba35d497d", - "Requirements": [] + "Requirements": [ + "R" + ], + "Hash": "1de7ab598047a87bba48434ba35d497d" }, "rsconnect": { "Package": "rsconnect", "Version": "0.8.29", "Source": "Repository", "Repository": "CRAN", - "Hash": "fe178fc15af80952f546aafedf655b36", "Requirements": [ + "R", "curl", "digest", "jsonlite", "openssl", "packrat", "rstudioapi", + "tools", "yaml" - ] + ], + "Hash": "fe178fc15af80952f546aafedf655b36" }, "rstudioapi": { "Package": "rstudioapi", "Version": "0.14", "Source": "Repository", "Repository": "CRAN", - "Hash": "690bd2acc42a9166ce34845884459320", - "Requirements": [] + "Hash": "690bd2acc42a9166ce34845884459320" }, "rversions": { "Package": "rversions", "Version": "2.1.2", "Source": "Repository", "Repository": "CRAN", - "Hash": "a9881dfed103e83f9de151dc17002cd1", "Requirements": [ "curl", + "utils", "xml2" - ] + ], + "Hash": "a9881dfed103e83f9de151dc17002cd1" }, "sass": { "Package": "sass", "Version": "0.4.5", "Source": "Repository", - "Repository": "CRAN", - "Hash": "2bb4371a4c80115518261866eab6ab11", + "Repository": "RSPM", "Requirements": [ "R6", "fs", "htmltools", "rappdirs", "rlang" - ] + ], + "Hash": "2bb4371a4c80115518261866eab6ab11" }, "scales": { "Package": "scales", "Version": "1.2.1", "Source": "Repository", "Repository": "RSPM", - "Hash": "906cb23d2f1c5680b8ce439b44c6fa63", "Requirements": [ + "R", "R6", "RColorBrewer", "farver", @@ -1065,25 +1352,29 @@ "munsell", "rlang", "viridisLite" - ] + ], + "Hash": "906cb23d2f1c5680b8ce439b44c6fa63" }, "sessioninfo": { "Package": "sessioninfo", "Version": "1.2.2", "Source": "Repository", "Repository": "CRAN", - "Hash": "3f9796a8d0a0e8c6eb49a4b029359d1f", "Requirements": [ - "cli" - ] + "R", + "cli", + "tools", + "utils" + ], + "Hash": "3f9796a8d0a0e8c6eb49a4b029359d1f" }, "shiny": { "Package": "shiny", "Version": "1.7.4", "Source": "Repository", "Repository": "CRAN", - "Hash": "c2eae3d8c670fa9dfa35a12066f4a1d5", "Requirements": [ + "R", "R6", "bslib", "cachem", @@ -1093,42 +1384,67 @@ "fastmap", "fontawesome", "glue", + "grDevices", "htmltools", "httpuv", "jsonlite", "later", "lifecycle", + "methods", "mime", "promises", "rlang", "sourcetools", + "tools", + "utils", "withr", "xtable" - ] + ], + "Hash": "c2eae3d8c670fa9dfa35a12066f4a1d5" }, "sourcetools": { "Package": "sourcetools", "Version": "0.1.7-1", "Source": "Repository", "Repository": "CRAN", - "Hash": "5f5a7629f956619d519205ec475fe647", - "Requirements": [] + "Requirements": [ + "R" + ], + "Hash": "5f5a7629f956619d519205ec475fe647" + }, + "spatial": { + "Package": "spatial", + "Version": "7.3-17", + "Source": "Repository", + "Repository": "CRAN", + "Requirements": [ + "R", + "graphics", + "stats", + "utils" + ], + "Hash": "1229a01b4ec059e9f2396724f2ec9010" }, "stringi": { "Package": "stringi", "Version": "1.7.12", "Source": "Repository", "Repository": "CRAN", - "Hash": "ca8bd84263c77310739d2cf64d84d7c9", - "Requirements": [] + "Requirements": [ + "R", + "stats", + "tools", + "utils" + ], + "Hash": "ca8bd84263c77310739d2cf64d84d7c9" }, "stringr": { "Package": "stringr", "Version": "1.5.0", "Source": "Repository", "Repository": "CRAN", - "Hash": "671a4d384ae9d32fc47a14e98bfa3dc8", "Requirements": [ + "R", "cli", "glue", "lifecycle", @@ -1136,33 +1452,50 @@ "rlang", "stringi", "vctrs" - ] + ], + "Hash": "671a4d384ae9d32fc47a14e98bfa3dc8" + }, + "survival": { + "Package": "survival", + "Version": "3.5-7", + "Source": "Repository", + "Repository": "RSPM", + "Requirements": [ + "Matrix", + "R", + "graphics", + "methods", + "splines", + "stats", + "utils" + ], + "Hash": "b8e943d262c3da0b0febd3e04517c197" }, "sys": { "Package": "sys", "Version": "3.4.1", "Source": "Repository", "Repository": "CRAN", - "Hash": "34c16f1ef796057bfa06d3f4ff818a5d", - "Requirements": [] + "Hash": "34c16f1ef796057bfa06d3f4ff818a5d" }, "systemfonts": { "Package": "systemfonts", "Version": "1.0.4", "Source": "Repository", "Repository": "CRAN", - "Hash": "90b28393209827327de889f49935140a", "Requirements": [ + "R", "cpp11" - ] + ], + "Hash": "90b28393209827327de889f49935140a" }, "testthat": { "Package": "testthat", "Version": "3.1.6", "Source": "Repository", "Repository": "CRAN", - "Hash": "7910146255835c66e9eb272fb215248d", "Requirements": [ + "R", "R6", "brio", "callr", @@ -1174,49 +1507,56 @@ "jsonlite", "lifecycle", "magrittr", + "methods", "pkgload", "praise", "processx", "ps", "rlang", + "utils", "waldo", "withr" - ] + ], + "Hash": "7910146255835c66e9eb272fb215248d" }, "textshaping": { "Package": "textshaping", "Version": "0.3.6", "Source": "Repository", "Repository": "CRAN", - "Hash": "1ab6223d3670fac7143202cb6a2d43d5", "Requirements": [ + "R", "cpp11", "systemfonts" - ] + ], + "Hash": "1ab6223d3670fac7143202cb6a2d43d5" }, "tibble": { "Package": "tibble", - "Version": "3.1.8", + "Version": "3.2.1", "Source": "Repository", "Repository": "CRAN", - "Hash": "56b6934ef0f8c68225949a8672fe1a8f", "Requirements": [ + "R", "fansi", "lifecycle", "magrittr", + "methods", "pillar", "pkgconfig", "rlang", + "utils", "vctrs" - ] + ], + "Hash": "a84e2cc86d07289b3b6f5069df7a004c" }, "tidyr": { "Package": "tidyr", "Version": "1.3.0", "Source": "Repository", "Repository": "CRAN", - "Hash": "e47debdc7ce599b070c8e78e8ac0cfcf", "Requirements": [ + "R", "cli", "cpp11", "dplyr", @@ -1228,53 +1568,58 @@ "stringr", "tibble", "tidyselect", + "utils", "vctrs" - ] + ], + "Hash": "e47debdc7ce599b070c8e78e8ac0cfcf" }, "tidyselect": { "Package": "tidyselect", - "Version": "1.2.0", + "Version": "1.2.1", "Source": "Repository", "Repository": "CRAN", - "Hash": "79540e5fcd9e0435af547d885f184fd5", "Requirements": [ + "R", "cli", "glue", "lifecycle", "rlang", "vctrs", "withr" - ] + ], + "Hash": "829f27b9c4919c16b593794a6344d6c0" }, "tinytex": { "Package": "tinytex", "Version": "0.44", "Source": "Repository", - "Repository": "CRAN", - "Hash": "c0f007e2eeed7722ce13d42b84a22e07", + "Repository": "RSPM", "Requirements": [ "xfun" - ] + ], + "Hash": "c0f007e2eeed7722ce13d42b84a22e07" }, "urlchecker": { "Package": "urlchecker", "Version": "1.0.1", "Source": "Repository", "Repository": "CRAN", - "Hash": "409328b8e1253c8d729a7836fe7f7a16", "Requirements": [ + "R", "cli", "curl", + "tools", "xml2" - ] + ], + "Hash": "409328b8e1253c8d729a7836fe7f7a16" }, "usethis": { "Package": "usethis", "Version": "2.1.6", "Source": "Repository", "Repository": "RSPM", - "Hash": "a67a22c201832b12c036cc059f1d137d", "Requirements": [ + "R", "cli", "clipr", "crayon", @@ -1291,121 +1636,142 @@ "rlang", "rprojroot", "rstudioapi", + "stats", + "utils", "whisker", "withr", "yaml" - ] + ], + "Hash": "a67a22c201832b12c036cc059f1d137d" }, "utf8": { "Package": "utf8", - "Version": "1.2.3", + "Version": "1.2.4", "Source": "Repository", "Repository": "CRAN", - "Hash": "1fe17157424bb09c48a8b3b550c753bc", - "Requirements": [] + "Requirements": [ + "R" + ], + "Hash": "62b65c52671e6665f803ff02954446e9" }, "vctrs": { "Package": "vctrs", - "Version": "0.5.2", + "Version": "0.6.5", "Source": "Repository", - "Repository": "CRAN", - "Hash": "e4ffa94ceed5f124d429a5a5f0f5b378", + "Repository": "RSPM", "Requirements": [ + "R", "cli", "glue", "lifecycle", "rlang" - ] + ], + "Hash": "c03fa420630029418f7e6da3667aac4a" }, "viridisLite": { "Package": "viridisLite", "Version": "0.4.1", "Source": "Repository", "Repository": "RSPM", - "Hash": "62f4b5da3e08d8e5bcba6cac15603f70", - "Requirements": [] + "Requirements": [ + "R" + ], + "Hash": "62f4b5da3e08d8e5bcba6cac15603f70" }, "waldo": { "Package": "waldo", "Version": "0.4.0", "Source": "Repository", "Repository": "CRAN", - "Hash": "035fba89d0c86e2113120f93301b98ad", "Requirements": [ "cli", "diffobj", "fansi", "glue", + "methods", "rematch2", "rlang", "tibble" - ] + ], + "Hash": "035fba89d0c86e2113120f93301b98ad" }, "whisker": { "Package": "whisker", "Version": "0.4.1", "Source": "Repository", "Repository": "CRAN", - "Hash": "c6abfa47a46d281a7d5159d0a8891e88", - "Requirements": [] + "Hash": "c6abfa47a46d281a7d5159d0a8891e88" }, "withr": { "Package": "withr", - "Version": "2.5.0", + "Version": "3.0.0", "Source": "Repository", - "Repository": "CRAN", - "Hash": "c0e49a9760983e81e55cdd9be92e7182", - "Requirements": [] + "Repository": "RSPM", + "Requirements": [ + "R", + "grDevices", + "graphics" + ], + "Hash": "d31b6c62c10dcf11ec530ca6b0dd5d35" }, "xfun": { "Package": "xfun", "Version": "0.37", "Source": "Repository", "Repository": "CRAN", - "Hash": "a6860e1400a8fd1ddb6d9b4230cc34ab", - "Requirements": [] + "Requirements": [ + "stats", + "tools" + ], + "Hash": "a6860e1400a8fd1ddb6d9b4230cc34ab" }, "xml2": { "Package": "xml2", "Version": "1.3.3", "Source": "Repository", "Repository": "CRAN", - "Hash": "40682ed6a969ea5abfd351eb67833adc", - "Requirements": [] + "Requirements": [ + "R", + "methods" + ], + "Hash": "40682ed6a969ea5abfd351eb67833adc" }, "xopen": { "Package": "xopen", "Version": "1.0.0", "Source": "Repository", "Repository": "CRAN", - "Hash": "6c85f015dee9cc7710ddd20f86881f58", "Requirements": [ + "R", "processx" - ] + ], + "Hash": "6c85f015dee9cc7710ddd20f86881f58" }, "xtable": { "Package": "xtable", "Version": "1.8-4", "Source": "Repository", "Repository": "CRAN", - "Hash": "b8acdf8af494d9ec19ccb2481a9b11c2", - "Requirements": [] + "Requirements": [ + "R", + "stats", + "utils" + ], + "Hash": "b8acdf8af494d9ec19ccb2481a9b11c2" }, "yaml": { "Package": "yaml", "Version": "2.3.7", "Source": "Repository", "Repository": "CRAN", - "Hash": "0d0056cc5383fbc240ccd0cb584bf436", - "Requirements": [] + "Hash": "0d0056cc5383fbc240ccd0cb584bf436" }, "zip": { "Package": "zip", "Version": "2.2.2", "Source": "Repository", "Repository": "RSPM", - "Hash": "c42bfcec3fa6a0cce17ce1f8bc684f88", - "Requirements": [] + "Hash": "c42bfcec3fa6a0cce17ce1f8bc684f88" } } } diff --git a/renv/.gitignore b/renv/.gitignore index cb06864..63b9ec4 100644 --- a/renv/.gitignore +++ b/renv/.gitignore @@ -1,3 +1,4 @@ +sandbox/ cellar/ library/ local/ diff --git a/renv/activate.R b/renv/activate.R index e5d141a..d13f993 100644 --- a/renv/activate.R +++ b/renv/activate.R @@ -2,10 +2,28 @@ local({ # the requested version of renv - version <- "0.15.4-4" + version <- "1.0.7" + attr(version, "sha") <- NULL # the project directory - project <- getwd() + project <- Sys.getenv("RENV_PROJECT") + if (!nzchar(project)) + project <- getwd() + + # use start-up diagnostics if enabled + diagnostics <- Sys.getenv("RENV_STARTUP_DIAGNOSTICS", unset = "FALSE") + if (diagnostics) { + start <- Sys.time() + profile <- tempfile("renv-startup-", fileext = ".Rprof") + utils::Rprof(profile) + on.exit({ + utils::Rprof(NULL) + elapsed <- signif(difftime(Sys.time(), start, units = "auto"), digits = 2L) + writeLines(sprintf("- renv took %s to run the autoloader.", format(elapsed))) + writeLines(sprintf("- Profile: %s", profile)) + print(utils::summaryRprof(profile)) + }, add = TRUE) + } # figure out whether the autoloader is enabled enabled <- local({ @@ -15,6 +33,14 @@ local({ if (!is.null(override)) return(override) + # if we're being run in a context where R_LIBS is already set, + # don't load -- presumably we're being run as a sub-process and + # the parent process has already set up library paths for us + rcmd <- Sys.getenv("R_CMD", unset = NA) + rlibs <- Sys.getenv("R_LIBS", unset = NA) + if (!is.na(rlibs) && !is.na(rcmd)) + return(FALSE) + # next, check environment variables # TODO: prefer using the configuration one in the future envvars <- c( @@ -34,9 +60,22 @@ local({ }) - if (!enabled) + # bail if we're not enabled + if (!enabled) { + + # if we're not enabled, we might still need to manually load + # the user profile here + profile <- Sys.getenv("R_PROFILE_USER", unset = "~/.Rprofile") + if (file.exists(profile)) { + cfg <- Sys.getenv("RENV_CONFIG_USER_PROFILE", unset = "TRUE") + if (tolower(cfg) %in% c("true", "t", "1")) + sys.source(profile, envir = globalenv()) + } + return(FALSE) + } + # avoid recursion if (identical(getOption("renv.autoloader.running"), TRUE)) { warning("ignoring recursive attempt to run renv autoloader") @@ -54,27 +93,96 @@ local({ # mask 'utils' packages, will come first on the search path library(utils, lib.loc = .Library) - # unload renv if it's already been laoded + # unload renv if it's already been loaded if ("renv" %in% loadedNamespaces()) unloadNamespace("renv") # load bootstrap tools `%||%` <- function(x, y) { - if (is.environment(x) || length(x)) x else y + if (is.null(x)) y else x + } + + catf <- function(fmt, ..., appendLF = TRUE) { + + quiet <- getOption("renv.bootstrap.quiet", default = FALSE) + if (quiet) + return(invisible()) + + msg <- sprintf(fmt, ...) + cat(msg, file = stdout(), sep = if (appendLF) "\n" else "") + + invisible(msg) + + } + + header <- function(label, + ..., + prefix = "#", + suffix = "-", + n = min(getOption("width"), 78)) + { + label <- sprintf(label, ...) + n <- max(n - nchar(label) - nchar(prefix) - 2L, 8L) + if (n <= 0) + return(paste(prefix, label)) + + tail <- paste(rep.int(suffix, n), collapse = "") + paste0(prefix, " ", label, " ", tail) + + } + + heredoc <- function(text, leave = 0) { + + # remove leading, trailing whitespace + trimmed <- gsub("^\\s*\\n|\\n\\s*$", "", text) + + # split into lines + lines <- strsplit(trimmed, "\n", fixed = TRUE)[[1L]] + + # compute common indent + indent <- regexpr("[^[:space:]]", lines) + common <- min(setdiff(indent, -1L)) - leave + paste(substring(lines, common), collapse = "\n") + + } + + startswith <- function(string, prefix) { + substring(string, 1, nchar(prefix)) == prefix } bootstrap <- function(version, library) { + friendly <- renv_bootstrap_version_friendly(version) + section <- header(sprintf("Bootstrapping renv %s", friendly)) + catf(section) + # attempt to download renv - tarball <- tryCatch(renv_bootstrap_download(version), error = identity) - if (inherits(tarball, "error")) - stop("failed to download renv ", version) + catf("- Downloading renv ... ", appendLF = FALSE) + withCallingHandlers( + tarball <- renv_bootstrap_download(version), + error = function(err) { + catf("FAILED") + stop("failed to download:\n", conditionMessage(err)) + } + ) + catf("OK") + on.exit(unlink(tarball), add = TRUE) # now attempt to install - status <- tryCatch(renv_bootstrap_install(version, tarball, library), error = identity) - if (inherits(status, "error")) - stop("failed to install renv ", version) + catf("- Installing renv ... ", appendLF = FALSE) + withCallingHandlers( + status <- renv_bootstrap_install(version, tarball, library), + error = function(err) { + catf("FAILED") + stop("failed to install:\n", conditionMessage(err)) + } + ) + catf("OK") + # add empty line to break up bootstrapping from normal output + catf("") + + return(invisible()) } renv_bootstrap_tests_running <- function() { @@ -83,28 +191,32 @@ local({ renv_bootstrap_repos <- function() { + # get CRAN repository + cran <- getOption("renv.repos.cran", "https://cloud.r-project.org") + # check for repos override repos <- Sys.getenv("RENV_CONFIG_REPOS_OVERRIDE", unset = NA) - if (!is.na(repos)) + if (!is.na(repos)) { + + # check for RSPM; if set, use a fallback repository for renv + rspm <- Sys.getenv("RSPM", unset = NA) + if (identical(rspm, repos)) + repos <- c(RSPM = rspm, CRAN = cran) + return(repos) + } + # check for lockfile repositories repos <- tryCatch(renv_bootstrap_repos_lockfile(), error = identity) if (!inherits(repos, "error") && length(repos)) return(repos) - # if we're testing, re-use the test repositories - if (renv_bootstrap_tests_running()) - return(getOption("renv.tests.repos")) - # retrieve current repos repos <- getOption("repos") # ensure @CRAN@ entries are resolved - repos[repos == "@CRAN@"] <- getOption( - "renv.repos.cran", - "https://cloud.r-project.org" - ) + repos[repos == "@CRAN@"] <- cran # add in renv.bootstrap.repos if set default <- c(FALLBACK = "https://cloud.r-project.org") @@ -143,33 +255,34 @@ local({ renv_bootstrap_download <- function(version) { - # if the renv version number has 4 components, assume it must - # be retrieved via github - nv <- numeric_version(version) - components <- unclass(nv)[[1]] - - # if this appears to be a development version of 'renv', we'll - # try to restore from github - dev <- length(components) == 4L - - # begin collecting different methods for finding renv - methods <- c( - renv_bootstrap_download_tarball, - if (dev) - renv_bootstrap_download_github - else c( - renv_bootstrap_download_cran_latest, - renv_bootstrap_download_cran_archive + sha <- attr(version, "sha", exact = TRUE) + + methods <- if (!is.null(sha)) { + + # attempting to bootstrap a development version of renv + c( + function() renv_bootstrap_download_tarball(sha), + function() renv_bootstrap_download_github(sha) ) - ) + + } else { + + # attempting to bootstrap a release version of renv + c( + function() renv_bootstrap_download_tarball(version), + function() renv_bootstrap_download_cran_latest(version), + function() renv_bootstrap_download_cran_archive(version) + ) + + } for (method in methods) { - path <- tryCatch(method(version), error = identity) + path <- tryCatch(method(), error = identity) if (is.character(path) && file.exists(path)) return(path) } - stop("failed to download renv ", version) + stop("All download methods failed") } @@ -185,43 +298,75 @@ local({ if (fixup) mode <- "w+b" - utils::download.file( + args <- list( url = url, destfile = destfile, mode = mode, quiet = TRUE ) + if ("headers" %in% names(formals(utils::download.file))) + args$headers <- renv_bootstrap_download_custom_headers(url) + + do.call(utils::download.file, args) + } - renv_bootstrap_download_cran_latest <- function(version) { + renv_bootstrap_download_custom_headers <- function(url) { - spec <- renv_bootstrap_download_cran_latest_find(version) + headers <- getOption("renv.download.headers") + if (is.null(headers)) + return(character()) + + if (!is.function(headers)) + stopf("'renv.download.headers' is not a function") + + headers <- headers(url) + if (length(headers) == 0L) + return(character()) - message("* Downloading renv ", version, " ... ", appendLF = FALSE) + if (is.list(headers)) + headers <- unlist(headers, recursive = FALSE, use.names = TRUE) + ok <- + is.character(headers) && + is.character(names(headers)) && + all(nzchar(names(headers))) + + if (!ok) + stop("invocation of 'renv.download.headers' did not return a named character vector") + + headers + + } + + renv_bootstrap_download_cran_latest <- function(version) { + + spec <- renv_bootstrap_download_cran_latest_find(version) type <- spec$type repos <- spec$repos - info <- tryCatch( - utils::download.packages( - pkgs = "renv", - destdir = tempdir(), - repos = repos, - type = type, - quiet = TRUE - ), + baseurl <- utils::contrib.url(repos = repos, type = type) + ext <- if (identical(type, "source")) + ".tar.gz" + else if (Sys.info()[["sysname"]] == "Windows") + ".zip" + else + ".tgz" + name <- sprintf("renv_%s%s", version, ext) + url <- paste(baseurl, name, sep = "/") + + destfile <- file.path(tempdir(), name) + status <- tryCatch( + renv_bootstrap_download_impl(url, destfile), condition = identity ) - if (inherits(info, "condition")) { - message("FAILED") + if (inherits(status, "condition")) return(FALSE) - } # report success and return - message("OK (downloaded ", type, ")") - info[1, 2] + destfile } @@ -277,8 +422,6 @@ local({ urls <- file.path(repos, "src/contrib/Archive/renv", name) destfile <- file.path(tempdir(), name) - message("* Downloading renv ", version, " ... ", appendLF = FALSE) - for (url in urls) { status <- tryCatch( @@ -286,14 +429,11 @@ local({ condition = identity ) - if (identical(status, 0L)) { - message("OK") + if (identical(status, 0L)) return(destfile) - } } - message("FAILED") return(FALSE) } @@ -307,20 +447,25 @@ local({ return() # allow directories - info <- file.info(tarball, extra_cols = FALSE) - if (identical(info$isdir, TRUE)) { + if (dir.exists(tarball)) { name <- sprintf("renv_%s.tar.gz", version) tarball <- file.path(tarball, name) } # bail if it doesn't exist - if (!file.exists(tarball)) + if (!file.exists(tarball)) { + + # let the user know we weren't able to honour their request + fmt <- "- RENV_BOOTSTRAP_TARBALL is set (%s) but does not exist." + msg <- sprintf(fmt, tarball) + warning(msg) + + # bail return() - fmt <- "* Bootstrapping with tarball at path '%s'." - msg <- sprintf(fmt, tarball) - message(msg) + } + catf("- Using local tarball '%s'.", tarball) tarball } @@ -347,8 +492,6 @@ local({ on.exit(do.call(base::options, saved), add = TRUE) } - message("* Downloading renv ", version, " from GitHub ... ", appendLF = FALSE) - url <- file.path("https://api.github.com/repos/rstudio/renv/tarball", version) name <- sprintf("renv_%s.tar.gz", version) destfile <- file.path(tempdir(), name) @@ -358,26 +501,105 @@ local({ condition = identity ) - if (!identical(status, 0L)) { - message("FAILED") + if (!identical(status, 0L)) return(FALSE) - } - message("OK") + renv_bootstrap_download_augment(destfile) + return(destfile) } + # Add Sha to DESCRIPTION. This is stop gap until #890, after which we + # can use renv::install() to fully capture metadata. + renv_bootstrap_download_augment <- function(destfile) { + sha <- renv_bootstrap_git_extract_sha1_tar(destfile) + if (is.null(sha)) { + return() + } + + # Untar + tempdir <- tempfile("renv-github-") + on.exit(unlink(tempdir, recursive = TRUE), add = TRUE) + untar(destfile, exdir = tempdir) + pkgdir <- dir(tempdir, full.names = TRUE)[[1]] + + # Modify description + desc_path <- file.path(pkgdir, "DESCRIPTION") + desc_lines <- readLines(desc_path) + remotes_fields <- c( + "RemoteType: github", + "RemoteHost: api.github.com", + "RemoteRepo: renv", + "RemoteUsername: rstudio", + "RemotePkgRef: rstudio/renv", + paste("RemoteRef: ", sha), + paste("RemoteSha: ", sha) + ) + writeLines(c(desc_lines[desc_lines != ""], remotes_fields), con = desc_path) + + # Re-tar + local({ + old <- setwd(tempdir) + on.exit(setwd(old), add = TRUE) + + tar(destfile, compression = "gzip") + }) + invisible() + } + + # Extract the commit hash from a git archive. Git archives include the SHA1 + # hash as the comment field of the tarball pax extended header + # (see https://www.kernel.org/pub/software/scm/git/docs/git-archive.html) + # For GitHub archives this should be the first header after the default one + # (512 byte) header. + renv_bootstrap_git_extract_sha1_tar <- function(bundle) { + + # open the bundle for reading + # We use gzcon for everything because (from ?gzcon) + # > Reading from a connection which does not supply a 'gzip' magic + # > header is equivalent to reading from the original connection + conn <- gzcon(file(bundle, open = "rb", raw = TRUE)) + on.exit(close(conn)) + + # The default pax header is 512 bytes long and the first pax extended header + # with the comment should be 51 bytes long + # `52 comment=` (11 chars) + 40 byte SHA1 hash + len <- 0x200 + 0x33 + res <- rawToChar(readBin(conn, "raw", n = len)[0x201:len]) + + if (grepl("^52 comment=", res)) { + sub("52 comment=", "", res) + } else { + NULL + } + } + renv_bootstrap_install <- function(version, tarball, library) { # attempt to install it into project library - message("* Installing renv ", version, " ... ", appendLF = FALSE) dir.create(library, showWarnings = FALSE, recursive = TRUE) + output <- renv_bootstrap_install_impl(library, tarball) + + # check for successful install + status <- attr(output, "status") + if (is.null(status) || identical(status, 0L)) + return(status) + + # an error occurred; report it + header <- "installation of renv failed" + lines <- paste(rep.int("=", nchar(header)), collapse = "") + text <- paste(c(header, lines, output), collapse = "\n") + stop(text) + + } + + renv_bootstrap_install_impl <- function(library, tarball) { # invoke using system2 so we can capture and report output bin <- R.home("bin") exe <- if (Sys.info()[["sysname"]] == "Windows") "R.exe" else "R" - r <- file.path(bin, exe) + R <- file.path(bin, exe) args <- c( "--vanilla", "CMD", "INSTALL", "--no-multiarch", @@ -385,19 +607,7 @@ local({ shQuote(path.expand(tarball)) ) - output <- system2(r, args, stdout = TRUE, stderr = TRUE) - message("Done!") - - # check for successful install - status <- attr(output, "status") - if (is.numeric(status) && !identical(status, 0L)) { - header <- "Error installing renv:" - lines <- paste(rep.int("=", nchar(header)), collapse = "") - text <- c(header, lines, output) - writeLines(text, con = stderr()) - } - - status + system2(R, args, stdout = TRUE, stderr = TRUE) } @@ -438,6 +648,9 @@ local({ # if the user has requested an automatic prefix, generate it auto <- Sys.getenv("RENV_PATHS_PREFIX_AUTO", unset = NA) + if (is.na(auto) && getRversion() >= "4.4.0") + auto <- "TRUE" + if (auto %in% c("TRUE", "True", "true", "1")) return(renv_bootstrap_platform_prefix_auto()) @@ -607,34 +820,61 @@ local({ } - renv_bootstrap_validate_version <- function(version) { + renv_bootstrap_validate_version <- function(version, description = NULL) { - loadedversion <- utils::packageDescription("renv", fields = "Version") - if (version == loadedversion) + # resolve description file + # + # avoid passing lib.loc to `packageDescription()` below, since R will + # use the loaded version of the package by default anyhow. note that + # this function should only be called after 'renv' is loaded + # https://github.com/rstudio/renv/issues/1625 + description <- description %||% packageDescription("renv") + + # check whether requested version 'version' matches loaded version of renv + sha <- attr(version, "sha", exact = TRUE) + valid <- if (!is.null(sha)) + renv_bootstrap_validate_version_dev(sha, description) + else + renv_bootstrap_validate_version_release(version, description) + + if (valid) return(TRUE) - # assume four-component versions are from GitHub; three-component - # versions are from CRAN - components <- strsplit(loadedversion, "[.-]")[[1]] - remote <- if (length(components) == 4L) - paste("rstudio/renv", loadedversion, sep = "@") + # the loaded version of renv doesn't match the requested version; + # give the user instructions on how to proceed + dev <- identical(description[["RemoteType"]], "github") + remote <- if (dev) + paste("rstudio/renv", description[["RemoteSha"]], sep = "@") else - paste("renv", loadedversion, sep = "@") + paste("renv", description[["Version"]], sep = "@") - fmt <- paste( - "renv %1$s was loaded from project library, but this project is configured to use renv %2$s.", - "Use `renv::record(\"%3$s\")` to record renv %1$s in the lockfile.", - "Use `renv::restore(packages = \"renv\")` to install renv %2$s into the project library.", - sep = "\n" + # display both loaded version + sha if available + friendly <- renv_bootstrap_version_friendly( + version = description[["Version"]], + sha = if (dev) description[["RemoteSha"]] ) - msg <- sprintf(fmt, loadedversion, version, remote) - warning(msg, call. = FALSE) + fmt <- heredoc(" + renv %1$s was loaded from project library, but this project is configured to use renv %2$s. + - Use `renv::record(\"%3$s\")` to record renv %1$s in the lockfile. + - Use `renv::restore(packages = \"renv\")` to install renv %2$s into the project library. + ") + catf(fmt, friendly, renv_bootstrap_version_friendly(version), remote) FALSE } + renv_bootstrap_validate_version_dev <- function(version, description) { + expected <- description[["RemoteSha"]] + is.character(expected) && startswith(expected, version) + } + + renv_bootstrap_validate_version_release <- function(version, description) { + expected <- description[["Version"]] + is.character(expected) && identical(expected, version) + } + renv_bootstrap_hash_text <- function(text) { hashfile <- tempfile("renv-hash-") @@ -654,6 +894,12 @@ local({ # warn if the version of renv loaded does not match renv_bootstrap_validate_version(version) + # execute renv load hooks, if any + hooks <- getHook("renv::autoload") + for (hook in hooks) + if (is.function(hook)) + tryCatch(hook(), error = warnify) + # load the project renv::load(project) @@ -669,7 +915,7 @@ local({ return(profile) # check for a profile file (nothing to do if it doesn't exist) - path <- renv_bootstrap_paths_renv("profile", profile = FALSE) + path <- renv_bootstrap_paths_renv("profile", profile = FALSE, project = project) if (!file.exists(path)) return(NULL) @@ -793,12 +1039,78 @@ local({ } + renv_bootstrap_version_friendly <- function(version, shafmt = NULL, sha = NULL) { + sha <- sha %||% attr(version, "sha", exact = TRUE) + parts <- c(version, sprintf(shafmt %||% " [sha: %s]", substring(sha, 1L, 7L))) + paste(parts, collapse = "") + } + + renv_bootstrap_exec <- function(project, libpath, version) { + if (!renv_bootstrap_load(project, libpath, version)) + renv_bootstrap_run(version, libpath) + } + + renv_bootstrap_run <- function(version, libpath) { + + # perform bootstrap + bootstrap(version, libpath) + + # exit early if we're just testing bootstrap + if (!is.na(Sys.getenv("RENV_BOOTSTRAP_INSTALL_ONLY", unset = NA))) + return(TRUE) + + # try again to load + if (requireNamespace("renv", lib.loc = libpath, quietly = TRUE)) { + return(renv::load(project = getwd())) + } + + # failed to download or load renv; warn the user + msg <- c( + "Failed to find an renv installation: the project will not be loaded.", + "Use `renv::activate()` to re-initialize the project." + ) + + warning(paste(msg, collapse = "\n"), call. = FALSE) + + } renv_json_read <- function(file = NULL, text = NULL) { - text <- paste(text %||% read(file), collapse = "\n") + jlerr <- NULL + + # if jsonlite is loaded, use that instead + if ("jsonlite" %in% loadedNamespaces()) { + + json <- tryCatch(renv_json_read_jsonlite(file, text), error = identity) + if (!inherits(json, "error")) + return(json) + + jlerr <- json + + } + + # otherwise, fall back to the default JSON reader + json <- tryCatch(renv_json_read_default(file, text), error = identity) + if (!inherits(json, "error")) + return(json) + + # report an error + if (!is.null(jlerr)) + stop(jlerr) + else + stop(json) + + } + + renv_json_read_jsonlite <- function(file = NULL, text = NULL) { + text <- paste(text %||% readLines(file, warn = FALSE), collapse = "\n") + jsonlite::fromJSON(txt = text, simplifyVector = FALSE) + } + + renv_json_read_default <- function(file = NULL, text = NULL) { # find strings in the JSON + text <- paste(text %||% readLines(file, warn = FALSE), collapse = "\n") pattern <- '["](?:(?:\\\\.)|(?:[^"\\\\]))*?["]' locs <- gregexpr(pattern, text, perl = TRUE)[[1]] @@ -829,8 +1141,9 @@ local({ # transform the JSON into something the R parser understands transformed <- replaced - transformed <- gsub("[[{]", "list(", transformed) - transformed <- gsub("[]}]", ")", transformed) + transformed <- gsub("{}", "`names<-`(list(), character())", transformed, fixed = TRUE) + transformed <- gsub("[[{]", "list(", transformed, perl = TRUE) + transformed <- gsub("[]}]", ")", transformed, perl = TRUE) transformed <- gsub(":", "=", transformed, fixed = TRUE) text <- paste(transformed, collapse = "\n") @@ -845,14 +1158,14 @@ local({ map <- as.list(map) # remap strings in object - remapped <- renv_json_remap(json, map) + remapped <- renv_json_read_remap(json, map) # evaluate eval(remapped, envir = baseenv()) } - renv_json_remap <- function(json, map) { + renv_json_read_remap <- function(json, map) { # fix names if (!is.null(names(json))) { @@ -879,7 +1192,7 @@ local({ # recurse if (is.recursive(json)) { for (i in seq_along(json)) { - json[i] <- list(renv_json_remap(json[[i]], map)) + json[i] <- list(renv_json_read_remap(json[[i]], map)) } } @@ -899,35 +1212,9 @@ local({ # construct full libpath libpath <- file.path(root, prefix) - # attempt to load - if (renv_bootstrap_load(project, libpath, version)) - return(TRUE) - - # load failed; inform user we're about to bootstrap - prefix <- paste("# Bootstrapping renv", version) - postfix <- paste(rep.int("-", 77L - nchar(prefix)), collapse = "") - header <- paste(prefix, postfix) - message(header) - - # perform bootstrap - bootstrap(version, libpath) - - # exit early if we're just testing bootstrap - if (!is.na(Sys.getenv("RENV_BOOTSTRAP_INSTALL_ONLY", unset = NA))) - return(TRUE) - - # try again to load - if (requireNamespace("renv", lib.loc = libpath, quietly = TRUE)) { - message("* Successfully installed and loaded renv ", version, ".") - return(renv::load()) - } - - # failed to download or load renv; warn the user - msg <- c( - "Failed to find an renv installation: the project will not be loaded.", - "Use `renv::activate()` to re-initialize the project." - ) + # run bootstrap code + renv_bootstrap_exec(project, libpath, version) - warning(paste(msg, collapse = "\n"), call. = FALSE) + invisible() }) diff --git a/renv/settings.json b/renv/settings.json new file mode 100644 index 0000000..cc536fb --- /dev/null +++ b/renv/settings.json @@ -0,0 +1,21 @@ +{ + "bioconductor.version": null, + "external.libraries": [], + "ignored.packages": [ + "cohortBuilder" + ], + "package.dependency.fields": [ + "Imports", + "Depends", + "LinkingTo" + ], + "ppm.enabled": null, + "ppm.ignored.urls": [], + "r.version": [], + "snapshot.type": "all", + "use.cache": true, + "vcs.ignore.cellar": true, + "vcs.ignore.library": true, + "vcs.ignore.local": true, + "vcs.manage.ignores": true +} diff --git a/tests/testthat/test-filter.R b/tests/testthat/test-filter.R index ac8e288..95e785f 100644 --- a/tests/testthat/test-filter.R +++ b/tests/testthat/test-filter.R @@ -82,3 +82,47 @@ test_that("Multi discrete filter works fine", { ) }) + +test_that("Query discrete filter works fine", { + md_data <- data.frame(col1 = c("A", "B", "A", "B", "A"), col2 = c("C", "C", "C", "D", "D")) + md_source <- set_source( + tblist(md_data = md_data) + ) + md_filter <- cohortBuilder::filter( + type = "query", id = "qcols", name = "Query Cols", dataset = "md_data", + variables = c("col1", "col2"), + value = queryBuilder::queryGroup( + condition = "AND", + queryBuilder::queryRule("col1", "equal", "A"), + queryBuilder::queryRule("col2", "in", "D") + ) + ) + + coh <- Cohort$new( + md_source, + md_filter + ) + expect_equal(coh$get_data(1, state = "pre")$md_data, md_data) + + coh$run_flow() + expect_setequal(unique(coh$get_data(1, state = "post")$md_data$col1), c("A")) + expect_setequal(unique(coh$get_data(1, state = "post")$md_data$col2), c("D")) + + expect_equal( + coh$get_cache("1", "qcols", state = "pre")$specs$col1$values, + unique(md_data$col1) + ) + expect_equal( + coh$get_cache("1", "qcols", state = "pre")$specs$col2$values, + unique(md_data$col2) + ) + expect_equal( + coh$get_cache("1", "qcols", state = "post")$specs$col1$values, + unique(c("A")) + ) + expect_equal( + coh$get_cache("1", "qcols", state = "post")$specs$col2$values, + unique(c("D")) + ) + +})