Skip to content

Commit c56a5ca

Browse files
committed
feat: expand on compatibility with an environment
1 parent ab9e342 commit c56a5ca

File tree

9 files changed

+93
-46
lines changed

9 files changed

+93
-46
lines changed

DESCRIPTION

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ Collate:
6363
'qenv-get_var.R'
6464
'qenv-get_warnings.R'
6565
'qenv-join.R'
66+
'qenv-length.R'
6667
'qenv-show.R'
6768
'qenv-within.R'
6869
'teal.code-package.R'

NAMESPACE

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
11
# Generated by roxygen2: do not edit by hand
22

33
S3method("$",qenv.error)
4-
S3method("$<-",qenv.error)
54
S3method("[[",qenv.error)
6-
S3method("[[<-",qenv.error)
5+
S3method(as.list,qenv.error)
6+
S3method(c,qenv)
7+
S3method(c,qenv.error)
8+
S3method(length,qenv)
9+
S3method(length,qenv.error)
710
S3method(within,qenv)
811
S3method(within,qenv.error)
912
export(concat)

R/qenv-class.R

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -20,14 +20,21 @@ setClass(
2020
warnings = "character",
2121
messages = "character"
2222
),
23-
contains = "environment",
24-
prototype = list(
25-
.xData = new.env(parent = parent.env(.GlobalEnv)),
26-
code = character(0),
27-
id = integer(0),
28-
warnings = character(0),
29-
messages = character(0)
30-
)
23+
contains = "environment"
24+
)
25+
26+
setMethod(
27+
"initialize",
28+
"qenv",
29+
function(.Object, .xData = new.env(parent = parent.env(.GlobalEnv)), ...) { # nolint: object_name.
30+
.Object <- callNextMethod(.Object, ...) # nolint: object_name.
31+
32+
checkmate::assert_environment(.xData)
33+
lockEnvironment(.xData)
34+
.Object@.xData <- .xData # nolint: object_name.
35+
36+
.Object
37+
}
3138
)
3239

3340
#' It takes a `qenv` class and returns `TRUE` if the input is valid

R/qenv-errors.R

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,10 @@
11
# needed to handle try-error
22
setOldClass("qenv.error")
3+
4+
#' @export
5+
as.list.qenv.error <- function(x, ...) {
6+
stop(errorCondition(
7+
list(message = conditionMessage(x)),
8+
class = c("validation", "try-error", "simpleError")
9+
))
10+
}

R/qenv-get_var.R

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -70,14 +70,3 @@ setMethod("[[", signature = c("qenv", "ANY"), function(x, i) {
7070
class = c("validation", "try-error", "simpleError")
7171
))
7272
}
73-
74-
#' @export
75-
`[[<-.qenv.error` <- function(x, name, value) {
76-
stop(errorCondition(
77-
list(message = conditionMessage(x)),
78-
class = c("validation", "try-error", "simpleError")
79-
))
80-
}
81-
82-
#' @export
83-
`$<-.qenv.error` <- `[[<-.qenv.error`

R/qenv-join.R

Lines changed: 46 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -136,30 +136,17 @@
136136
setGeneric("join", function(x, y) standardGeneric("join"))
137137

138138
setMethod("join", signature = c("qenv", "qenv"), function(x, y) {
139-
join_validation <- .check_joinable(x, y)
140-
141-
# join expressions
142-
if (!isTRUE(join_validation)) {
143-
stop(join_validation)
144-
}
145-
146-
id_unique <- !y@id %in% x@id
147-
x@id <- c(x@id, y@id[id_unique])
148-
x@code <- c(x@code, y@code[id_unique])
149-
x@warnings <- c(x@warnings, y@warnings[id_unique])
150-
x@messages <- c(x@messages, y@messages[id_unique])
151-
152-
# insert (and overwrite) objects from y to x
153-
x@.xData <- rlang::env_clone(x@.xData, parent = parent.env(.GlobalEnv))
154-
rlang::env_coalesce(env = x@.xData, from = y@.xData)
155-
x
139+
lifecycle::deprecate_soft("0.5.1", "join()", details = "Please use `c()` instead")
140+
c(x, y)
156141
})
157142

