From eb24644c7ff421478611cd5ea8a737367efa0465 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Ver=C3=ADssimo?= <211358+averissimo@users.noreply.github.com> Date: Mon, 28 Oct 2024 13:29:34 +0000 Subject: [PATCH 01/13] feat: initial support for names(teal_data) --- DESCRIPTION | 2 +- NAMESPACE | 3 +- NEWS.md | 10 +- R/deprecated.R | 35 +++++++ R/join_keys.R | 1 - R/teal_data-class.R | 16 +--- R/teal_data-datanames.R | 68 -------------- R/teal_data-names.R | 53 +++++++++++ man/datanames.Rd | 33 ++----- man/names.teal_data.Rd | 40 ++++++++ man/new_teal_data.Rd | 10 +- man/teal_data-class.Rd | 4 - tests/testthat/test-datanames.R | 116 +++++++++++++----------- tests/testthat/test-teal_data.R | 16 +--- vignettes/join-keys.Rmd | 4 - vignettes/teal-data-reproducibility.Rmd | 2 +- vignettes/teal-data.Rmd | 23 ++++- 17 files changed, 234 insertions(+), 202 deletions(-) delete mode 100644 R/teal_data-datanames.R create mode 100644 R/teal_data-names.R create mode 100644 man/names.teal_data.Rd diff --git a/DESCRIPTION b/DESCRIPTION index 25d9bb0c3..8fa36bb3c 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -72,8 +72,8 @@ Collate: 'join_keys.R' 'teal.data.R' 'teal_data-class.R' - 'teal_data-datanames.R' 'teal_data-get_code.R' + 'teal_data-names.R' 'teal_data-show.R' 'teal_data.R' 'testhat-helpers.R' diff --git a/NAMESPACE b/NAMESPACE index 71db8957b..5391bfda9 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -14,11 +14,12 @@ S3method(format,join_keys) S3method(join_keys,default) S3method(join_keys,join_keys) S3method(join_keys,teal_data) +S3method(names,"teal_data<-") +S3method(names,teal_data) S3method(parents,join_keys) S3method(parents,teal_data) S3method(print,join_keys) export("col_labels<-") -export("datanames<-") export("get_join_keys<-") export("join_keys<-") export("parents<-") diff --git a/NEWS.md b/NEWS.md index c37b3a076..26db0f66e 100644 --- a/NEWS.md +++ b/NEWS.md @@ -3,16 +3,18 @@ ### Breaking changes - soft deprecate `datanames` argument of `get_code()`. Use `names` instead. +- Soft deprecate of `datanames()` and `datanames(x) <- value` functions. +Use `names()` and `names(x) <- value` instead. ### Enhancements -- `datanames()` - - if `join_keys` are provided, the `datanames()` are now sorted in topological way (`Kahn` algorithm), +- `names()` function is introduced replacing `datanames`. + - if `join_keys` are provided, the `names()` are now sorted in topological way (`Kahn` algorithm), which means the parent dataset always precedes the child dataset. - - are extended by the parent dataset name, if one of the child dataset exist in `datanames()` and + - are extended by the parent dataset name, if one of the child dataset exist in `names()` and the connection between child-parent is set through `join_keys` and `parent` exist in `teal_data` environment. - do not allow to set a dataset name that do not exist in `teal_data` environment. - - `teal_data` no longer set default `datanames()` based on `join_keys` names - it uses only data names. + - `teal_data` no longer set default `names()` based on `join_keys` names - it uses only data names. ### Miscellaneous diff --git a/R/deprecated.R b/R/deprecated.R index d4b3e9e93..b876fb2ac 100644 --- a/R/deprecated.R +++ b/R/deprecated.R @@ -343,3 +343,38 @@ get_join_keys <- function(...) { get_labels <- function(...) { .deprecate_function("get_labels()", "Use col_labels(data)") } + +#' Names of data sets in `teal_data` object +#' +#' @description +#' `r lifecycle::badge("deprecated")` +#' +#' Use `names()` instead of `datanames()`. +#' +#' `datanames()` is deprecated. If object should be hidden, then use a `.` (dot) +#' prefix for the object's name. +#' +#' @param x (`teal_data` or `qenv_error`) object to access or modify +#' @param ... (`character`) new value for `@datanames`; all elements must be names of variables existing in `@env` +#' +#' @return The contents of `@datanames` or `teal_data` object with updated `@datanames`. +#' +#' +#' @name datanames + +#' @rdname datanames +#' @export +datanames <- function(x, ...) { + lifecycle::deprecate_soft("0.6.1", "datanames()", details = "names()") + names(x) +} + +#' @rdname datanames +`datanames<-` <- function(x, value, ...) { + lifecycle::deprecate_soft( + "0.6.1", + "`datanames<-`()", + details = "Function has no effect. Use a `.` (dot) prefix to hide objects instead in `teal_data`. See the documentation for more details." + ) + names(x) +} diff --git a/R/join_keys.R b/R/join_keys.R index 1798a46af..47fb97836 100644 --- a/R/join_keys.R +++ b/R/join_keys.R @@ -142,7 +142,6 @@ join_keys.teal_data <- function(...) { #' join_keys(td) `join_keys<-.teal_data` <- function(x, value) { join_keys(x@join_keys) <- value - datanames(x) <- x@datanames # datanames fun manages some exceptions x } diff --git a/R/teal_data-class.R b/R/teal_data-class.R index 3015797b9..23fc7c8e6 100644 --- a/R/teal_data-class.R +++ b/R/teal_data-class.R @@ -26,9 +26,6 @@ setOldClass("join_keys") #' @slot messages (`character`) vector of messages raised when evaluating code. #' @slot join_keys (`join_keys`) object specifying joining keys for data sets in `@env`. #' Access or modify with [join_keys()]. -#' @slot datanames (`character`) vector of names of data sets in `@env`. -#' Used internally to distinguish them from auxiliary variables. -#' Access or modify with [datanames()]. #' @slot verified (`logical(1)`) flag signifying that code in `@code` has been proven to yield contents of `@env`. #' Used internally. See [`verify()`] for more details. #' @@ -37,10 +34,9 @@ setOldClass("join_keys") setClass( Class = "teal_data", contains = "qenv", - slots = c(join_keys = "join_keys", datanames = "character", verified = "logical"), + slots = c(join_keys = "join_keys", verified = "logical"), prototype = list( join_keys = join_keys(), - datanames = character(0), verified = logical(0) ) ) @@ -53,18 +49,13 @@ setClass( #' @param code (`character` or `language`) code to reproduce the `data`. #' Accepts and stores comments also. #' @param join_keys (`join_keys`) object -#' @param datanames (`character`) names of datasets passed to `data`. -#' Needed when non-dataset objects are needed in the `env` slot. #' @rdname new_teal_data #' @keywords internal new_teal_data <- function(data, code = character(0), - join_keys = join_keys(), - datanames = names(data)) { + join_keys = join_keys()) { checkmate::assert_list(data) checkmate::assert_class(join_keys, "join_keys") - if (is.null(datanames)) datanames <- character(0) # todo: allow to specify - checkmate::assert_character(datanames) if (!any(is.language(code), is.character(code))) { stop("`code` must be a character or language object.") } @@ -82,8 +73,6 @@ new_teal_data <- function(data, new_env <- rlang::env_clone(list2env(data), parent = parent.env(.GlobalEnv)) lockEnvironment(new_env, bindings = TRUE) - datanames <- .get_sorted_datanames(datanames = datanames, join_keys = join_keys, env = new_env) - methods::new( "teal_data", env = new_env, @@ -92,7 +81,6 @@ new_teal_data <- function(data, messages = rep("", length(code)), id = id, join_keys = join_keys, - datanames = datanames, verified = verified ) } diff --git a/R/teal_data-datanames.R b/R/teal_data-datanames.R deleted file mode 100644 index d32727859..000000000 --- a/R/teal_data-datanames.R +++ /dev/null @@ -1,68 +0,0 @@ -#' Names of data sets in `teal_data` object -#' -#' Get or set the value of the `datanames` slot. -#' -#' The `@datanames` slot in a `teal_data` object specifies which of the variables stored in its environment -#' (the `@env` slot) are data sets to be taken into consideration. -#' The contents of `@datanames` can be specified upon creation and default to all variables in `@env`. -#' Variables created later, which may well be data sets, are not automatically considered such. -#' Use this function to update the slot. -#' -#' @param x (`teal_data`) object to access or modify -#' @param value (`character`) new value for `@datanames`; all elements must be names of variables existing in `@env` -#' -#' @return The contents of `@datanames` or `teal_data` object with updated `@datanames`. -#' -#' @examples -#' td <- teal_data(iris = iris) -#' td <- within(td, mtcars <- mtcars) -#' datanames(td) -#' -#' datanames(td) <- c("iris", "mtcars") -#' datanames(td) -#' -#' @name datanames -#' @aliases datanames,teal_data-method -#' @aliases datanames<-,teal_data,character-method -#' @aliases datanames,qenv.error-method -#' @aliases datanames<-,qenv.error,character-method - -#' @rdname datanames -#' @export -setGeneric("datanames", function(x) standardGeneric("datanames")) -setMethod("datanames", signature = "teal_data", definition = function(x) { - x@datanames -}) -setMethod("datanames", signature = "qenv.error", definition = function(x) { - NULL -}) - -#' @rdname datanames -#' @export -setGeneric("datanames<-", function(x, value) standardGeneric("datanames<-")) -setMethod("datanames<-", signature = c("teal_data", "character"), definition = function(x, value) { - checkmate::assert_subset(value, names(x@env)) - x@datanames <- .get_sorted_datanames(datanames = value, join_keys = x@join_keys, env = x@env) - methods::validObject(x) - x -}) -setMethod("datanames<-", signature = c("qenv.error", "character"), definition = function(x, value) { - methods::validObject(x) - x -}) - - -#' @keywords internal -.get_sorted_datanames <- function(datanames, join_keys, env) { - child_parent <- sapply( - datanames, - function(name) parent(join_keys, name), - USE.NAMES = TRUE, - simplify = FALSE - ) - - union( - intersect(unlist(topological_sort(child_parent)), ls(env)), - datanames - ) -} diff --git a/R/teal_data-names.R b/R/teal_data-names.R new file mode 100644 index 000000000..194d120f7 --- /dev/null +++ b/R/teal_data-names.R @@ -0,0 +1,53 @@ +#' Names of data sets in `teal_data` object +#' +#' Functions to get the names of a `teal_data` object. +#' The names are extrapolated from the objects in the `qenv` environment and +#' are not stored statically, unlike the normal behavior of `names()` function. +#' +#' Objects named with a `.` (dot) prefix will be ignored and not returned, +#' unless `all.names` parameter is set to `TRUE`. +#' +#' @param x A (`teal_data`) object to access or modify. +#' @param all.names (`logical(1)`) that specifies whether to include hidden +#' objects. +#' @param value Does nothing as the names assignment is not supported. +#' +#' @return A character vector of names. +#' +#' @examples +#' td <- teal_data(iris = iris) +#' td <- within(td, mtcars <- mtcars) +#' names(td) +#' +#' td <- within(td, .CO2 <- CO2) +#' names(td) +#' +#' @export +names.teal_data <- function(x, all.names = FALSE) { + checkmate::assert_flag(all.names) + # Call method on qenv class + names_x <- utils::getS3method("names", class = "qenv")(x, all.names) + .get_sorted_names(names_x, join_keys(x), teal.code::get_env(x)) +} + +#' @rdname names.teal_data +#' @export +`names.teal_data<-` <- function(x, value) { + warning("`names(x) <- value` assignment does nothing for teal_data objects") + x +} + +#' @keywords internal +.get_sorted_names <- function(datanames, join_keys, env) { + child_parent <- sapply( + datanames, + function(name) parent(join_keys, name), + USE.NAMES = TRUE, + simplify = FALSE + ) + + union( + intersect(unlist(topological_sort(child_parent)), ls(env, all.names = TRUE)), + datanames + ) +} diff --git a/man/datanames.Rd b/man/datanames.Rd index 4908979a2..16307f003 100644 --- a/man/datanames.Rd +++ b/man/datanames.Rd @@ -1,42 +1,27 @@ % Generated by roxygen2: do not edit by hand -% Please edit documentation in R/teal_data-datanames.R +% Please edit documentation in R/deprecated.R \name{datanames} \alias{datanames} -\alias{datanames,teal_data-method} -\alias{datanames<-,teal_data,character-method} -\alias{datanames,qenv.error-method} -\alias{datanames<-,qenv.error,character-method} \alias{datanames<-} \title{Names of data sets in \code{teal_data} object} \usage{ -datanames(x) +datanames(x, ...) -datanames(x) <- value +datanames(x, ...) <- value } \arguments{ -\item{x}{(\code{teal_data}) object to access or modify} +\item{x}{(\code{teal_data} or \code{qenv_error}) object to access or modify} -\item{value}{(\code{character}) new value for \verb{@datanames}; all elements must be names of variables existing in \verb{@env}} +\item{...}{(\code{character}) new value for \verb{@datanames}; all elements must be names of variables existing in \verb{@env}} } \value{ The contents of \verb{@datanames} or \code{teal_data} object with updated \verb{@datanames}. } \description{ -Get or set the value of the \code{datanames} slot. -} -\details{ -The \verb{@datanames} slot in a \code{teal_data} object specifies which of the variables stored in its environment -(the \verb{@env} slot) are data sets to be taken into consideration. -The contents of \verb{@datanames} can be specified upon creation and default to all variables in \verb{@env}. -Variables created later, which may well be data sets, are not automatically considered such. -Use this function to update the slot. -} -\examples{ -td <- teal_data(iris = iris) -td <- within(td, mtcars <- mtcars) -datanames(td) +\ifelse{html}{\href{https://lifecycle.r-lib.org/articles/stages.html#deprecated}{\figure{lifecycle-deprecated.svg}{options: alt='[Deprecated]'}}}{\strong{[Deprecated]}} -datanames(td) <- c("iris", "mtcars") -datanames(td) +Use \code{names()} instead of \code{datanames()}. +\code{datanames()} is deprecated. If object should be hidden, then use a \code{.} (dot) +prefix for the object's name. } diff --git a/man/names.teal_data.Rd b/man/names.teal_data.Rd new file mode 100644 index 000000000..3daeee900 --- /dev/null +++ b/man/names.teal_data.Rd @@ -0,0 +1,40 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/teal_data-names.R +\name{names.teal_data} +\alias{names.teal_data} +\alias{names.teal_data<-} +\title{Names of data sets in \code{teal_data} object} +\usage{ +\method{names}{teal_data}(x, all.names = FALSE) + +\method{names}{`teal_data<-`}(x, value) +} +\arguments{ +\item{x}{A (\code{teal_data}) object to access or modify.} + +\item{all.names}{(\code{logical(1)}) that specifies whether to include hidden +objects.} + +\item{value}{Does nothing as the names assignment is not supported.} +} +\value{ +A character vector of names. +} +\description{ +Functions to get the names of a \code{teal_data} object. +The names are extrapolated from the objects in the \code{qenv} environment and +are not stored statically, unlike the normal behavior of \code{names()} function. +} +\details{ +Objects named with a \code{.} (dot) prefix will be ignored and not returned, +unless \code{all.names} parameter is set to \code{TRUE}. +} +\examples{ +td <- teal_data(iris = iris) +td <- within(td, mtcars <- mtcars) +names(td) + +td <- within(td, .CO2 <- CO2) +names(td) + +} diff --git a/man/new_teal_data.Rd b/man/new_teal_data.Rd index 4ddc43c95..2bdd63ee9 100644 --- a/man/new_teal_data.Rd +++ b/man/new_teal_data.Rd @@ -4,12 +4,7 @@ \alias{new_teal_data} \title{Initialize \code{teal_data} object} \usage{ -new_teal_data( - data, - code = character(0), - join_keys = join_keys(), - datanames = names(data) -) +new_teal_data(data, code = character(0), join_keys = join_keys()) } \arguments{ \item{data}{(\verb{named list}) of data objects.} @@ -18,9 +13,6 @@ new_teal_data( Accepts and stores comments also.} \item{join_keys}{(\code{join_keys}) object} - -\item{datanames}{(\code{character}) names of datasets passed to \code{data}. -Needed when non-dataset objects are needed in the \code{env} slot.} } \description{ Initialize \code{teal_data} object diff --git a/man/teal_data-class.Rd b/man/teal_data-class.Rd index ef1c1decb..d35268e77 100644 --- a/man/teal_data-class.Rd +++ b/man/teal_data-class.Rd @@ -36,10 +36,6 @@ Access with \code{\link[=get_warnings]{get_warnings()}}.} \item{\code{join_keys}}{(\code{join_keys}) object specifying joining keys for data sets in \verb{@env}. Access or modify with \code{\link[=join_keys]{join_keys()}}.} -\item{\code{datanames}}{(\code{character}) vector of names of data sets in \verb{@env}. -Used internally to distinguish them from auxiliary variables. -Access or modify with \code{\link[=datanames]{datanames()}}.} - \item{\code{verified}}{(\code{logical(1)}) flag signifying that code in \verb{@code} has been proven to yield contents of \verb{@env}. Used internally. See \code{\link[=verify]{verify()}} for more details.} }} diff --git a/tests/testthat/test-datanames.R b/tests/testthat/test-datanames.R index e0c99bb63..22e169fba 100644 --- a/tests/testthat/test-datanames.R +++ b/tests/testthat/test-datanames.R @@ -1,128 +1,136 @@ # get ---- -testthat::test_that("datanames returns contents of @datanames slot", { +testthat::test_that("names returns list of objects in teal_data", { td <- teal_data(i = iris, m = mtcars) - testthat::expect_identical(datanames(td), c("i", "m")) + testthat::expect_identical(names(td), c("i", "m")) }) -testthat::test_that("variables not in @datanames are omitted", { +testthat::test_that("variables with dot prefix are omitted", { td <- teal_data(i = iris, m = mtcars) - td <- within(td, f <- faithful) - testthat::expect_identical(datanames(td), c("i", "m")) + td <- within(td, .f <- faithful) + testthat::expect_identical(names(td), c("i", "m")) }) -# set ---- -testthat::test_that("datanames can set value of @datanames", { - td <- teal_data(i = iris, m = mtcars) - testthat::expect_identical(datanames(td), c("i", "m")) - datanames(td) <- "i" - testthat::expect_identical(datanames(td), "i") -}) +# set --- +testthat::describe("names<- called on teal_data", { + testthat::it("throws warning", { + td <- teal_data(i = iris, m = mtcars) + testthat::expect_warning(names(td) <- c("a", "b", "c"), "assignment does nothing for qenv objects") + }) -testthat::test_that("only names of existing variables are accepted", { - td <- teal_data(i = iris, m = mtcars) - testthat::expect_no_error(datanames(td) <- "i") - testthat::expect_error(datanames(td) <- "f", "Assertion .* failed: Must be a subset") + testthat::it("does not change it", { + td <- teal_data(i = iris, m = mtcars) + tdc <- td <- teal_data(i = iris, m = mtcars) + suppressWarnings(names(td) <- c("a", "b", "c")) + testthat::expect_identical(qe, qec) + }) }) # qenv.error support ---- -testthat::test_that("datanames supports qenv.error class", { +testthat::test_that("names supports qenv.error class", { qe <- within(teal_data(), stop()) - testthat::expect_no_error(datanames(qe)) - testthat::expect_no_error(datanames(qe) <- "name") + testthat::expect_no_error(names(qe)) }) -testthat::test_that("datanames called on qenv.error returns NULL", { +testthat::test_that("names called on qenv.error returns NULL", { qe <- within(teal_data(), stop()) - testthat::expect_null(datanames(qe)) + testthat::expect_null(names(qe)) }) -testthat::test_that("datanames<- called on qenv.error does not change qenv.error", { - qe <- within(teal_data(), stop()) - qec <- qe - testthat::expect_identical(qe, qec) +testthat::describe("names<- called on qenv.error", { + testthat::it("throws warning", { + qe <- within(teal_data(), stop()) + testthat::expect_warning(names(qe) <- c("a", "b", "c"), "assignment does nothing for qenv.error objects") + }) + testthat::test_that("does not change qenv.error", { + qe <- within(teal_data(), stop()) + qec <- within(teal_data(), stop()) + suppressWarnings(names(qe) <- c("a", "b", "c")) + testthat::expect_identical(qe, qec) + }) }) # topological_order ---- -testthat::test_that("datanames are set in topological order in constructor if join_keys are specified", { +testthat::test_that("names are set in topological order in constructor if join_keys are specified", { data <- teal_data(b = data.frame(), a = data.frame(), join_keys = join_keys(join_key("a", "b", "id"))) testthat::expect_identical( - datanames(data), + names(data), c("a", "b") ) }) -testthat::test_that("datanames return parent if in constructor it was provided in join_keys and exists in env", { - data <- - teal_data(b = data.frame(), a = data.frame(), join_keys = join_keys(join_key("a", "b", "id"))) - datanames(data) <- "b" - testthat::expect_identical( - datanames(data), - c("a", "b") +testthat::test_that("names return parent if in constructor it was provided in join_keys and exists in env", { + data <- teal_data( + b = data.frame(), + .a = data.frame(), + join_keys = join_keys(join_key(".a", "b", "id")) ) + testthat::expect_setequal(names(data), c(".a", "b")) }) testthat::test_that( - "datanames do not return parent if in constructor it was provided in join_keys but do not exists in env", + "names do not return parent if in constructor it was provided in join_keys but do not exists in env", { - data <- - teal_data(b = data.frame(), join_keys = join_keys(join_key("a", "b", "id"))) + data <- teal_data(b = data.frame(), join_keys = join_keys(join_key("a", "b", "id"))) testthat::expect_identical( - datanames(data), + names(data), "b" ) } ) -testthat::test_that("datanames return topological order of datasets once join_keys are specified", { +testthat::test_that("names return topological order of datasets once join_keys are specified", { data <- within(teal_data(), { ADTTE <- teal.data::rADTTE # nolint: object_name. - iris <- iris + ADTR <- teal.data::rADTR # nolint: object_name. ADSL <- teal.data::rADSL # nolint: object_name. }) - datanames(data) <- c("ADTTE", "iris", "ADSL") join_keys(data) <- default_cdisc_join_keys[c("ADSL", "ADTTE")] testthat::expect_identical( - datanames(data), - c("ADSL", "ADTTE", "iris") + names(data), + c("ADTR", "ADSL", "ADTTE") ) }) -testthat::test_that("datanames return topological order of datasets after datanames are called after join_keys", { +testthat::test_that("names return topological order of datasets after new objects are added after join_keys", { data <- within(teal_data(), { ADTTE <- teal.data::rADTTE # nolint: object_name. - iris <- iris ADSL <- teal.data::rADSL # nolint: object_name. }) + testthat::expect_identical( + names(data), + c("ADSL", "ADTTE") + ) + join_keys(data) <- default_cdisc_join_keys[c("ADSL", "ADTTE")] - datanames(data) <- c("ADTTE", "iris", "ADSL") + data <- within(data, ADTR <- teal.data::rADTR) # nolint: object_name. testthat::expect_identical( - datanames(data), - c("ADSL", "ADTTE", "iris") + names(data), + c("ADTR", "ADSL", "ADTTE") ) }) -testthat::test_that("datanames return parent if join_keys were provided and parent exists in env", { +testthat::test_that("names return parent if join_keys were provided and parent exists in env", { data <- within(teal_data(), { ADTTE <- teal.data::rADTTE # nolint: object_name. iris <- iris - ADSL <- teal.data::rADSL # nolint: object_name. + .ADSL <- teal.data::rADSL # nolint: object_name. }) join_keys(data) <- default_cdisc_join_keys[c("ADSL", "ADTTE")] - datanames(data) <- c("ADTTE", "iris") + names(join_keys(data)) <- c(".ADSL", "ADTTE") testthat::expect_identical( - datanames(data), + names(data), c("ADSL", "ADTTE", "iris") ) }) -testthat::test_that("datanames do not return parent if join_keys were provided and parent did not exists in env", { +testthat::test_that("names do not return parent if join_keys were provided and parent did not exists in env", { data <- teal_data( ADTTE = teal.data::rADTTE, # nolint: object_name. iris = iris @@ -131,7 +139,7 @@ testthat::test_that("datanames do not return parent if join_keys were provided a join_keys(data) <- default_cdisc_join_keys[c("ADSL", "ADTTE")] testthat::expect_identical( - datanames(data), + names(data), c("ADTTE", "iris") ) }) diff --git a/tests/testthat/test-teal_data.R b/tests/testthat/test-teal_data.R index 8391f72e2..e5d7ab895 100644 --- a/tests/testthat/test-teal_data.R +++ b/tests/testthat/test-teal_data.R @@ -21,34 +21,26 @@ testthat::test_that("teal_data allows to initialize empty teal_data with join_ke ) }) -testthat::test_that("teal_data initializes teal_data object with @datanames taken from passed objects", { - testthat::expect_identical( - teal_data(iris = iris, mtcars = mtcars)@datanames, - c("iris", "mtcars") - ) -}) - testthat::test_that( - "teal_data initializes teal_data object without @datanames taken from join_keys if objects did not exist in env", + "teal_data initializes teal_data object without names taken from join_keys if objects did not exist in env", { testthat::expect_identical( - datanames(teal_data(join_keys = join_keys(join_key("parent", "child", "id")))), + names(teal_data(join_keys = join_keys(join_key("parent", "child", "id")))), character(0) ) } ) testthat::test_that( - "teal_data initializes teal_data object with @datanames taken only from passed objects and not join_keys", + "teal_data initializes teal_data object with names taken only from passed objects and not join_keys", { testthat::expect_identical( - datanames(teal_data(iris = iris, join_keys = join_keys(join_key("parent", "child", "id")))), + names(teal_data(iris = iris, join_keys = join_keys(join_key("parent", "child", "id")))), "iris" ) } ) - testthat::test_that("teal_data returns teal_data when data passed as named list", { df1 <- data.frame(id = c("A", "B"), a = c(1L, 2L)) testthat::expect_s4_class(teal_data(df1 = df1), "teal_data") diff --git a/vignettes/join-keys.Rmd b/vignettes/join-keys.Rmd index 9d06fed22..9ead04820 100644 --- a/vignettes/join-keys.Rmd +++ b/vignettes/join-keys.Rmd @@ -192,7 +192,6 @@ td_pk <- within( teal_data(), ds1 <- transform(iris, id = seq_len(nrow(iris))) ) -datanames(td_pk) <- "ds1" join_keys(td_pk) <- join_keys(join_key("ds1", keys = "id")) @@ -209,7 +208,6 @@ td_pk <- within( ds3 <- data.frame(V = 5:14, N = 4) } ) -datanames(td_pk) <- c(datanames(td_pk), "ds2", "ds3") join_keys(td_pk)["ds2", "ds2"] <- c("V", "W") join_keys(td_pk)["ds3", "ds3"] <- c("V", "W") @@ -239,7 +237,6 @@ td_fk <- within( ds3 <- data.frame(V = 5:14, N = 4) } ) -datanames(td_fk) <- c("ds1", "ds2", "ds3") join_keys(td_fk) <- join_keys( # Primary keys @@ -275,7 +272,6 @@ td <- within( ds4 <- data.frame(V = 5:14, R = rnorm(10)) } ) -datanames(td) <- c("ds1", "ds2", "ds3", "ds4") join_keys(td) <- join_keys( # Primary keys diff --git a/vignettes/teal-data-reproducibility.Rmd b/vignettes/teal-data-reproducibility.Rmd index f39d0a81b..b0b379cc9 100644 --- a/vignettes/teal-data-reproducibility.Rmd +++ b/vignettes/teal-data-reproducibility.Rmd @@ -105,7 +105,7 @@ Note that in when retrieving code for a specific dataset, the result is only the ## Tracking object dependencies -Calling `get_code` with `datanames` specified initiates an analysis of the stored code, in which object dependencies are automatically discovered. +Calling `get_code` with `names` specified initiates an analysis of the stored code, in which object dependencies are automatically discovered. If object `x` is created with an expression that uses object `y`, the lines that create object `y` must also be returned. This is quite effective when objects are created by simple assignments like `x <- foo(y)`. However, in rare cases discovering dependencies is impossible, _e.g._ when opening connections to databases or when objects are created by side effects (functions acting on their calling environment implicitly rather than returning a value that is then assigned). diff --git a/vignettes/teal-data.Rmd b/vignettes/teal-data.Rmd index 687b136d9..2288a7f5b 100644 --- a/vignettes/teal-data.Rmd +++ b/vignettes/teal-data.Rmd @@ -40,9 +40,8 @@ my_data[["data1"]] # get reproducible code get_code(my_data) -# get or set datanames -datanames(my_data) <- c("data1", "data2") -datanames(my_data) +# get datanames +names(my_data) # print print(my_data) @@ -55,7 +54,7 @@ A `teal_data` object keeps the following information: - `env` - an environment containing data. - `code` - a string containing code to reproduce `env` (details in [reproducibility](teal-data-reproducibility.html)). -- `datanames` - a character vector listing objects of interest to `teal` modules (details in [this `teal` vignette](https://insightsengineering.github.io/teal/latest-tag/articles/including-data-in-teal-applications.html)). +- `names` - a character vector listing objects of interest to `teal` modules (details in [this `teal` vignette](https://insightsengineering.github.io/teal/latest-tag/articles/including-data-in-teal-applications.html)). - `join_keys` - a `join_keys` object defining relationships between datasets (details in [Join Keys](join-keys.html)). ### Reproducibility @@ -71,7 +70,6 @@ my_data <- within(my_data, data$id <- seq_len(nrow(data))) my_data # is verified ``` - ### Relational data models The `teal_data` class supports relational data. @@ -94,3 +92,18 @@ join_keys(my_data) <- join_keys( join_keys(my_data) ``` + +### Hidden objects + +An object is hidden in `teal_data` if its name starts with a dot (`.`). +This can be used to pass auxiliary objects / function in the `teal_data` instance, without being visible in the `teal` summary and filter panel. + +```{r} +my_data <- teal_data() +my_data <- within(my_data, { + data <- data.frame(id = 1:10, x = 11:20) + .data2 <- data.frame(id = 1:20, data_id = c(1:10, 1:10), y = 21:30) +}) + +names(my_data) +``` From b3fe731f55d93f3dcdcca02e475b66a71e01c409 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Ver=C3=ADssimo?= <211358+averissimo@users.noreply.github.com> Date: Mon, 28 Oct 2024 18:09:30 +0000 Subject: [PATCH 02/13] fix: remove extra parameters and deprecate names()<-.teal_data --- NAMESPACE | 2 +- R/deprecated.R | 15 +++++++++++++-- R/teal_data-names.R | 16 ++-------------- man/datanames.Rd | 4 ++-- man/names.teal_data.Rd | 10 +--------- 5 files changed, 19 insertions(+), 28 deletions(-) diff --git a/NAMESPACE b/NAMESPACE index 5391bfda9..565f57429 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -6,6 +6,7 @@ S3method("[[<-",join_keys) S3method("join_keys<-",join_keys) S3method("join_keys<-",teal_data) S3method("names<-",join_keys) +S3method("names<-",teal_data) S3method("parents<-",join_keys) S3method("parents<-",teal_data) S3method(c,join_key_set) @@ -14,7 +15,6 @@ S3method(format,join_keys) S3method(join_keys,default) S3method(join_keys,join_keys) S3method(join_keys,teal_data) -S3method(names,"teal_data<-") S3method(names,teal_data) S3method(parents,join_keys) S3method(parents,teal_data) diff --git a/R/deprecated.R b/R/deprecated.R index b876fb2ac..5f35794f5 100644 --- a/R/deprecated.R +++ b/R/deprecated.R @@ -370,11 +370,22 @@ datanames <- function(x, ...) { } #' @rdname datanames -`datanames<-` <- function(x, value, ...) { +`datanames<-.teal_data` <- function(x, value, ...) { lifecycle::deprecate_soft( "0.6.1", "`datanames<-`()", - details = "Function has no effect. Use a `.` (dot) prefix to hide objects instead in `teal_data`. See the documentation for more details." + details = "invalid to use `datanames()<-` or `names()<-` on an object of class `teal_data`. See ?names.teal_data" ) names(x) } + +#' @export +#' @keywords internal +`names<-.teal_data` <- function(x, value) { + lifecycle::deprecate_warn( + "0.6.1", + "`names.teal_data<-`()", + details = "invalid to use `datanames()<-` or `names()<-` on an object of class `teal_data`. See ?names.teal_data" + ) + x +} diff --git a/R/teal_data-names.R b/R/teal_data-names.R index 194d120f7..f8c97c041 100644 --- a/R/teal_data-names.R +++ b/R/teal_data-names.R @@ -8,9 +8,6 @@ #' unless `all.names` parameter is set to `TRUE`. #' #' @param x A (`teal_data`) object to access or modify. -#' @param all.names (`logical(1)`) that specifies whether to include hidden -#' objects. -#' @param value Does nothing as the names assignment is not supported. #' #' @return A character vector of names. #' @@ -23,20 +20,11 @@ #' names(td) #' #' @export -names.teal_data <- function(x, all.names = FALSE) { - checkmate::assert_flag(all.names) - # Call method on qenv class - names_x <- utils::getS3method("names", class = "qenv")(x, all.names) +names.teal_data <- function(x) { + names_x <- utils::getS3method("names", class = "qenv")(x) .get_sorted_names(names_x, join_keys(x), teal.code::get_env(x)) } -#' @rdname names.teal_data -#' @export -`names.teal_data<-` <- function(x, value) { - warning("`names(x) <- value` assignment does nothing for teal_data objects") - x -} - #' @keywords internal .get_sorted_names <- function(datanames, join_keys, env) { child_parent <- sapply( diff --git a/man/datanames.Rd b/man/datanames.Rd index 16307f003..16d34c579 100644 --- a/man/datanames.Rd +++ b/man/datanames.Rd @@ -2,12 +2,12 @@ % Please edit documentation in R/deprecated.R \name{datanames} \alias{datanames} -\alias{datanames<-} +\alias{datanames<-.teal_data} \title{Names of data sets in \code{teal_data} object} \usage{ datanames(x, ...) -datanames(x, ...) <- value +datanames.teal_data(x, ...) <- value } \arguments{ \item{x}{(\code{teal_data} or \code{qenv_error}) object to access or modify} diff --git a/man/names.teal_data.Rd b/man/names.teal_data.Rd index 3daeee900..06fa3179a 100644 --- a/man/names.teal_data.Rd +++ b/man/names.teal_data.Rd @@ -2,20 +2,12 @@ % Please edit documentation in R/teal_data-names.R \name{names.teal_data} \alias{names.teal_data} -\alias{names.teal_data<-} \title{Names of data sets in \code{teal_data} object} \usage{ -\method{names}{teal_data}(x, all.names = FALSE) - -\method{names}{`teal_data<-`}(x, value) +\method{names}{teal_data}(x) } \arguments{ \item{x}{A (\code{teal_data}) object to access or modify.} - -\item{all.names}{(\code{logical(1)}) that specifies whether to include hidden -objects.} - -\item{value}{Does nothing as the names assignment is not supported.} } \value{ A character vector of names. From 8406a837293dc943317e7fbc3ea19559b6ae52d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Ver=C3=ADssimo?= <211358+averissimo@users.noreply.github.com> Date: Wed, 30 Oct 2024 18:57:04 +0000 Subject: [PATCH 03/13] feat: update to remove all @env mentions --- R/teal_data-class.R | 6 ++---- R/teal_data-show.R | 2 +- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/R/teal_data-class.R b/R/teal_data-class.R index 23fc7c8e6..d218ec281 100644 --- a/R/teal_data-class.R +++ b/R/teal_data-class.R @@ -51,9 +51,7 @@ setClass( #' @param join_keys (`join_keys`) object #' @rdname new_teal_data #' @keywords internal -new_teal_data <- function(data, - code = character(0), - join_keys = join_keys()) { +new_teal_data <- function(data, code = character(0), join_keys = join_keys()) { checkmate::assert_list(data) checkmate::assert_class(join_keys, "join_keys") if (!any(is.language(code), is.character(code))) { @@ -75,7 +73,7 @@ new_teal_data <- function(data, methods::new( "teal_data", - env = new_env, + .xData = new_env, code = code, warnings = rep("", length(code)), messages = rep("", length(code)), diff --git a/R/teal_data-show.R b/R/teal_data-show.R index b47f29c10..fca8cf66e 100644 --- a/R/teal_data-show.R +++ b/R/teal_data-show.R @@ -16,5 +16,5 @@ setMethod("show", signature = "teal_data", function(object) { } else { cat("\u2716", "unverified teal_data object\n") } - rlang::env_print(object@env) + rlang::env_print(teal.code::get_env(object)) }) From cd5a93884e86f667cdd458f15b9c09de49da10b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Ver=C3=ADssimo?= <211358+averissimo@users.noreply.github.com> Date: Wed, 30 Oct 2024 19:46:41 +0000 Subject: [PATCH 04/13] fix: replace @env and corrects minor issues with qenv as environment --- NAMESPACE | 1 + NEWS.md | 7 +-- R/deprecated.R | 12 +++-- R/teal_data-class.R | 19 +++++--- R/teal_data-get_code.R | 6 ++- R/teal_data-names.R | 4 +- R/verify.R | 16 ++++--- man/datanames.Rd | 13 ++++-- man/get_code.Rd | 6 ++- man/teal_data-class.Rd | 19 +++++--- man/verify.Rd | 6 ++- tests/testthat/test-teal_data.R | 8 ++-- ...est-datanames.R => test-test_data-names.R} | 46 +++---------------- tests/testthat/test-verify.R | 2 +- 14 files changed, 80 insertions(+), 85 deletions(-) rename tests/testthat/{test-datanames.R => test-test_data-names.R} (71%) diff --git a/NAMESPACE b/NAMESPACE index 565f57429..49a6f08bb 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -20,6 +20,7 @@ S3method(parents,join_keys) S3method(parents,teal_data) S3method(print,join_keys) export("col_labels<-") +export("datanames<-") export("get_join_keys<-") export("join_keys<-") export("parents<-") diff --git a/NEWS.md b/NEWS.md index 26db0f66e..bcf1da4d2 100644 --- a/NEWS.md +++ b/NEWS.md @@ -2,9 +2,10 @@ ### Breaking changes -- soft deprecate `datanames` argument of `get_code()`. Use `names` instead. -- Soft deprecate of `datanames()` and `datanames(x) <- value` functions. -Use `names()` and `names(x) <- value` instead. +- Soft deprecate `datanames` argument of `get_code()`. Use `names` instead. +- Soft deprecate of `datanames()`. Use `names()` instead. +- Deprecate of `datanames(x) <- value`. Does nothing, replace with renaming the objects inside the environment. + ### Enhancements diff --git a/R/deprecated.R b/R/deprecated.R index 5f35794f5..97035fcd8 100644 --- a/R/deprecated.R +++ b/R/deprecated.R @@ -355,22 +355,23 @@ get_labels <- function(...) { #' prefix for the object's name. #' #' @param x (`teal_data` or `qenv_error`) object to access or modify -#' @param ... (`character`) new value for `@datanames`; all elements must be names of variables existing in `@env` +#' @param value (`character`) new value for `@datanames`; all elements must be names of variables existing in `@.xData` #' #' @return The contents of `@datanames` or `teal_data` object with updated `@datanames`. -#' +#' @aliases `datanames<-.teal_data` #' #' @name datanames #' @rdname datanames #' @export -datanames <- function(x, ...) { +datanames <- function(x) { lifecycle::deprecate_soft("0.6.1", "datanames()", details = "names()") names(x) } #' @rdname datanames -`datanames<-.teal_data` <- function(x, value, ...) { +#' @export +`datanames<-` <- function(x, value) { lifecycle::deprecate_soft( "0.6.1", "`datanames<-`()", @@ -379,12 +380,13 @@ datanames <- function(x, ...) { names(x) } +#' @rdname datanames #' @export #' @keywords internal `names<-.teal_data` <- function(x, value) { lifecycle::deprecate_warn( "0.6.1", - "`names.teal_data<-`()", + "`names<-.teal_data`()", details = "invalid to use `datanames()<-` or `names()<-` on an object of class `teal_data`. See ?names.teal_data" ) x diff --git a/R/teal_data-class.R b/R/teal_data-class.R index d218ec281..a5ddb439a 100644 --- a/R/teal_data-class.R +++ b/R/teal_data-class.R @@ -14,19 +14,24 @@ setOldClass("join_keys") #' @name teal_data-class #' @rdname teal_data-class #' -#' @slot env (`environment`) environment containing data sets and possibly auxiliary variables. -#' Access variables with [get_var()] or [`[[`]. -#' No setter provided. Evaluate code to add variables into `@env`. -#' @slot code (`character`) vector representing code necessary to reproduce the contents of `@env`. +#' @slot .xData (`environment`) environment containing data sets and possibly +#' auxiliary variables. +#' Access variables with [get()], [`$`], [get_var()] or [`[[`]. +#' No setter provided. Evaluate code to add variables into `@.xData`. +#' @slot code (`character`) vector representing code necessary to reproduce the +#' contents of `@.xData`. #' Access with [get_code()]. #' No setter provided. Evaluate code to append code to the slot. -#' @slot id (`integer`) random identifier assigned to each element of `@code`. Used internally. +#' @slot id (`integer`) random identifier assigned to each element of `@code`. +#' Used internally. #' @slot warnings (`character`) vector of warnings raised when evaluating code. #' Access with [get_warnings()]. #' @slot messages (`character`) vector of messages raised when evaluating code. -#' @slot join_keys (`join_keys`) object specifying joining keys for data sets in `@env`. +#' @slot join_keys (`join_keys`) object specifying joining keys for data sets in +#' `@.xData`. #' Access or modify with [join_keys()]. -#' @slot verified (`logical(1)`) flag signifying that code in `@code` has been proven to yield contents of `@env`. +#' @slot verified (`logical(1)`) flag signifying that code in `@code` has been +#' proven to yield contents of `@.xData`. #' Used internally. See [`verify()`] for more details. #' #' @import teal.code diff --git a/R/teal_data-get_code.R b/R/teal_data-get_code.R index 1fd668193..d1292c7a5 100644 --- a/R/teal_data-get_code.R +++ b/R/teal_data-get_code.R @@ -2,8 +2,10 @@ #' #' Retrieve code from `teal_data` object. #' -#' Retrieve code stored in `@code`, which (in principle) can be used to recreate all objects found in `@env`. -#' Use `names` to limit the code to one or more of the datasets enumerated in `@datanames`. +#' Retrieve code stored in `@code`, which (in principle) can be used to recreate +#' all objects found in `@.xData`. +#' Use `names` to limit the code to one or more of the datasets enumerated in +#' the environment. #' #' @section Extracting dataset-specific code: #' When `names` is specified, the code returned will be limited to the lines needed to _create_ diff --git a/R/teal_data-names.R b/R/teal_data-names.R index f8c97c041..2da0b187e 100644 --- a/R/teal_data-names.R +++ b/R/teal_data-names.R @@ -21,8 +21,8 @@ #' #' @export names.teal_data <- function(x) { - names_x <- utils::getS3method("names", class = "qenv")(x) - .get_sorted_names(names_x, join_keys(x), teal.code::get_env(x)) + names_x <- ls(x) + .get_sorted_names(names_x, join_keys(x), as.environment(x)) } #' @keywords internal diff --git a/R/verify.R b/R/verify.R index 7caa648f2..df40e91bd 100644 --- a/R/verify.R +++ b/R/verify.R @@ -2,10 +2,12 @@ #' #' Checks whether code in `teal_data` object reproduces the stored objects. #' -#' If objects created by code in the `@code` slot of `x` are `all_equal` to the contents of the `@env` slot, +#' If objects created by code in the `@code` slot of `x` are `all_equal` to the +#' contents of the `@.xData` slot, #' the function updates the `@verified` slot to `TRUE` in the returned `teal_data` object. #' Once verified, the slot will always be set to `TRUE`. -#' If the `@code` fails to recreate objects in `teal_data@env`, an error is raised. +#' If the `@code` fails to recreate objects in `teal_data`'s environment, an +#' error is raised. #' #' @return Input `teal_data` object or error. #' @@ -65,7 +67,7 @@ setMethod("verify", signature = "teal_data", definition = function(x) { stop(conditionMessage(y), call. = FALSE) } - reproduced <- isTRUE(all.equal(x@env, y@env)) + reproduced <- isTRUE(all.equal(teal.code::get_env(x), teal.code::get_env(y))) if (reproduced) { x@verified <- TRUE methods::validObject(x) @@ -74,15 +76,15 @@ setMethod("verify", signature = "teal_data", definition = function(x) { error <- "Code verification failed." objects_diff <- vapply( - intersect(names(x@env), names(y@env)), + intersect(names(x), names(y)), function(element) { - isTRUE(all.equal(x@env[[element]], y@env[[element]])) + isTRUE(all.equal(x[[element]], y[[element]])) }, logical(1) ) - names_diff_other <- setdiff(names(y@env), names(x@env)) - names_diff_inenv <- setdiff(names(x@env), names(y@env)) + names_diff_other <- setdiff(names(y), names(x)) + names_diff_inenv <- setdiff(names(x), names(y)) if (length(objects_diff)) { error <- c( diff --git a/man/datanames.Rd b/man/datanames.Rd index 16d34c579..19cbb2a0e 100644 --- a/man/datanames.Rd +++ b/man/datanames.Rd @@ -2,17 +2,21 @@ % Please edit documentation in R/deprecated.R \name{datanames} \alias{datanames} -\alias{datanames<-.teal_data} +\alias{`datanames<-.teal_data`} +\alias{datanames<-} +\alias{names<-.teal_data} \title{Names of data sets in \code{teal_data} object} \usage{ -datanames(x, ...) +datanames(x) -datanames.teal_data(x, ...) <- value +datanames(x) <- value + +\method{names}{teal_data}(x) <- value } \arguments{ \item{x}{(\code{teal_data} or \code{qenv_error}) object to access or modify} -\item{...}{(\code{character}) new value for \verb{@datanames}; all elements must be names of variables existing in \verb{@env}} +\item{value}{(\code{character}) new value for \verb{@datanames}; all elements must be names of variables existing in \verb{@.xData}} } \value{ The contents of \verb{@datanames} or \code{teal_data} object with updated \verb{@datanames}. @@ -25,3 +29,4 @@ Use \code{names()} instead of \code{datanames()}. \code{datanames()} is deprecated. If object should be hidden, then use a \code{.} (dot) prefix for the object's name. } +\keyword{internal} diff --git a/man/get_code.Rd b/man/get_code.Rd index 8a21424e7..38bcaf41a 100644 --- a/man/get_code.Rd +++ b/man/get_code.Rd @@ -36,8 +36,10 @@ only code that \emph{creates} that dataset (not code that uses it) is returned. Retrieve code from \code{teal_data} object. } \details{ -Retrieve code stored in \verb{@code}, which (in principle) can be used to recreate all objects found in \verb{@env}. -Use \code{names} to limit the code to one or more of the datasets enumerated in \verb{@datanames}. +Retrieve code stored in \verb{@code}, which (in principle) can be used to recreate +all objects found in \verb{@.xData}. +Use \code{names} to limit the code to one or more of the datasets enumerated in +the environment. } \section{Extracting dataset-specific code}{ diff --git a/man/teal_data-class.Rd b/man/teal_data-class.Rd index d35268e77..707029e66 100644 --- a/man/teal_data-class.Rd +++ b/man/teal_data-class.Rd @@ -18,25 +18,30 @@ If errors are raised, a \code{qenv.error} object is returned. \section{Slots}{ \describe{ -\item{\code{env}}{(\code{environment}) environment containing data sets and possibly auxiliary variables. -Access variables with \code{\link[=get_var]{get_var()}} or [\code{[[}]. -No setter provided. Evaluate code to add variables into \verb{@env}.} +\item{\code{.xData}}{(\code{environment}) environment containing data sets and possibly +auxiliary variables. +Access variables with \code{\link[=get]{get()}}, \code{\link{$}}, \code{\link[=get_var]{get_var()}} or [\code{[[}]. +No setter provided. Evaluate code to add variables into \verb{@.xData}.} -\item{\code{code}}{(\code{character}) vector representing code necessary to reproduce the contents of \verb{@env}. +\item{\code{code}}{(\code{character}) vector representing code necessary to reproduce the +contents of \verb{@.xData}. Access with \code{\link[=get_code]{get_code()}}. No setter provided. Evaluate code to append code to the slot.} -\item{\code{id}}{(\code{integer}) random identifier assigned to each element of \verb{@code}. Used internally.} +\item{\code{id}}{(\code{integer}) random identifier assigned to each element of \verb{@code}. +Used internally.} \item{\code{warnings}}{(\code{character}) vector of warnings raised when evaluating code. Access with \code{\link[=get_warnings]{get_warnings()}}.} \item{\code{messages}}{(\code{character}) vector of messages raised when evaluating code.} -\item{\code{join_keys}}{(\code{join_keys}) object specifying joining keys for data sets in \verb{@env}. +\item{\code{join_keys}}{(\code{join_keys}) object specifying joining keys for data sets in +\verb{@.xData}. Access or modify with \code{\link[=join_keys]{join_keys()}}.} -\item{\code{verified}}{(\code{logical(1)}) flag signifying that code in \verb{@code} has been proven to yield contents of \verb{@env}. +\item{\code{verified}}{(\code{logical(1)}) flag signifying that code in \verb{@code} has been +proven to yield contents of \verb{@.xData}. Used internally. See \code{\link[=verify]{verify()}} for more details.} }} diff --git a/man/verify.Rd b/man/verify.Rd index 630a08788..d3f7dcd77 100644 --- a/man/verify.Rd +++ b/man/verify.Rd @@ -18,10 +18,12 @@ Input \code{teal_data} object or error. Checks whether code in \code{teal_data} object reproduces the stored objects. } \details{ -If objects created by code in the \verb{@code} slot of \code{x} are \code{all_equal} to the contents of the \verb{@env} slot, +If objects created by code in the \verb{@code} slot of \code{x} are \code{all_equal} to the +contents of the \verb{@.xData} slot, the function updates the \verb{@verified} slot to \code{TRUE} in the returned \code{teal_data} object. Once verified, the slot will always be set to \code{TRUE}. -If the \verb{@code} fails to recreate objects in \code{teal_data@env}, an error is raised. +If the \verb{@code} fails to recreate objects in \code{teal_data}'s environment, an +error is raised. } \examples{ tdata1 <- teal_data() diff --git a/tests/testthat/test-teal_data.R b/tests/testthat/test-teal_data.R index e5d7ab895..a7d715d3e 100644 --- a/tests/testthat/test-teal_data.R +++ b/tests/testthat/test-teal_data.R @@ -85,9 +85,9 @@ testthat::test_that("teal_data code is concatenated into single string", { ) }) -testthat::test_that("teal_data@env is locked. Not able to modify, add or remove bindings", { +testthat::test_that("teal_data@.xData is locked. Not able to modify, add or remove bindings", { data <- teal_data(iris = iris) - testthat::expect_error(data@env$iris <- iris, "cannot change value of locked binding for 'iris'") - testthat::expect_error(data@env$iris2 <- iris, "cannot add bindings to a locked environment") - testthat::expect_error(rm("iris", envir = data@env), "cannot remove bindings from a locked environment") + testthat::expect_error(data@.xData$iris <- iris, "cannot change value of locked binding for 'iris'") + testthat::expect_error(data@.xData$iris2 <- iris, "cannot add bindings to a locked environment") + testthat::expect_error(rm("iris", envir = data@.xData), "cannot remove bindings from a locked environment") }) diff --git a/tests/testthat/test-datanames.R b/tests/testthat/test-test_data-names.R similarity index 71% rename from tests/testthat/test-datanames.R rename to tests/testthat/test-test_data-names.R index 22e169fba..5db8d9d14 100644 --- a/tests/testthat/test-datanames.R +++ b/tests/testthat/test-test_data-names.R @@ -11,18 +11,11 @@ testthat::test_that("variables with dot prefix are omitted", { }) # set --- -testthat::describe("names<- called on teal_data", { - testthat::it("throws warning", { - td <- teal_data(i = iris, m = mtcars) - testthat::expect_warning(names(td) <- c("a", "b", "c"), "assignment does nothing for qenv objects") - }) - - testthat::it("does not change it", { - td <- teal_data(i = iris, m = mtcars) - tdc <- td <- teal_data(i = iris, m = mtcars) - suppressWarnings(names(td) <- c("a", "b", "c")) - testthat::expect_identical(qe, qec) - }) +testthat::test_that("names<- called on teal_data does not change it", { + td <- teal_data(i = iris, m = mtcars) + tdc <- td <- teal_data(i = iris, m = mtcars) + suppressWarnings(names(td) <- c("a", "b", "c")) + testthat::expect_identical(td, tdc) }) # qenv.error support ---- @@ -31,23 +24,6 @@ testthat::test_that("names supports qenv.error class", { testthat::expect_no_error(names(qe)) }) -testthat::test_that("names called on qenv.error returns NULL", { - qe <- within(teal_data(), stop()) - testthat::expect_null(names(qe)) -}) - -testthat::describe("names<- called on qenv.error", { - testthat::it("throws warning", { - qe <- within(teal_data(), stop()) - testthat::expect_warning(names(qe) <- c("a", "b", "c"), "assignment does nothing for qenv.error objects") - }) - testthat::test_that("does not change qenv.error", { - qe <- within(teal_data(), stop()) - qec <- within(teal_data(), stop()) - suppressWarnings(names(qe) <- c("a", "b", "c")) - testthat::expect_identical(qe, qec) - }) -}) # topological_order ---- @@ -124,10 +100,7 @@ testthat::test_that("names return parent if join_keys were provided and parent e join_keys(data) <- default_cdisc_join_keys[c("ADSL", "ADTTE")] names(join_keys(data)) <- c(".ADSL", "ADTTE") - testthat::expect_identical( - names(data), - c("ADSL", "ADTTE", "iris") - ) + testthat::expect_setequal(names(data), c(".ADSL", "ADTTE", "iris")) }) testthat::test_that("names do not return parent if join_keys were provided and parent did not exists in env", { @@ -135,11 +108,6 @@ testthat::test_that("names do not return parent if join_keys were provided and p ADTTE = teal.data::rADTTE, # nolint: object_name. iris = iris ) - join_keys(data) <- default_cdisc_join_keys[c("ADSL", "ADTTE")] - - testthat::expect_identical( - names(data), - c("ADTTE", "iris") - ) + testthat::expect_setequal(names(data), c("ADTTE", "iris")) }) diff --git a/tests/testthat/test-verify.R b/tests/testthat/test-verify.R index a2b45a7bb..4e15fb696 100644 --- a/tests/testthat/test-verify.R +++ b/tests/testthat/test-verify.R @@ -17,7 +17,7 @@ testthat::test_that("verify returns the same object with changed @verified field testthat::expect_identical(tdata2@verified, FALSE) testthat::expect_identical(tdata2_ver@verified, TRUE) testthat::expect_identical(tdata2_ver@code, tdata2@code) - testthat::expect_identical(tdata2_ver@env, tdata2@env) + testthat::expect_identical(teal.code::get_env(tdata2_ver), teal.code::get_env(tdata2)) }) testthat::test_that("verify raises error if @code does not restore objects in @env", { From 4f9246730cc7327f61b519a845a4ad2a9978e9e4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Ver=C3=ADssimo?= <211358+averissimo@users.noreply.github.com> Date: Fri, 1 Nov 2024 14:57:15 +0000 Subject: [PATCH 05/13] fix: use names instead of ls --- R/teal_data-names.R | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/R/teal_data-names.R b/R/teal_data-names.R index 2da0b187e..bae379f62 100644 --- a/R/teal_data-names.R +++ b/R/teal_data-names.R @@ -21,7 +21,7 @@ #' #' @export names.teal_data <- function(x) { - names_x <- ls(x) + names_x <- names(as.environment(x)) .get_sorted_names(names_x, join_keys(x), as.environment(x)) } From d35fcca1deb428d454f3df79cd32a9ac4f35889b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Ver=C3=ADssimo?= <211358+averissimo@users.noreply.github.com> Date: Mon, 4 Nov 2024 14:12:52 +0000 Subject: [PATCH 06/13] fix: names return sorted strings and adds github prefix to teal.code --- .pre-commit-config.yaml | 2 +- R/teal_data-names.R | 4 +++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index ccfcc1c64..d67687526 100755 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -20,7 +20,7 @@ repos: - methods - rlang - stats - - teal.code + - insightsengineering/teal.code - utils - yaml - id: spell-check diff --git a/R/teal_data-names.R b/R/teal_data-names.R index bae379f62..6504be8e2 100644 --- a/R/teal_data-names.R +++ b/R/teal_data-names.R @@ -21,7 +21,9 @@ #' #' @export names.teal_data <- function(x) { - names_x <- names(as.environment(x)) + # Sorting can be safely done as environments don't have any order + # nor support numeric-index subsetting + names_x <- sort(names(as.environment(x))) .get_sorted_names(names_x, join_keys(x), as.environment(x)) } From 711a7e9e643927eab46904d8f9324b9940d7a0e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Ver=C3=ADssimo?= <211358+averissimo@users.noreply.github.com> Date: Mon, 4 Nov 2024 18:21:18 +0000 Subject: [PATCH 07/13] feat: exclude dot prefixed names from teal.data --- R/teal_data-names.R | 23 +++++++++-------------- man/names.teal_data.Rd | 10 +++++----- 2 files changed, 14 insertions(+), 19 deletions(-) diff --git a/R/teal_data-names.R b/R/teal_data-names.R index 6504be8e2..8f234538c 100644 --- a/R/teal_data-names.R +++ b/R/teal_data-names.R @@ -1,11 +1,11 @@ #' Names of data sets in `teal_data` object #' #' Functions to get the names of a `teal_data` object. -#' The names are extrapolated from the objects in the `qenv` environment and -#' are not stored statically, unlike the normal behavior of `names()` function. +#' The names are obtained from the objects listed in the `qenv` environment. #' -#' Objects named with a `.` (dot) prefix will be ignored and not returned, -#' unless `all.names` parameter is set to `TRUE`. +#' Objects named with a `.` (dot) prefix will be ignored and not returned. +#' To get the names of all objects, use `ls(x, all.names = TRUE)`, however, it +#' will not group the names by the join_keys topological structure. #' #' @param x A (`teal_data`) object to access or modify. #' @@ -17,24 +17,19 @@ #' names(td) #' #' td <- within(td, .CO2 <- CO2) -#' names(td) +#' names(td) # '.CO2' will not be returned #' #' @export names.teal_data <- function(x) { - # Sorting can be safely done as environments don't have any order + # Sorting from `ls` can be safely done as environments don't have any order # nor support numeric-index subsetting - names_x <- sort(names(as.environment(x))) - .get_sorted_names(names_x, join_keys(x), as.environment(x)) + envir <- as.environment(x) + .get_sorted_names(ls(envir = envir), join_keys(x), envir) } #' @keywords internal .get_sorted_names <- function(datanames, join_keys, env) { - child_parent <- sapply( - datanames, - function(name) parent(join_keys, name), - USE.NAMES = TRUE, - simplify = FALSE - ) + child_parent <- sapply(datanames, parent, x = join_keys, USE.NAMES = TRUE, simplify = FALSE) union( intersect(unlist(topological_sort(child_parent)), ls(env, all.names = TRUE)), diff --git a/man/names.teal_data.Rd b/man/names.teal_data.Rd index 06fa3179a..4f03fce70 100644 --- a/man/names.teal_data.Rd +++ b/man/names.teal_data.Rd @@ -14,12 +14,12 @@ A character vector of names. } \description{ Functions to get the names of a \code{teal_data} object. -The names are extrapolated from the objects in the \code{qenv} environment and -are not stored statically, unlike the normal behavior of \code{names()} function. +The names are obtained from the objects listed in the \code{qenv} environment. } \details{ -Objects named with a \code{.} (dot) prefix will be ignored and not returned, -unless \code{all.names} parameter is set to \code{TRUE}. +Objects named with a \code{.} (dot) prefix will be ignored and not returned. +To get the names of all objects, use \code{ls(x, all.names = TRUE)}, however, it +will not group the names by the join_keys topological structure. } \examples{ td <- teal_data(iris = iris) @@ -27,6 +27,6 @@ td <- within(td, mtcars <- mtcars) names(td) td <- within(td, .CO2 <- CO2) -names(td) +names(td) # '.CO2' will not be returned } From cba8ac7f0d6fa196a75f9369f772f376bd2a409e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Ver=C3=ADssimo?= <211358+averissimo@users.noreply.github.com> Date: Mon, 4 Nov 2024 20:38:35 +0000 Subject: [PATCH 08/13] fix: pkgdown and adds custom length that only shows non-dot prefixed objects --- NAMESPACE | 1 + R/teal_data-names.R | 3 +++ _pkgdown.yml | 1 + 3 files changed, 5 insertions(+) diff --git a/NAMESPACE b/NAMESPACE index 49a6f08bb..a126ccc47 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -15,6 +15,7 @@ S3method(format,join_keys) S3method(join_keys,default) S3method(join_keys,join_keys) S3method(join_keys,teal_data) +S3method(length,teal.data) S3method(names,teal_data) S3method(parents,join_keys) S3method(parents,teal_data) diff --git a/R/teal_data-names.R b/R/teal_data-names.R index 8f234538c..32e9d71de 100644 --- a/R/teal_data-names.R +++ b/R/teal_data-names.R @@ -27,6 +27,9 @@ names.teal_data <- function(x) { .get_sorted_names(ls(envir = envir), join_keys(x), envir) } +#' @export +length.teal.data <- function(x) length(ls(x)) + #' @keywords internal .get_sorted_names <- function(datanames, join_keys, env) { child_parent <- sapply(datanames, parent, x = join_keys, USE.NAMES = TRUE, simplify = FALSE) diff --git a/_pkgdown.yml b/_pkgdown.yml index 2ecf65392..cc6bbb0c3 100644 --- a/_pkgdown.yml +++ b/_pkgdown.yml @@ -41,6 +41,7 @@ reference: - join_key - join_keys - join_keys<- + - names.teal_data - names<-.join_keys - parents - parents<- From 33de31f375f8c93048f95cbd087d12c56d06467c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Ver=C3=ADssimo?= <211358+averissimo@users.noreply.github.com> Date: Tue, 5 Nov 2024 17:39:14 +0000 Subject: [PATCH 09/13] chore: bumps versions --- DESCRIPTION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DESCRIPTION b/DESCRIPTION index 8fa36bb3c..45ffa7c97 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -29,7 +29,7 @@ URL: https://insightsengineering.github.io/teal.data/, BugReports: https://github.com/insightsengineering/teal.data/issues Depends: R (>= 4.0), - teal.code (>= 0.5.0.9011) + teal.code (>= 0.5.0.9012) Imports: checkmate (>= 2.1.0), lifecycle (>= 0.2.0), From 64f16da15e529983632929b6fec62f7ae77881e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Ver=C3=ADssimo?= <211358+averissimo@users.noreply.github.com> Date: Wed, 6 Nov 2024 16:19:55 +0100 Subject: [PATCH 10/13] Update .pre-commit-config.yaml MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Dawid Kałędkowski Signed-off-by: André Veríssimo <211358+averissimo@users.noreply.github.com> --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index d67687526..ccfcc1c64 100755 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -20,7 +20,7 @@ repos: - methods - rlang - stats - - insightsengineering/teal.code + - teal.code - utils - yaml - id: spell-check From 583b145b7f2b7b7c8f7e035cdf581c8f611c08a3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Ver=C3=ADssimo?= <211358+averissimo@users.noreply.github.com> Date: Wed, 6 Nov 2024 18:43:29 +0000 Subject: [PATCH 11/13] feat: move code/id/warn/msg logic to teal.code and simplify --- R/teal_data-class.R | 59 ++++++++++++++++-------------------------- R/teal_data-get_code.R | 2 +- R/teal_data.R | 5 ++-- R/verify.R | 2 +- man/get_code.Rd | 2 +- man/new_teal_data.Rd | 20 -------------- man/verify.Rd | 2 +- 7 files changed, 29 insertions(+), 63 deletions(-) delete mode 100644 man/new_teal_data.Rd diff --git a/R/teal_data-class.R b/R/teal_data-class.R index a5ddb439a..80e97b7f6 100644 --- a/R/teal_data-class.R +++ b/R/teal_data-class.R @@ -46,44 +46,29 @@ setClass( ) ) -#' Initialize `teal_data` object +#' It initializes the `teal_data` class #' -#' @name new_teal_data -#' -#' @param data (`named list`) of data objects. -#' @param code (`character` or `language`) code to reproduce the `data`. -#' Accepts and stores comments also. -#' @param join_keys (`join_keys`) object -#' @rdname new_teal_data -#' @keywords internal -new_teal_data <- function(data, code = character(0), join_keys = join_keys()) { - checkmate::assert_list(data) - checkmate::assert_class(join_keys, "join_keys") - if (!any(is.language(code), is.character(code))) { - stop("`code` must be a character or language object.") - } +#' Accepts .xData as a list and converts it to an environment before initializing +#' parent constructor (`qenv`). +#' @noRd +setMethod( + "initialize", + "teal_data", + function(.Object, .xData = list(), join_keys = join_keys(), ...) { # nolint: object_name. + # Allow .xData to be a list and convert it to an environment + if (!missing(.xData) && inherits(.xData, "list")) { + .xData <- rlang::env_clone(list2env(.xData), parent = parent.env(.GlobalEnv)) + lockEnvironment(.xData, bindings = TRUE) + } + checkmate::assert_environment(.xData) - if (is.language(code)) { - code <- paste(lang2calls(code), collapse = "\n") - } - if (length(code)) { - code <- paste(code, collapse = "\n") - } - verified <- (length(code) == 0L && length(data) == 0L) + .Object <- methods::callNextMethod(.Object, .xData, join_keys = join_keys, ...) # nolint: object_name. - id <- sample.int(.Machine$integer.max, size = length(code)) + # teal data specific slots + checkmate::assert_class(join_keys, "join_keys") + .Object@verified <- (length(.Object@code) == 0L && length(.Object@.xData) == 0L) + .Object@join_keys <- join_keys - new_env <- rlang::env_clone(list2env(data), parent = parent.env(.GlobalEnv)) - lockEnvironment(new_env, bindings = TRUE) - - methods::new( - "teal_data", - .xData = new_env, - code = code, - warnings = rep("", length(code)), - messages = rep("", length(code)), - id = id, - join_keys = join_keys, - verified = verified - ) -} + .Object + } +) diff --git a/R/teal_data-get_code.R b/R/teal_data-get_code.R index d1292c7a5..23002590d 100644 --- a/R/teal_data-get_code.R +++ b/R/teal_data-get_code.R @@ -3,7 +3,7 @@ #' Retrieve code from `teal_data` object. #' #' Retrieve code stored in `@code`, which (in principle) can be used to recreate -#' all objects found in `@.xData`. +#' all objects found in the environment (`@.xData`). #' Use `names` to limit the code to one or more of the datasets enumerated in #' the environment. #' diff --git a/R/teal_data.R b/R/teal_data.R index ea32e624a..1721c94fe 100644 --- a/R/teal_data.R +++ b/R/teal_data.R @@ -60,8 +60,9 @@ teal_data <- function(..., if (length(data_objects) > 0 && !checkmate::test_names(names(data_objects), type = "named")) { stop("Dot (`...`) arguments on `teal_data()` must be named.") } - new_teal_data( - data = data_objects, + methods::new( + "teal_data", + .xData = data_objects, code = code, join_keys = join_keys ) diff --git a/R/verify.R b/R/verify.R index df40e91bd..a3c1f24fe 100644 --- a/R/verify.R +++ b/R/verify.R @@ -3,7 +3,7 @@ #' Checks whether code in `teal_data` object reproduces the stored objects. #' #' If objects created by code in the `@code` slot of `x` are `all_equal` to the -#' contents of the `@.xData` slot, +#' contents of the environment (`@.xData` slot), #' the function updates the `@verified` slot to `TRUE` in the returned `teal_data` object. #' Once verified, the slot will always be set to `TRUE`. #' If the `@code` fails to recreate objects in `teal_data`'s environment, an diff --git a/man/get_code.Rd b/man/get_code.Rd index 38bcaf41a..3d3b8cf25 100644 --- a/man/get_code.Rd +++ b/man/get_code.Rd @@ -37,7 +37,7 @@ Retrieve code from \code{teal_data} object. } \details{ Retrieve code stored in \verb{@code}, which (in principle) can be used to recreate -all objects found in \verb{@.xData}. +all objects found in the environment (\verb{@.xData}). Use \code{names} to limit the code to one or more of the datasets enumerated in the environment. } diff --git a/man/new_teal_data.Rd b/man/new_teal_data.Rd deleted file mode 100644 index 2bdd63ee9..000000000 --- a/man/new_teal_data.Rd +++ /dev/null @@ -1,20 +0,0 @@ -% Generated by roxygen2: do not edit by hand -% Please edit documentation in R/teal_data-class.R -\name{new_teal_data} -\alias{new_teal_data} -\title{Initialize \code{teal_data} object} -\usage{ -new_teal_data(data, code = character(0), join_keys = join_keys()) -} -\arguments{ -\item{data}{(\verb{named list}) of data objects.} - -\item{code}{(\code{character} or \code{language}) code to reproduce the \code{data}. -Accepts and stores comments also.} - -\item{join_keys}{(\code{join_keys}) object} -} -\description{ -Initialize \code{teal_data} object -} -\keyword{internal} diff --git a/man/verify.Rd b/man/verify.Rd index d3f7dcd77..7b71ce489 100644 --- a/man/verify.Rd +++ b/man/verify.Rd @@ -19,7 +19,7 @@ Checks whether code in \code{teal_data} object reproduces the stored objects. } \details{ If objects created by code in the \verb{@code} slot of \code{x} are \code{all_equal} to the -contents of the \verb{@.xData} slot, +contents of the environment (\verb{@.xData} slot), the function updates the \verb{@verified} slot to \code{TRUE} in the returned \code{teal_data} object. Once verified, the slot will always be set to \code{TRUE}. If the \verb{@code} fails to recreate objects in \code{teal_data}'s environment, an From 1c2862527b4c0e056d7398e63b4ce2df744230da Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Ver=C3=ADssimo?= <211358+averissimo@users.noreply.github.com> Date: Wed, 6 Nov 2024 19:02:32 +0000 Subject: [PATCH 12/13] chore: fix lint error --- R/teal_data-class.R | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/R/teal_data-class.R b/R/teal_data-class.R index 80e97b7f6..2bfb2ca8a 100644 --- a/R/teal_data-class.R +++ b/R/teal_data-class.R @@ -57,7 +57,7 @@ setMethod( function(.Object, .xData = list(), join_keys = join_keys(), ...) { # nolint: object_name. # Allow .xData to be a list and convert it to an environment if (!missing(.xData) && inherits(.xData, "list")) { - .xData <- rlang::env_clone(list2env(.xData), parent = parent.env(.GlobalEnv)) + .xData <- rlang::env_clone(list2env(.xData), parent = parent.env(.GlobalEnv)) # nolint: object_name. lockEnvironment(.xData, bindings = TRUE) } checkmate::assert_environment(.xData) @@ -66,8 +66,8 @@ setMethod( # teal data specific slots checkmate::assert_class(join_keys, "join_keys") - .Object@verified <- (length(.Object@code) == 0L && length(.Object@.xData) == 0L) - .Object@join_keys <- join_keys + .Object@verified <- (length(.Object@code) == 0L && length(.Object@.xData) == 0L) # nolint: object_name. + .Object@join_keys <- join_keys # nolint: object_name. .Object } From 04fd26ef3da92e5258b0b2cd080fee879a275de3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Andr=C3=A9=20Ver=C3=ADssimo?= <211358+averissimo@users.noreply.github.com> Date: Thu, 7 Nov 2024 10:09:14 +0000 Subject: [PATCH 13/13] pr: apply suggestion by @gogonzo --- R/teal_data-class.R | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/R/teal_data-class.R b/R/teal_data-class.R index 2bfb2ca8a..aea827319 100644 --- a/R/teal_data-class.R +++ b/R/teal_data-class.R @@ -60,15 +60,16 @@ setMethod( .xData <- rlang::env_clone(list2env(.xData), parent = parent.env(.GlobalEnv)) # nolint: object_name. lockEnvironment(.xData, bindings = TRUE) } + args <- list(...) checkmate::assert_environment(.xData) - - .Object <- methods::callNextMethod(.Object, .xData, join_keys = join_keys, ...) # nolint: object_name. - - # teal data specific slots checkmate::assert_class(join_keys, "join_keys") - .Object@verified <- (length(.Object@code) == 0L && length(.Object@.xData) == 0L) # nolint: object_name. - .Object@join_keys <- join_keys # nolint: object_name. - - .Object + checkmate::assert_list(args, names = "named") + methods::callNextMethod( + .Object, + .xData, + join_keys = join_keys, + verified = (length(args$code) == 0L && length(.xData) == 0L), + ... + ) } )