Skip to content

Commit

Permalink
refactor: improve readability and logical of `try_user_config_locatio…
Browse files Browse the repository at this point in the history
…n()`

- encapsulate finding the relevant lines in the config file into "guess_lines_to_config_file()"
    - function allows for multi-line/grk-style app_sys()-calls (if file path to long and must be put into next line)
    - has clearer and commented logic to find the lines
- document proper logic of function with comments
- style with `grkstyle::grk_style_transformer`
- update `tests/testthat/test-config.R` to incorporate above changes and move code coverage of that file to 64.22%
  • Loading branch information
ilyaZar committed Aug 2, 2023
1 parent 230b73d commit b76efe7
Show file tree
Hide file tree
Showing 2 changed files with 87 additions and 50 deletions.
69 changes: 50 additions & 19 deletions R/config.R
Original file line number Diff line number Diff line change
Expand Up @@ -49,13 +49,13 @@ guess_where_config <- function(
)
}
ret_path <- try_user_config_location(pth = golem::pkg_path())
if (is.null(ret_path)) return(NULL)
if (fs_file_exists(ret_path)) {
return(fs_path_abs(ret_path))
}

return(NULL)
}

try_user_config_location <- function(pth) {
# I. try to retrieve from possible user change in app_config.R
user_location_default <- file.path(pth, "R/app_config.R")
Expand All @@ -64,29 +64,60 @@ try_user_config_location <- function(pth) {
}

# II. if successful, read file and find line where new config is located
tmp_guess_text <- readLines(user_location_default)
tmp_guess_line <- which(grepl("app_sys\\(", tmp_guess_text))
if (identical(integer(0), tmp_guess_line)) {
return(NULL)
}

# III. if successfull, identify the string that gives new config-path
tmp_config_expr <- regexpr("\\(.*\\)$", tmp_guess_text[tmp_guess_line])
tmp_config_char <- regmatches(
tmp_guess_text[tmp_guess_line],
tmp_config_expr
)

# IV. clean that string from artefacts of regexpr()
out_config_char <- substr(
substring(tmp_config_char, 3),
start = 1,
stop = nchar(substring(tmp_config_char, 3)) - 2
tmp_guess_text <- readLines("R/app_config.R")
tmp_guess_lines <- guess_lines_to_config_file(tmp_guess_text)
## -> early return if malformation i.e. no lines found that match app_sys(...)
if (is.null(tmp_guess_lines)) return(NULL)

# III. Collapse character-text found into a single char from which to retrieve
# path! This is important if the path is a (complicated) multi-line path.
tmp_guess_subtext <- paste0(tmp_guess_text[tmp_guess_lines], collapse = "")

# IV. Identify quoted string that gives new config-path
tmp_config_expr <- regexpr("\\((.|\n)*\\)$", tmp_guess_subtext)
tmp_config_char <- regmatches(tmp_guess_subtext, tmp_config_expr)

# V. Manually remove quotes/character-artefacts to form a proper path
out_config_char <- regmatches(
tmp_config_char,
regexpr('\\".*\\"', tmp_config_char)
)
out_config_char <- substring(out_config_char, 2, nchar(out_config_char) - 1)

# V. return full path to new config file including pkg-path and 'inst'
return(file.path(pth, "inst", out_config_char))
}
guess_lines_to_config_file <- function(guess_text) {
# I. Check if the path is a one-liner i.e. try to match `app_sys(...)` string
tmp_guess_lines <- which(grepl("app_sys\\((.|\n)*\\)$", guess_text))
if (identical(integer(0), tmp_guess_lines)) {
# II. If that is not the case, identify lines that contain the path info
tmp_guess_multi_liner <- which(grepl("app_sys\\(", guess_text))
if (identical(integer(0), tmp_guess_multi_liner)) {
# Early return NULL if file does not contain the `app_sys()` command;
# alternatively, there could be an error thrown here if `app_sys()` must
# be present inside any `R/app_config.R`; think about this later
return(NULL)
}
tmp_guess_lines <- tmp_guess_multi_liner
tmp_check_lines <- seq(
from = tmp_guess_lines + 1,
to = length(guess_text)
)
# Fine the closing brace `)` of app_sys(...) - identified code portion must
# contain information on the path.
tmp_end_line <- NULL
for (i in tmp_check_lines) {
if (grepl(".*\\)", guess_text[i])) {
tmp_end_line <- i
break
}
}
# Return value is a sequence of line numbers where to elicit the config-path
tmp_guess_lines <- seq(from = tmp_guess_lines, to = tmp_end_line)
}
return(tmp_guess_lines)
}
#' Get the path to the current config File
#'
#' This function tries to guess where the golem-config file is located.
Expand Down
68 changes: 37 additions & 31 deletions tests/testthat/test-config.R
Original file line number Diff line number Diff line change
Expand Up @@ -76,10 +76,9 @@ test_that("config works", {
)
})
})
test_that("golem-config.yml can be moved to another location", {
test_that("golem-config.yml can be renamed and moved to another location", {

path_dummy_golem <- tempfile(pattern = "dummygolem")

golem::create_golem(
path = path_dummy_golem,
open = FALSE
Expand All @@ -88,59 +87,66 @@ test_that("golem-config.yml can be moved to another location", {
old_wd <- setwd(path_dummy_golem)
on.exit(setwd(old_wd))

# The good config path is returned
## The default config path is returned
expect_equal(
golem:::guess_where_config(),
golem:::fs_path_abs(file.path(
path_dummy_golem,
"inst/golem-config.yml"
))
)
# document_and_reload does not throw an error
expect_error(
document_and_reload(),
regexp = NA
)
expect_equal(
get_golem_name(),
basename(path_dummy_golem)
)
expect_equal(
get_golem_wd(),
path_dummy_golem
)

## Move config file
## Some renamed config AND under a different path is returned
## I. create new dir
dir.create(
"inst/config"
)
## II. Move config file under a different name to that dir
file.copy(
from = "inst/golem-config.yml",
to = "inst/config/golem.yml"
)
## III. Remove old config file
file.remove(
"inst/golem-config.yml"
)
# User adjusts the correct line in app_config.R:
tmp_app_config_r <- readLines("R/app_config.R")
tmp_app_config_r[36] <- " file = app_sys(\"config/golem.yml\")"
writeLines(tmp_app_config_r, "R/app_config.R")

# The good config path is returned
## IV Save content of default config to restore and for final test later
tmp_app_config_default <- readLines("R/app_config.R")
# V.A User alters correct line in app_config.R: different path AND filename!
tmp_app_config_test_01 <- readLines("R/app_config.R")
tmp_app_config_test_01[36] <- " file = app_sys(\"config/golem.yml\")"
writeLines(tmp_app_config_test_01, "R/app_config.R")
# V.A The updated config is found
expect_equal(
golem:::guess_where_config(),
golem:::fs_path_abs(file.path(
path_dummy_golem,
"inst/config/golem.yml"
))
)
# document_and_reload does not throw an error
expect_error(
document_and_reload(),
regexp = NA
)
## V.B app_config.R has a multi-line statement
## - > e.g. because of grkstyle formatting or long path names
tmp_app_config_test_02 <- tmp_app_config_default
tmp_max_lines_config <- length(tmp_app_config_test_02)
tmp_app_config_test_02[36] <- " file = app_sys("
tmp_app_config_test_02 <- c(tmp_app_config_test_02[1:36],
"\"config/golem.yml\"",
")",
tmp_app_config_test_02[37:tmp_max_lines_config])
writeLines(tmp_app_config_test_02, "R/app_config.R")
# V.B The updated config with multi-line app_sys()-call is read correctly
expect_equal(
get_golem_name(),
basename(path_dummy_golem)
golem:::guess_where_config(),
golem:::fs_path_abs(file.path(
path_dummy_golem,
"inst/config/golem.yml"
))
)
## V.C app_config.R has a malformatted app_sys(...) call
## -> e.g. because of grkstyle formatting or long path names
tmp_app_config_test_03 <- tmp_app_config_default
## malformation = typo: app_syss() instead of app_sys()
tmp_app_config_test_03[36] <- " file = app_syss(\"config/golem.yml\")"
writeLines(tmp_app_config_test_03, "R/app_config.R")
# V.C The updated config with multi-line app_sys()-call is read correctly
expect_null(golem:::guess_where_config())
})

0 comments on commit b76efe7

Please sign in to comment.