158143
setMethod("join", signature = c("qenv", "qenv.error"), function(x, y) {
144+
lifecycle::deprecate_soft("0.5.1", "join()", details = "Please use `c()` instead")
159145
y
160146
})
161147

162148
setMethod("join", signature = c("qenv.error", "ANY"), function(x, y) {
149+
lifecycle::deprecate_soft("0.5.1", "join()", details = "Please use `c()` instead")
163150
x
164151
})
165152

@@ -214,3 +201,45 @@ setMethod("join", signature = c("qenv.error", "ANY"), function(x, y) {
214201
)
215202
}
216203
}
204+
205+
#' @export
206+
c.qenv.error <- function(...) {
207+
rlang::list2(...)[[1]]
208+
}
209+
210+
#' @export
211+
c.qenv <- function(...) {
212+
dots <- rlang::list2(...)
213+
if (!checkmate::test_list(dots[-1], types = c("qenv", "qenv.error"))) {
214+
return(NextMethod(c, dots[[1]]))
215+
}
216+
217+
first_non_qenv_ix <- which.min(vapply(dots, inherits, what = "qenv", logical(1)))
218+
if (first_non_qenv_ix > 1) {
219+
return(dots[[first_non_qenv_ix]])
220+
}
221+
222+
Reduce(
223+
x = dots[-1],
224+
init = dots[[1]],
225+
f = function(x, y) {
226+
join_validation <- .check_joinable(x, y)
227+
228+
# join expressions
229+
if (!isTRUE(join_validation)) {
230+
stop(join_validation)
231+
}
232+
233+
id_unique <- !y@id %in% x@id
234+
x@id <- c(x@id, y@id[id_unique])
235+
x@code <- c(x@code, y@code[id_unique])
236+
x@warnings <- c(x@warnings, y@warnings[id_unique])
237+
x@messages <- c(x@messages, y@messages[id_unique])
238+
239+
# insert (and overwrite) objects from y to x
240+
x@.xData <- rlang::env_clone(x@.xData, parent = parent.env(.GlobalEnv))
241+
rlang::env_coalesce(env = x@.xData, from = y@.xData)
242+
x
243+
}
244+
)
245+
}

R/qenv-length.R

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
#' @export
2+
length.qenv <- function(x) length(x@.xData)
3+
4+
#' @export
5+
length.qenv.error <- function(x) 0

tests/testthat/test-qenv-class.R

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
testthat::describe("methods::new(qenv)", {
2+
testthat::it("creates a locked environment", {
3+
expect_true(is.environment(methods::new("qenv")))
4+
})
5+
6+
testthat::it("throws error when id and code length doesn't match", {
7+
expect_error(is.environment(methods::new("qenv", id = 1)))
8+
})
9+
10+
testthat::it("throws error when .xData is not an environment", {
11+
expect_true(is.environment(methods::new("qenv")))
12+
})
13+
})

tests/testthat/test-qenv_get_var.R

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -53,11 +53,3 @@ testthat::test_that("get_var, `$` and `[[` only returns objects from qenv, not .
5353
testthat::expect_null(q[["iris"]])
5454
testthat::expect_null(q$iris)
5555
})
56-
57-
testthat::test_that("`$<-` and `[[<-` always return error", {
58-
q <- eval_code(qenv(), quote(x <- 1))
59-
q <- eval_code(q, quote(y <- w * x))
60-
61-
testthat::expect_error(q[["x2"]] <- 3, "when evaluating qenv code")
62-
testthat::expect_error(q$x2 <- 3, "when evaluating qenv code")
63-
})

0 commit comments

Comments
 (0)