From 3dd596a382c4e29d4172714acc898de158077580 Mon Sep 17 00:00:00 2001 From: Ashley Baldry Date: Thu, 17 Sep 2026 15:22:37 +0100 Subject: [PATCH 1/2] (fix): ensure anon functions don't get misclassed as reactive calls --- R/call_chunk_utils.R | 14 +++++++++----- tests/testthat/test-call_chunk_utils.R | 21 +++++++++++++++++++++ 2 files changed, 30 insertions(+), 5 deletions(-) diff --git a/R/call_chunk_utils.R b/R/call_chunk_utils.R index 0a0b475..a352ddd 100644 --- a/R/call_chunk_utils.R +++ b/R/call_chunk_utils.R @@ -18,9 +18,11 @@ #' @keywords internal #' @rdname call_chunk_checks is_reactive_call <- function(x, env = rlang::caller_env()) { - rlang::is_call(x) && + call_name <- if (rlang::is_call(x)) rlang::call_name(x) + + !is.null(call_name) && length(rlang::call_args(x)) == 0 && - rlang::call_name(x) %in% names(env) + call_name %in% names(env) } #' @description @@ -39,10 +41,12 @@ is_reactive_val_call <- function(x, env = rlang::caller_env()) { #' #' @rdname call_chunk_checks is_reactive_val_setter_call <- function(x, env = rlang::caller_env()) { - rlang::is_call(x) && + call_name <- if (rlang::is_call(x)) rlang::call_name(x) + + !is.null(call_name) && length(rlang::call_args(x)) == 1L && - rlang::call_name(x) %in% names(env) && - inherits(env[[rlang::call_name(x)]], "reactiveVal") + call_name %in% names(env) && + inherits(env[[call_name]], "reactiveVal") } #' @description diff --git a/tests/testthat/test-call_chunk_utils.R b/tests/testthat/test-call_chunk_utils.R index 256de02..9177427 100644 --- a/tests/testthat/test-call_chunk_utils.R +++ b/tests/testthat/test-call_chunk_utils.R @@ -10,3 +10,24 @@ test_that("Able to extract package name from unnamespaced function call", { test_that("When extract package from function call, base R packages are ignored", { expect_null(get_pkg_name(str2lang("nzchar('foo')"))) }) + +test_that("Call checks return FALSE, not NA, when the call has no function name", { + anon_call <- str2lang('get("mean")(1:10)') + + expect_false(is_reactive_call(anon_call)) + expect_false(is_reactive_val_call(anon_call)) + expect_false(is_reactive_val_setter_call(anon_call)) +}) + +test_that("A reactive calling an unnamed function is reproduced rather than erroring", { + testthat::skip_if_not_installed("shiny") + + shiny::reactiveConsole(TRUE) + on.exit(shiny::reactiveConsole(FALSE), add = TRUE) + + named_fn <- shiny::reactive(get("mean")(1:10)) + expect_identical(reprex_reactive(named_fn), 'get("mean")(1:10)') + + anon_fn <- shiny::reactive((function(x) x + 1)(1)) + expect_identical(reprex_reactive(anon_fn), "(function(x) x + 1)(1)") +}) From 93e02718e4b3b1c4754fb55a99a241a1d9118d86 Mon Sep 17 00:00:00 2001 From: Ashley Baldry Date: Thu, 17 Sep 2026 16:25:35 +0100 Subject: [PATCH 2/2] (fix): 0-arg function calls no longer classed as reactives --- R/call_chunk_utils.R | 3 ++- tests/testthat/test-call_chunk_utils.R | 11 +++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/R/call_chunk_utils.R b/R/call_chunk_utils.R index a352ddd..ad2e6fc 100644 --- a/R/call_chunk_utils.R +++ b/R/call_chunk_utils.R @@ -22,7 +22,8 @@ is_reactive_call <- function(x, env = rlang::caller_env()) { !is.null(call_name) && length(rlang::call_args(x)) == 0 && - call_name %in% names(env) + call_name %in% names(env) && + inherits(env[[call_name]], "reactive") } #' @description diff --git a/tests/testthat/test-call_chunk_utils.R b/tests/testthat/test-call_chunk_utils.R index 9177427..80f653f 100644 --- a/tests/testthat/test-call_chunk_utils.R +++ b/tests/testthat/test-call_chunk_utils.R @@ -31,3 +31,14 @@ test_that("A reactive calling an unnamed function is reproduced rather than erro anon_fn <- shiny::reactive((function(x) x + 1)(1)) expect_identical(reprex_reactive(anon_fn), "(function(x) x + 1)(1)") }) + +# is_reactive_call ---- +test_that("A function call with no arguments is not classed as a reactive", { + testthat::skip_if_not_installed("shiny") + + my_fn <- function() "hello" + my_reactive <- shiny::reactive("") + + expect_false(is_reactive_call(quote(my_fn()))) + expect_true(is_reactive_call(quote(my_reactive()))) +})