Skip to content

Commit 9b7337f

Browse files
committed
Fix RecordArgs
1 parent de92360 commit 9b7337f

File tree

5 files changed

+68
-32
lines changed

5 files changed

+68
-32
lines changed

DESCRIPTION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ Package: IASDT.R
33
Title: Modelling the distribution of invasive alien plant species in
44
Europe
55
Version: 0.1.03
6-
Date: 2025-03-09
6+
Date: 2025-03-10
77
Authors@R:
88
person("Ahmed", "El-Gabbas", , "ahmed.el-gabbas@ufz.de", role = c("aut", "cre"),
99
comment = c(ORCID = "0000-0003-2225-088X"))

R/General_RecordArgs.R

Lines changed: 56 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -33,11 +33,14 @@
3333
#' environment, and combines them with default values from the parent
3434
#' function’s formal arguments. Unevaluated expressions (e.g., `a + b`) are
3535
#' preserved as character strings via `deparse()`, while scalars (including
36-
#' symbols like `i` in loops that evaluate to scalars) and complex objects
37-
#' (e.g., `lm`, `SpatRaster`) are handled appropriately:
36+
#' symbols like `i` in loops that evaluate to scalars), multi-element vectors
37+
#' (e.g., `c(1, 2)`), and complex objects (e.g., `lm`, `SpatRaster`) are
38+
#' handled appropriately:
3839
#' - Symbols (e.g., `i` in `lapply`) are treated as matching their evaluated
3940
#' scalar values, resulting in a single column.
4041
#' - Calls (e.g., `a + b`) result in `_orig`/`_eval` pairs.
42+
#' - Multi-element vectors (e.g., `c(1, 2)`) result in a single column when
43+
#' unevaluated and evaluated forms match, or `_orig`/`_eval` pairs otherwise.
4144
#' - Complex objects are wrapped in lists in `_eval` columns.
4245
#' Columns are ordered based on the original argument sequence: single columns
4346
#' (for matching values) appear first, followed by `_orig` and `_eval` pairs
@@ -67,13 +70,11 @@
6770
#' a <- 5
6871
#' b <- 3
6972
#'
70-
#' Function1 <- function(w = 5, x, y, z = 10) {
73+
#' Function1 <- function(w = 5, x, y, z = c(1, 2)) {
7174
#' Args <- IASDT.R::RecordArgs(call = match.call(), env = parent.frame())
7275
#' return(Args)
7376
#' }
7477
#'
75-
#' # --------------------------------------------------------------
76-
#'
7778
#' # Basic usage with scalars and expressions
7879
#' Out1 <- Function1(x = a + b, y = 2)
7980
#'
@@ -83,7 +84,8 @@
8384
#' Out1$x_orig # "a + b" (unevaluated expression)
8485
#' Out1$x_eval # 8 (evaluated result)
8586
#' Out1$y # 2 (single column, scalar matches evaluated)
86-
#' Out1$z # 10 (single column, default matches evaluated)
87+
#' Out1$z_orig # "c(1, 2)"
88+
#' Out1$z_eval # c(1, 2) (single column, default matches evaluated)
8789
#'
8890
#' # --------------------------------------------------------------
8991
#'
@@ -134,18 +136,18 @@ RecordArgs <- function(ExportPath = NULL, call = NULL, env = NULL) {
134136

135137
# Capture the parent function's call: use provided call (e.g., from
136138
# match.call()) or fall back to sys.call(-1) for direct calls
137-
call_info <- if (!is.null(call)) call else sys.call(-1)
139+
call_info <- if (!is.null(call)) {
140+
call
141+
} else {
142+
sys.call(-1)
143+
}
138144

139145
# Check if call_info is valid; stop if not called within a function
140146
if (is.null(call_info)) {
141147
stop(
142148
"RecordArgs() must be called from within another function", call. = FALSE)
143149
}
144150

145-
# Extract the arguments from the call, excluding the function name (first
146-
# element)
147-
args_list <- as.list(call_info)[-1]
148-
149151
# Get the name of the calling function as a character string
150152
calling_func <- deparse(call_info[[1]])
151153

@@ -157,8 +159,20 @@ RecordArgs <- function(ExportPath = NULL, call = NULL, env = NULL) {
157159
parent_func <- sys.function(-1)
158160
formals_full <- formals(parent_func)
159161

160-
# Evaluate the captured arguments in the parent environment
161-
args_values <- lapply(args_list, eval, envir = parent_env)
162+
# Extract the arguments from the call, excluding the function name (first
163+
# element), and preserve defaults for missing arguments
164+
args_list <- as.list(call_info)[-1]
165+
args_list <- utils::modifyList(formals_full, args_list)
166+
167+
# Evaluate the captured arguments in the parent environment, handling all
168+
# cases safely
169+
args_values <- lapply(args_list, function(x) {
170+
tryCatch(eval(x, envir = parent_env), error = function(e) {
171+
# If evaluation fails in parent_env, try globalenv() to resolve globals
172+
# (e.g., 'a' and 'b' in 'a + b')
173+
tryCatch(eval(x, envir = globalenv()), error = function(e2) NA)
174+
})
175+
})
162176

163177
# Name the evaluated values with their corresponding argument names
164178
recorded_values <- stats::setNames(args_values, names(args_list))
@@ -207,14 +221,28 @@ RecordArgs <- function(ExportPath = NULL, call = NULL, env = NULL) {
207221
# e.g., "x_orig" (unevaluated forms)
208222
uneval_cols <- paste0(diff_cols, "_orig")
209223

210-
# Format evaluated values: scalars as-is, complex objects (e.g., SpatRaster)
211-
# wrapped in lists
224+
# Format evaluated values: scalars as-is (e.g., 5, 8, NA), multi-element
225+
# vectors (e.g., c(1, 2)) and complex objects in lists
212226
eval_values <- purrr::map(
213227
.x = as.list(Evaluated),
214228
.f = function(x) {
215-
if (is.vector(x) && length(x) == 1 && !is.list(x)) {
216-
# Scalars remain as-is (e.g., 8, "BCD")
217-
return(x)
229+
if (is.vector(x) && !is.list(x)) {
230+
if (length(x) == 1) {
231+
# Scalars (e.g., 5, 8, NA) remain as-is
232+
return(x)
233+
} else {
234+
# Multi-element vectors (e.g., c(1, 2)) wrapped in a list
235+
return(list(x))
236+
}
237+
} else if (is.language(x)) {
238+
# Evaluate language objects and handle based on length
239+
eval_result <- eval(x, envir = parent_env)
240+
if (is.vector(eval_result) && !is.list(eval_result) &&
241+
length(eval_result) == 1) {
242+
return(eval_result)
243+
} else {
244+
return(list(eval_result))
245+
}
218246
} else {
219247
if (inherits(x, "SpatRaster")) {
220248
# Wrap SpatRaster objects for storage
@@ -225,17 +253,22 @@ RecordArgs <- function(ExportPath = NULL, call = NULL, env = NULL) {
225253
}
226254
})
227255

228-
# Format unevaluated values: calls as character strings, scalars as-is,
229-
# complex objects in lists
256+
# Format unevaluated values: calls as strings (e.g., "a + b"), scalars as-is
257+
# (e.g., 5), multi-element vectors (e.g., c(1, 2)) in lists
230258
uneval_values <- purrr::map(
231259
.x = as.list(Unevaluated),
232260
.f = function(x) {
233261
if (is.call(x)) {
234262
# Convert calls (e.g., a + b) to strings without quotes
235263
return(noquote(deparse(x)))
236-
} else if (is.vector(x) && length(x) == 1 && !is.list(x)) {
237-
# Scalars (e.g., 2, 10) remain as-is
238-
return(x)
264+
} else if (is.vector(x) && !is.list(x)) {
265+
if (length(x) == 1) {
266+
# Scalars (e.g., 5) remain as-is
267+
return(x)
268+
} else {
269+
# Multi-element vectors (e.g., c(1, 2)) wrapped in a list
270+
return(list(x))
271+
}
239272
} else {
240273
if (inherits(x, "SpatRaster")) {
241274
# Wrap SpatRaster objects

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -74,4 +74,4 @@ If you use the `IASDT.R` package, please cite it as:
7474
> <a href="https://biodt.eu" target="_blank">https://biodt.eu</a>.
7575
7676
<span style=" color: grey !important;">Last update:
77-
2025-03-09</span>
77+
2025-03-10</span>

man/RecordArgs.Rd

Lines changed: 8 additions & 6 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

vignettes/workflow_1_overview.Rmd

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,8 @@ DT <- tibble::tribble(
132132
"DP_R_PA", "Species distribution", "Directory path to species-specific presence-absence data", "datasets/processed/IAS_PA",
133133
"DP_R_HabAff", "Taxa information", "Path to `rds` file containing species affinity to habitat types", "references/taxon-habitat-combined_2024-02-07.rds",
134134
"DP_R_Taxa_country", "Taxa information", "Path to excel file containing the number of grid cells per species and country", "references/cell_count_per_species_and_country_2024-01-30-IA-VK-MG.xlsx",
135-
"DP_R_Taxa_easin", "Taxa information", "Path to `rds` file containing EASIN standardized taxonomy", "references/easin_taxon-list-gbif_2024-02-07.rds") %>%
135+
"DP_R_Taxa_easin", "Taxa information", "Path to `rds` file containing EASIN standardized taxonomy", "references/easin_taxon-list-gbif_2024-02-07.rds",
136+
"DP_R_OPeNDAP_url", "", "Path to OpENDAP server for the `IAS-pDT`", "http://opendap.biodt.eu/ias-pdt/") %>%
136137
dplyr::mutate(
137138
Variable = paste0("<cc>", Variable, "</cc>"),
138139
Category = NULL,

0 commit comments

Comments
 (0)