Skip to content

Commit 09009b5

Browse files
committed
Tweak API checking and minor doc fixes.
1 parent 1d83a2c commit 09009b5

6 files changed

Lines changed: 83 additions & 33 deletions

File tree

R/CM.R

Lines changed: 47 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
1-
# YT#VHb3a67af97b323ee47762788154a489fd#VHa53bd254d6ac8e6a19dfa057febb06b5#
1+
# YT#VHd079be9470139acf1264d75176dd9b2c#VHe9395a780f86f7653c9f11cadba1e3f0#
22
CM <- local({ # _C_hecked _M_odule
3+
# 2025-07-11: [feature] New `manual_check` flag to tell `CM$generate_check_functions()` to ignore particular elements
4+
# 2025-04-09: [fix] Make `generate_map_afmm_function` maps multi-variable parameters (e.g. `visit_vars`)
35
# 2025-03-21: [feature] report errors for all loaded datasets and [fix] dehardcode "PARAM" string and use `par` argument
46

57
message_well <- function(title, contents, color = "f5f5f5") {
@@ -281,6 +283,13 @@ CM <- local({ # _C_hecked _M_odule
281283
elem <- spec$elements[[elem_name]]
282284
attrs_ids <- setdiff(names(attributes(elem)), c("names", "docs"))
283285
attrs <- attributes(elem)[attrs_ids]
286+
287+
if(isTRUE(attrs[["manual_check"]])) {
288+
push(sprintf("'NOTE: %s (%s) tagged as \"manual_check\"'\n", elem_name, elem$kind))
289+
push(sprintf("' The expectation is that it either does not require automated checks or that'\n"))
290+
push(sprintf("' the caller of this function has written manual checks near the call site.'\n"))
291+
next
292+
}
284293

285294
if (isTRUE(attrs[["subjid_var"]])) {
286295
subjid_vars <- c(subjid_vars, elem_name)
@@ -320,6 +329,11 @@ CM <- local({ # _C_hecked _M_odule
320329
"OK[['%s']] <- CM$check_function('%s', %s, %d, flags, warn, err)\n",
321330
elem_name, elem_name, elem_name, elem$arg_count
322331
))
332+
} else if (elem$kind == "group") {
333+
push(sprintf("'NOTE: %s (%s) unsupported as the check generator cannot handle nested elements yet'\n",
334+
elem_name, elem$kind))
335+
push(sprintf("' The expectation is that it either does not require automated checks or that'\n"))
336+
push(sprintf("' the caller of this function has written manual checks near the call site.'\n"))
323337
} else {
324338
push(sprintf("'NOTE: %s (%s) has no associated automated checks'\n", elem_name, elem$kind))
325339
push(sprintf("' The expectation is that it either does not require them or that'\n"))
@@ -422,11 +436,24 @@ CM <- local({ # _C_hecked _M_odule
422436
elem <- spec$elements[[elem_name]]
423437
stopifnot(elem$kind == "col")
424438
dataset_name <- elem[["dataset_name"]]
425-
push(sprintf("if(is.character(ds[[%s]][[%s]])){\n", dataset_name, elem_name))
426-
push("mapping_summary <- c(mapping_summary,")
427-
push(sprintf("paste0('(', ds_name, ') ', %s, '[[\"', %s, '\"]]')", dataset_name, elem_name))
428-
push(")\n")
429-
push("}\n")
439+
440+
multiple <- (isTRUE(attr(elem, "zero_or_more")) || isTRUE(attr(elem, "one_or_more")))
441+
if (multiple) {
442+
push(sprintf("for (.elem in %s) {\n", elem_name))
443+
push(sprintf("if(is.character(ds[[%s]][[.elem]])){\n", dataset_name))
444+
push("mapping_summary <- c(mapping_summary,")
445+
push(sprintf("paste0('(', ds_name, ') ', %s, '[[\"', .elem, '\"]]')", dataset_name))
446+
push(")\n")
447+
push("}\n")
448+
push("}\n")
449+
} else {
450+
push(sprintf("if(is.character(ds[[%s]][[%s]])){\n", dataset_name, elem_name))
451+
push("mapping_summary <- c(mapping_summary,")
452+
push(sprintf("paste0('(', ds_name, ') ', %s, '[[\"', %s, '\"]]')", dataset_name, elem_name))
453+
push(")\n")
454+
push("}\n")
455+
}
456+
430457
}
431458
push("}\n")
432459

@@ -449,10 +476,20 @@ CM <- local({ # _C_hecked _M_odule
449476
elem <- spec$elements[[elem_name]]
450477
dataset_name <- elem[["dataset_name"]]
451478

452-
push(sprintf("if (is.character(res[[%s]][[%s]])) {\n", dataset_name, elem_name))
453-
push(sprintf(" res[[%s]][[%s]] <- ", dataset_name, elem_name))
454-
push(sprintf(" as.factor(res[[%s]][[%s]])\n", dataset_name, elem_name))
455-
push("}\n")
479+
multiple <- (isTRUE(attr(elem, "zero_or_more")) || isTRUE(attr(elem, "one_or_more")))
480+
if (multiple) {
481+
push(sprintf("for (.elem in %s) {\n", elem_name))
482+
push(sprintf("if (is.character(res[[%s]][[.elem]])) {\n", dataset_name))
483+
push(sprintf(" res[[%s]][[.elem]] <- ", dataset_name))
484+
push(sprintf(" as.factor(res[[%s]][[.elem]])\n", dataset_name))
485+
push("}\n")
486+
push("}\n")
487+
} else {
488+
push(sprintf("if (is.character(res[[%s]][[%s]])) {\n", dataset_name, elem_name))
489+
push(sprintf(" res[[%s]][[%s]] <- ", dataset_name, elem_name))
490+
push(sprintf(" as.factor(res[[%s]][[%s]])\n", dataset_name, elem_name))
491+
push("}\n")
492+
}
456493
}
457494

458495
push(" return(res)\n")

R/TC.R

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# YT#VH1202cc468f3cbf448dd25ff917fc4762#VH00000000000000000000000000000000#
1+
# YT#VHf29a3f572c107632b46daf31f56ecd34#VH1202cc468f3cbf448dd25ff917fc4762#
22
TC <- local({ # _T_ype C_hecks
33
# basic types
44
T_logical <- function() list(kind = "logical")
@@ -78,6 +78,7 @@ TC <- local({ # _T_ype C_hecks
7878
"named", # elements of targetted argument must be named
7979
"map_character_to_factor", # the target TC$col() will be transformed to factor prior to reaching the module
8080
"ignore", # argument should be ignored by Dressing Room, for now
81+
"manual_check", # CM$generate_check_functions will not generate an automated check for this element
8182
# domain-specific flags
8283
"subject_level_dataset_name", # indicates dataset with one row per subject
8384
"subjid_var" # indicates unique subject identifier column on dataset pointed at by subject_level_dataset_name

R/check_call_auto.R

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -11,23 +11,23 @@ check_mod_listings_auto <- function(afmm, datasets, module_id, dataset_names, de
1111
flags <- list(one_or_more = TRUE)
1212
OK[["dataset_names"]] <- CM$check_dataset_name("dataset_names", dataset_names, flags, datasets, used_dataset_names,
1313
warn, err)
14-
"NOTE: default_vars (group) has no associated automated checks"
15-
" The expectation is that it either does not require them or that"
14+
"NOTE: default_vars (group) tagged as \"manual_check\""
15+
" The expectation is that it either does not require automated checks or that"
1616
" the caller of this function has written manual checks near the call site."
17-
"NOTE: pagination (group) has no associated automated checks"
18-
" The expectation is that it either does not require them or that"
17+
"NOTE: pagination (logical) tagged as \"manual_check\""
18+
" The expectation is that it either does not require automated checks or that"
1919
" the caller of this function has written manual checks near the call site."
20-
"NOTE: intended_use_label (group) has no associated automated checks"
21-
" The expectation is that it either does not require them or that"
20+
"NOTE: intended_use_label (character) tagged as \"manual_check\""
21+
" The expectation is that it either does not require automated checks or that"
2222
" the caller of this function has written manual checks near the call site."
23-
"NOTE: subjid_var (group) has no associated automated checks"
24-
" The expectation is that it either does not require them or that"
23+
"NOTE: subjid_var (character) tagged as \"manual_check\""
24+
" The expectation is that it either does not require automated checks or that"
2525
" the caller of this function has written manual checks near the call site."
26-
"NOTE: review (group) has no associated automated checks"
27-
" The expectation is that it either does not require them or that"
26+
"NOTE: review (group) tagged as \"manual_check\""
27+
" The expectation is that it either does not require automated checks or that"
2828
" the caller of this function has written manual checks near the call site."
29-
"NOTE: receiver_id (group) has no associated automated checks"
30-
" The expectation is that it either does not require them or that"
29+
"NOTE: receiver_id (character) tagged as \"manual_check\""
30+
" The expectation is that it either does not require automated checks or that"
3131
" the caller of this function has written manual checks near the call site."
3232
return(OK)
3333
}

R/mod_listings.R

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -205,7 +205,7 @@ listings_UI <- function(module_id) { # nolint
205205
#' @param intended_use_label `[character(1) | NULL]` Either a string indicating the intended use for export, or
206206
#' NULL. The provided label will be displayed prior to the download and will also be included in the exported file.
207207
#'
208-
#' @param subjid_var `[character(1) | NULL]`
208+
#' @param subjid_var `[character(1)]`
209209
#'
210210
#' Column corresponding to subject ID. Default value is 'USUBJID'
211211
#'
@@ -760,19 +760,31 @@ mod_listings_API_docs <- list(
760760
pagination = list(""),
761761
intended_use_label = list(""),
762762
subjid_var = list(""),
763-
review = list(""),
763+
review = list(
764+
"Review-related fields",
765+
datasets = list(""),
766+
choices = list(""),
767+
roles = list(""),
768+
store_path = list("")
769+
),
764770
receiver_id = list("")
765771
)
766772

767773
mod_listings_API_spec <- TC$group(
768774
module_id = TC$mod_ID(),
769775
dataset_names = TC$dataset_name() |> TC$flag("one_or_more"),
770-
default_vars = TC$group() |> TC$flag("ignore"), # manually tested by check_mod_listings
771-
pagination = TC$group() |> TC$flag("ignore"), # manually tested by check_mod_listings
772-
intended_use_label = TC$group() |> TC$flag("ignore"), # manually tested by check_mod_listings
773-
subjid_var = TC$group() |> TC$flag("ignore"), # manually tested by check_mod_listings
774-
review = TC$group() |> TC$flag("ignore"), # functionality is a WIP, so not defining for now
775-
receiver_id = TC$group() |> TC$flag("ignore") # manually tested by check_mod_listings
776+
default_vars = TC$group() |> TC$flag("manual_check"), # manually tested by check_mod_listings
777+
pagination = TC$logical() |> TC$flag("manual_check", "optional"), # manually tested by check_mod_listings
778+
intended_use_label = TC$character() |> TC$flag("manual_check", "optional"), # manually tested by check_mod_listings
779+
subjid_var = TC$character() |> TC$flag("manual_check"), # manually tested by check_mod_listings
780+
review = TC$group(
781+
# TODO: functionality is a WIP, so not defining for now
782+
datasets = TC$group(),
783+
choices = TC$character() |> TC$flag("one_or_more"),
784+
roles = TC$character() |> TC$flag("one_or_more"),
785+
store_path = TC$character() |> TC$flag("optional")
786+
) |> TC$flag("manual_check", "optional"),
787+
receiver_id = TC$character() |> TC$flag("manual_check") # manually tested by check_mod_listings
776788
) |> TC$attach_docs(mod_listings_API_docs)
777789

778790
dataset_info_listings <- function(dataset_names, ...) {

man/listings_UI.Rd

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

man/mod_listings.Rd

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)