Skip to content

Commit

Permalink
improve join docs (#92)
Browse files Browse the repository at this point in the history
closes #71 
move docs from check_joinable to join methods and improve documentation.
  • Loading branch information
donyunardi authored Nov 17, 2022
1 parent f9f8cf9 commit 49b13d2
Show file tree
Hide file tree
Showing 3 changed files with 221 additions and 23 deletions.
121 changes: 111 additions & 10 deletions R/qenv-join.R
Original file line number Diff line number Diff line change
@@ -1,12 +1,107 @@
#' Join two `qenv` objects
#'
#' Combine two `qenv` objects by merging their environments and the code.
#' Not all `qenv` objects can be combined:
#' - if their environments contains objects of the same name but not identical
#' - if `y` has unique code element placed before common element. This means that `y`
#' in the environment of the `y` was evaluated some extra code before which can influence
#' reproducibility
#' - more cases to be done
#' `join()` perform checks and merges two `qenv` objects into one `qenv` object.
#' Any common code at the start of the qenvs is only placed once at the start of the joined qenv.
#' This allows consistent behaviour when joining qenvs which share a common ancestor.
#' See below for an example.
#'
#' There are some situations where `join()` cannot be properly performed, such as these three scenarios:
#' \enumerate{
#' \item Both `qenv` objects contain an object of the same name but are not identical. \cr\cr
#' Example:
#' \preformatted{
#' x <- new_qenv(
#' code = c(mtcars1 = "mtcars1 <- mtcars"),
#' env = list2env(list(mtcars1 = mtcars))
#' )
#' y <- new_qenv(
#' code = c(mtcars1 = "mtcars1 <- mtcars['wt']"),
#' env = list2env(list(mtcars1 = mtcars['wt']))
#' )
#' z <- join(x, y)
#' # Error message will occur
#' }
#' In this example, `mtcars1` object exists in both `x` and `y` objects but the content are not identical.\cr
#' `mtcars1` in the `x qenv` object has more columns than `mtcars1` in the `y qenv` object (only has one column).
#' \item `join()` will look for identical `@id` values in both `qenv` objects.
#' The index position of these `@id`s must be the same to determine the evaluation order.
#' Otherwise, `join()` will throw an error message.\cr\cr
#' Example:
#' \preformatted{
#' common_q <- new_qenv(code = "v <- 1", env = list2env(list(v = 1)))
#' x <- eval_code(
#' common_q,
#' "x <- v"
#' )
#' y <- eval_code(
#' common_q,
#' "y <- v"
#' )
#' z <- eval_code(
#' y,
#' "z <- v"
#' )
#' q <- join(x, y)
#' join_q <- join(q, z)
#' # Error message will occur
#'
#' # Check the order of evaluation based on the id slot
#' shared_ids <- intersect(q@id, z@id)
#' match(shared_ids, q@id) # Output: 1 3
#' match(shared_ids, z@id) # Output: 1 2
#' }
#' The error occurs because the index position of identical `@id` between the two objects is not the same.
#' \item The usage of temporary variable in the code expression could cause `join()` to fail. \cr\cr
#' Example:
#' \preformatted{
#' common_q <- new_qenv()
#' x <- eval_code(
#' common_q,
#' "x <- numeric(0)
#' for (i in 1:2) {
#' x <- c(x, i)
#' }"
#' )
#' y <- eval_code(
#' common_q,
#' "y <- numeric(0)
#' for (i in 1:3) {
#' y <- c(y, i)
#' }"
#' )
#' q <- join(x,y)
#' # Error message will occur
#'
#' # Check the value of temporary variable i in both objects
#' x@env$i # Output: 2
#' y@env$i # Output: 3
#' }
#' `join()` fails to provide a proper result because of the temporary variable `i` exists in both objects but has different value.\cr
#' To fix this, we can set `i <- NULL` in the code expression for both objects.
#' \preformatted{
#' common_q <- new_qenv()
#' x <- eval_code(
#' common_q,
#' "x <- numeric(0)
#' for (i in 1:2) {
#' x <- c(x, i)
#' }
#' # dummy i variable to fix it
#' i <- NULL"
#' )
#' y <- eval_code(
#' common_q,
#' "y <- numeric(0)
#' for (i in 1:3) {
#' y <- c(y, i)
#' }
#' # dummy i variable to fix it
#' i <- NULL"
#' )
#' q <- join(x,y)
#' }
#' }
#'
#' @param x (`qenv`)
#' @param y (`qenv`)
#' @examples
Expand All @@ -22,6 +117,14 @@
#' q2 <- eval_code(q2, "mtcars2 <- mtcars")
#' qq <- join(q1, q2)
#' get_code(qq)
#'
#' common_q <- new_qenv(list2env(list(x = 1)), quote(x <- 1))
#' y_q <- eval_code(common_q, quote(y <- x * 2))
#' z_q <- eval_code(common_q, quote(z <- x * 3))
#' join_q <- join(y_q, z_q)
#' # get_code only has "x <- 1" occurring once
#' get_code(join_q)
#'
#' @export
setGeneric("join", function(x, y) {
standardGeneric("join")
Expand Down Expand Up @@ -64,9 +167,7 @@ setMethod("join", signature = c("qenv", "qenv.error"), function(x, y) {
#' If two `qenv` can be joined
#'
#' Checks if two `qenv` objects can be combined.
#' They can't be combined if (and):
#' - both share the same code (identified by `id`)
#' - indices of the shared code are not consecutive or don't start from 1
#' For more information, please see \code{\link{join}}
#' @param x (`qenv`)
#' @param y (`qenv`)
#' @return `TRUE` if able to join or `character` used to print error message.
Expand Down
6 changes: 1 addition & 5 deletions man/dot-check_joinable.Rd

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

117 changes: 109 additions & 8 deletions man/join.Rd

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

0 comments on commit 49b13d2

Please sign in to comment.