Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

datanames in vignettes #239

Open
wants to merge 22 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ repos:
name: Regenerate package documentation
additional_dependencies:
- checkmate
- cli
- grDevices
- lifecycle
- methods
Expand Down
4 changes: 2 additions & 2 deletions DESCRIPTION
Original file line number Diff line number Diff line change
Expand Up @@ -28,13 +28,13 @@ Depends:
R (>= 4.0)
Imports:
checkmate (>= 2.1.0),
cli (>= 3.4.0),
averissimo marked this conversation as resolved.
Show resolved Hide resolved
grDevices,
lifecycle (>= 0.2.0),
rlang (>= 1.1.0),
stats,
utils
Suggests:
cli (>= 3.4.0),
knitr (>= 1.42),
rmarkdown (>= 2.23),
shiny (>= 1.6.0),
Expand All @@ -45,7 +45,7 @@ VignetteBuilder:
rmarkdown
RdMacros:
lifecycle
Config/Needs/verdepcheck: mllg/checkmate, r-lib/lifecycle, r-lib/rlang,
Config/Needs/verdepcheck: mllg/checkmate, r-lib/cli, r-lib/lifecycle, r-lib/rlang,
r-lib/cli, yihui/knitr, rstudio/rmarkdown, rstudio/shiny,
r-lib/testthat, r-lib/withr
Config/Needs/website: insightsengineering/nesttemplate
Expand Down
38 changes: 24 additions & 14 deletions R/qenv-constructor.R
Original file line number Diff line number Diff line change
@@ -1,28 +1,38 @@
#' Code tracking with `qenv` object
#' Instantiates a `qenv` environment
#'
#' @description
#' `r badge("stable")`
#'
#' Create a `qenv` object and evaluate code in it to track code history.
#'
#' @param names (`character`) for `x[names]`, names of objects included in `qenv` to subset. Names not present in `qenv`
#' are skipped. For `get_code` `r lifecycle::badge("experimental")` vector of object names to return the code for.
#' For more details see the "Extracting dataset-specific code" section.
#' Instantiates a `qenv` environment.
#'
#' @details
#'
#' `qenv()` instantiates a `qenv` with an empty environment.
#' Any changes must be made by evaluating code in it with `eval_code` or `within`, thereby ensuring reproducibility.
#' `qenv` class has following characteristics:
#'
#' - It inherits from the environment and methods such as [`$`], [get()], [ls()], [as.list()],
#' [parent.env()] work out of the box.
#' - `qenv` is a locked environment, and data modification is only possible through the [eval_code()]
#' and [within.qenv()] functions.
#' - It stores metadata about the code used to create the data (see [get_code()]).
#' - It supports slicing (see [`subset-qenv`])
#' - It is immutable which means that each code evaluation does not modify the original `qenv`
#' environment directly. See the following code:
#'
#' ```
#' q1 <- qenv()
#' q2 <- eval_code(q1, "a <- 1")
#' identical(q1, q2) # FALSE
#' ```
#'
#' @name qenv
#'
#' @return `qenv` returns a `qenv` object.
#' @return `qenv` environment.
#'
#' @seealso [`base::within()`], [`get_var()`], [`get_env()`], [`get_warnings()`], [`join()`], [`concat()`]
#' @seealso [eval_code()], [get_var()], [`subset-qenv`], [get_env()],[get_warnings()], [join()], [concat()]
#' @examples
#' # create empty qenv
#' qenv()
#'
#' q <- qenv()
#' q2 <- within(q, a <- 1)
#' ls(q2)
#' q2$a
#' @export
qenv <- function() {
methods::new("qenv")
Expand Down
5 changes: 2 additions & 3 deletions R/qenv-eval_code.R
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#' Evaluate code in `qenv`
#'
#' @details
#'
#' `eval_code()` evaluates given code in the `qenv` environment and appends it to the `code` slot.
#' Thus, if the `qenv` had been instantiated empty, contents of the environment are always a result of the stored code.
#'
Expand All @@ -10,7 +11,7 @@
#' `expression` being a result of `parse(keep.source = TRUE)`.
#'
#' @return
#' `eval_code` returns a `qenv` object with `expr` evaluated or `qenv.error` if evaluation fails.
#' `qenv` environment with `code/expr` evaluated or `qenv.error` if evaluation fails.
#'
#' @examples
#' # evaluate code in qenv
Expand All @@ -20,8 +21,6 @@
#' q <- eval_code(q, quote(library(checkmate)))
#' q <- eval_code(q, expression(assert_number(a)))
#'
#' @name eval_code
#' @rdname qenv
#' @aliases eval_code,qenv,character-method
#' @aliases eval_code,qenv,language-method
#' @aliases eval_code,qenv,expression-method
Expand Down
15 changes: 8 additions & 7 deletions R/qenv-extract.R
Original file line number Diff line number Diff line change
@@ -1,20 +1,21 @@
#' Subsets `qenv`
#'
#' @section Subsetting:
#' `x[names]` subsets objects in `qenv` environment and limit the code to the necessary needed to build limited objects.
#' `...` passes parameters to further methods.
#' @description
#' Subsets [`qenv`] environment and limits the code to the necessary needed to build limited objects.
#'
#' @param x (`qenv`)
#' @param names (`character`) names of objects included in [`qenv`] to subset. Names not present in [`qenv`]
#' are skipped.
#' @param ... internal usage, please ignore.
#'
#' @examples
#' @name subset-qenv
#'
#' # Subsetting
#' @examples
#' q <- qenv()
#' q <- eval_code(q, "a <- 1;b<-2")
#' q["a"]
#' q[c("a", "b")]
#'
#' @rdname qenv
#'
#' @export
`[.qenv` <- function(x, names, ...) {
checkmate::assert_character(names, any.missing = FALSE)
Expand Down
40 changes: 8 additions & 32 deletions R/qenv-get_code.R
Original file line number Diff line number Diff line change
@@ -1,39 +1,17 @@
#' @name qenv-inheritted
#' @rdname qenv
#'
#' @details
#'
#' `x[[name]]`, `x$name` and `get(name, x)` are generic \R operators to access the objects in the environment.
#' See [`[[`] for more details.
#' `names(x)` calls on the `qenv` object and will list all objects in the environment.
#'
#' @return `[[`, `$` and `get` return the value of the object named `name` in the `qenv` object.
#' @return `names` return a character vector of all the names of the objects in the `qenv` object.
#' @return `ls` return a character vector of the names of the objects in the `qenv` object.
#' It will only show the objects that are not named with a dot prefix, unless
#' the `all.names = TRUE`, which will show all objects.
#'
#' @examples
#' # Extract objects from qenv
#' q[["a"]]
#' q$a
#'
#' # list objects in qenv
#' names(q)
NULL

#' Get code from `qenv`
#'
#' @details
#' `get_code()` retrieves the code stored in the `qenv`. `...` passes arguments to methods.
#' @description
#' Retrieves the code stored in the `qenv`.
#'
#' @param object (`qenv`)
#' @param deparse (`logical(1)`) flag specifying whether to return code as `character` or `expression`.
#' @param ... see `Details`
#'
#' @param ... internal usage, please ignore.
#' @param names (`character`) `r lifecycle::badge("experimental")` vector of object names to return the code for.
#' For more details see the "Extracting dataset-specific code" section.
#'
#' @section Extracting dataset-specific code:
#' When `names` for `get_code` is specified, the code returned will be limited to the lines needed to _create_
#'
#' `get_code(object, names)` limits the returned code to contain only those lines needed to _create_
#' the requested objects. The code stored in the `qenv` is analyzed statically to determine
#' which lines the objects of interest depend upon. The analysis works well when objects are created
#' with standard infix assignment operators (see `?assignOps`) but it can fail in some situations.
Expand Down Expand Up @@ -98,7 +76,7 @@ NULL
#' - creating and evaluating language objects, _e.g._ `eval(<call>)`
#'
#' @return
#' `get_code` returns the traced code in the form specified by `deparse`.
#' The code used in the `qenv` in the form specified by `deparse`.
#'
#' @examples
#' # retrieve code
Expand All @@ -114,8 +92,6 @@ NULL
#' q <- eval_code(q, code = c("a <- 1", "b <- 2"))
#' get_code(q, names = "a")
#'
#' @name get_code
#' @rdname qenv
#' @aliases get_code,qenv-method
#' @aliases get_code,qenv.error-method
#'
Expand Down
7 changes: 3 additions & 4 deletions R/qenv-get_var.R
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
#' Get object from `qenv`
#'
#' @description
#' `r lifecycle::badge("deprecated")` by native \R operators/functions:
#' `x[[name]]`, `x$name` or [get()].
#' `r lifecycle::badge("deprecated")`
#' Instead of [get_var()] use native \R operators/functions:
#' `x[[name]]`, `x$name` or [get()]:
#'
#' Retrieve variables from the `qenv` environment.
#'
Expand All @@ -17,8 +18,6 @@
#' q2 <- eval_code(q1, code = "b <- a")
#' get_var(q2, "b")
#'
#' @name get_var
#' @rdname get_var
#' @aliases get_var,qenv,character-method
#' @aliases get_var,qenv.error,ANY-method
#'
Expand Down
33 changes: 32 additions & 1 deletion R/qenv-show.R
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,36 @@
#' @importFrom methods show
#' @export
setMethod("show", "qenv", function(object) {
rlang::env_print([email protected])
env <- get_env(object)
header <- cli::col_blue(sprintf("<environment: %s>", rlang::env_label(env)))
parent <- sprintf("Parent: <environment: %s>", rlang::env_label(rlang::env_parent(env)))
cat(cli::style_bold(header), "\U1F512", "\n")
cat(parent, "\n")

shown <- ls(object)
gogonzo marked this conversation as resolved.
Show resolved Hide resolved
if (length(shown > 0L)) cat(cli::style_bold("Bindings:\n"))
lapply(shown, function(x) {
averissimo marked this conversation as resolved.
Show resolved Hide resolved
cat(
sprintf(
"- %s: [%s]\n",
deparse(rlang::sym(x), backtick = TRUE),
class(object[[x]])[1]
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

WDYT about using pillar::type_sum to get the class type?

We would use the same naming as tidyverse and it would get some extra specificity/weird cases (numeric -> dbl, rlang::missing_arg/symbol/quote/name and I'm sure some others)

The loss here would be shorter names and an extra dependency just for the show.qenv method

(same to be applied to hidden class below)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not a fan of changing original class names neither using extra dependency for it

)
)
})

hidden <- setdiff(ls(object, all.names = TRUE), shown)
lapply(hidden, function(x) {
cat(
cli::style_blurred(
sprintf(
"- %s: [%s]\n",
deparse(rlang::sym(x), backtick = TRUE),
class(object[[x]])[1]
)
)
)
})

invisible(object)
})
18 changes: 6 additions & 12 deletions R/qenv-within.R
Original file line number Diff line number Diff line change
@@ -1,22 +1,16 @@
#' Evaluate Expression in `qenv`
#'
#' @details
#' `within()` is a convenience function for evaluating inline code inside the environment of a `qenv`.
#' It is a method for the `base` generic that wraps `eval_code` to provide a simplified way of passing code.
#' `within` accepts only inline expressions (both simple and compound) and allows for injecting values into `expr`
#' through the `...` argument:
#' as `name:value` pairs are passed to `...`, `name` in `expr` will be replaced with `value`.
#' `within()` is a convenience method that wraps `eval_code` to provide a simplified way of passing expression.
#' `within` accepts only inline expressions (both simple and compound) and allows to substitute `expr`
#' with `...` named argument values.
#'
#' @section Using language objects with `within`:
#' Passing language objects to `expr` is generally not intended but can be achieved with `do.call`.
#' Only single `expression`s will work and substitution is not available. See examples.
#'
#' @param data (`qenv`)
#' @param expr (`expression`) to evaluate. Must be inline code, see `Using language objects...`
#' @param ... see `Details`
#'
#' @return
#' `within` returns a `qenv` object with `expr` evaluated or `qenv.error` if evaluation fails.
#' @param ... named argument value will substitute a symbol in the `expr` matched by the name.
#' For practical usage see Examples section below.
#'
#' @examples
#' # evaluate code using within
Expand Down Expand Up @@ -49,7 +43,7 @@
#' within(q, exprlist) # fails
#' do.call(within, list(q, do.call(c, exprlist)))
#'
#' @rdname qenv
#' @rdname eval_code
#'
#' @export
#'
Expand Down
1 change: 1 addition & 0 deletions _pkgdown.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,4 +37,5 @@ reference:
- join
- qenv
- show,qenv-method
- subset-qenv
- within.qenv
88 changes: 88 additions & 0 deletions man/eval_code.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
Loading