Skip to content

Commit 4fa6124

Browse files
committed
1 parent 31566a0 commit 4fa6124

File tree

3 files changed

+156
-2
lines changed

3 files changed

+156
-2
lines changed

R/qenv-get_code.R

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,11 @@ setMethod("get_code", signature = "qenv", function(object, deparse = TRUE, names
112112
checkmate::assert_flag(deparse)
113113
checkmate::assert_character(names, min.len = 1L, null.ok = TRUE)
114114

115+
# Normalize in case special it is backticked
116+
if (!is.null(names)) {
117+
names <- gsub("^`(.*)`$", "\\1", names)
118+
}
119+
115120
code <- if (!is.null(names)) {
116121
get_code_dependency(object@code, names, ...)
117122
} else {

R/utils-get_code_dependency.R

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ get_code_dependency <- function(code, names, check_names = TRUE) {
4242

4343
code <- parse(text = code, keep.source = TRUE)
4444
pd <- utils::getParseData(code)
45+
pd <- normalize_pd(pd)
4546
calls_pd <- extract_calls(pd)
4647

4748
if (check_names) {
@@ -175,7 +176,7 @@ fix_arrows <- function(calls) {
175176
sub_arrows <- function(call) {
176177
checkmate::assert_data_frame(call)
177178
map <- data.frame(
178-
row.names = c("`<-`", "`<<-`", "`=`"),
179+
row.names = c("<-", "<<-", "="),
179180
token = rep("LEFT_ASSIGN", 3),
180181
text = rep("<-", 3)
181182
)
@@ -297,7 +298,7 @@ extract_occurrence <- function(calls_pd) {
297298

298299
# What occurs in a function body is not tracked.
299300
x <- call_pd[!is_in_function(call_pd), ]
300-
sym_cond <- which(x$token %in% c("SYMBOL", "SYMBOL_FUNCTION_CALL"))
301+
sym_cond <- which(x$token %in% c("SPECIAL", "SYMBOL", "SYMBOL_FUNCTION_CALL"))
301302

302303
if (length(sym_cond) == 0) {
303304
return(character(0L))
@@ -434,3 +435,19 @@ detect_libraries <- function(calls_pd) {
434435
)
435436
)
436437
}
438+
439+
#' Normalize parsed data removing backticks from symbols
440+
#'
441+
#' @param pd `data.frame` resulting from `utils::getParseData()` call.
442+
#'
443+
#' @return `data.frame` with backticks removed from `text` column for `SYMBOL` tokens.
444+
#'
445+
#' @keywords internal
446+
#' @noRd
447+
normalize_pd <- function(pd) {
448+
# Remove backticks from SYMBOL tokens
449+
symbol_index <- grepl("^SYMBOL.*$", pd$token)
450+
pd[symbol_index, "text"] <- gsub("^`(.*)`$", "\\1", pd[symbol_index, "text"])
451+
452+
pd
453+
}

tests/testthat/test-qenv_get_code.R

Lines changed: 132 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -740,3 +740,135 @@ testthat::test_that("data() call is returned when data name is provided as a cha
740740
)
741741
)
742742
})
743+
744+
745+
testthat::describe("Backticked symbol", {
746+
testthat::it("code can be retrieved with get_code", {
747+
td <- within(
748+
teal_data(),
749+
{
750+
`%cbind%` <- function(lhs, rhs) cbind(lhs, rhs) # nolint: object_name.
751+
iris_ds <- iris %cbind% data.frame(new_col = "new column")
752+
}
753+
)
754+
755+
testthat::expect_identical(
756+
get_code(td, datanames = "%cbind%"),
757+
"`%cbind%` <- function(lhs, rhs) cbind(lhs, rhs)"
758+
)
759+
})
760+
761+
testthat::it("code can be retrieved with get_code", {
762+
td <- within(
763+
teal_data(),
764+
{
765+
`%cbind%` <- function(lhs, rhs) cbind(lhs, rhs) # nolint: object_name.
766+
iris_ds <- iris %cbind% data.frame(new_col = "new column")
767+
}
768+
)
769+
770+
testthat::expect_identical(
771+
get_code(td, datanames = "`%cbind%`"),
772+
"`%cbind%` <- function(lhs, rhs) cbind(lhs, rhs)"
773+
)
774+
})
775+
776+
testthat::it("starting with underscore is detected in code dependency", {
777+
td <- within(
778+
teal_data(),
779+
{
780+
`_add_column_` <- function(lhs, rhs) cbind(lhs, rhs) # nolint: object_name.
781+
iris_ds <- `_add_column_`(iris, data.frame(new_col = "new column"))
782+
}
783+
)
784+
785+
testthat::expect_identical(
786+
get_code(td, datanames = "iris_ds"),
787+
paste(
788+
sep = "\n",
789+
"`_add_column_` <- function(lhs, rhs) cbind(lhs, rhs)",
790+
"iris_ds <- `_add_column_`(iris, data.frame(new_col = \"new column\"))"
791+
)
792+
)
793+
})
794+
795+
testthat::it("with space character is detected in code dependency", {
796+
td <- within(
797+
teal_data(),
798+
{
799+
`add column` <- function(lhs, rhs) cbind(lhs, rhs) # nolint: object_name.
800+
iris_ds <- `add column`(iris, data.frame(new_col = "new column"))
801+
}
802+
)
803+
804+
testthat::expect_identical(
805+
get_code(td, datanames = "iris_ds"),
806+
paste(
807+
sep = "\n",
808+
"`add column` <- function(lhs, rhs) cbind(lhs, rhs)",
809+
"iris_ds <- `add column`(iris, data.frame(new_col = \"new column\"))"
810+
)
811+
)
812+
})
813+
814+
testthat::it("without special characters is cleaned and detected in code dependency", {
815+
td <- within(
816+
teal_data(),
817+
{
818+
`add_column` <- function(lhs, rhs) cbind(lhs, rhs)
819+
iris_ds <- `add_column`(iris, data.frame(new_col = "new column"))
820+
}
821+
)
822+
823+
testthat::expect_identical(
824+
get_code(td, datanames = "iris_ds"),
825+
paste(
826+
sep = "\n",
827+
"add_column <- function(lhs, rhs) cbind(lhs, rhs)",
828+
"iris_ds <- add_column(iris, data.frame(new_col = \"new column\"))"
829+
)
830+
)
831+
})
832+
833+
testthat::it("with non-native pipe used as function is detected code dependency", {
834+
td <- within(
835+
teal_data(),
836+
{
837+
`%add_column%` <- function(lhs, rhs) cbind(lhs, rhs)
838+
iris_ds <- `%add_column%`(iris, data.frame(new_col = "new column"))
839+
}
840+
)
841+
842+
# Note that the original code is changed to use the non-native pipe operator
843+
# correctly.
844+
testthat::expect_identical(
845+
get_code(td, datanames = "iris_ds"),
846+
paste(
847+
sep = "\n",
848+
"`%add_column%` <- function(lhs, rhs) cbind(lhs, rhs)",
849+
"iris_ds <- iris %add_column% data.frame(new_col = \"new column\")"
850+
)
851+
)
852+
})
853+
854+
testthat::it("with non-native pipe is detected code dependency", {
855+
td <- within(
856+
teal_data(),
857+
{
858+
`%add_column%` <- function(lhs, rhs) cbind(lhs, rhs)
859+
iris_ds <- iris %add_column% data.frame(new_col = "new column")
860+
}
861+
)
862+
863+
# Note that the original code is changed to use the non-native pipe operator
864+
# correctly.
865+
testthat::expect_identical(
866+
get_code(td, datanames = "iris_ds"),
867+
paste(
868+
sep = "\n",
869+
"`%add_column%` <- function(lhs, rhs) cbind(lhs, rhs)",
870+
"iris_ds <- iris %add_column% data.frame(new_col = \"new column\")"
871+
)
872+
)
873+
})
874+
})

0 commit comments

Comments
 (0)