Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closes #140 #196

Merged
merged 6 commits into from
Sep 13, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions R/axecute.R
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,13 @@
#' close(fileConn)
#'
#' axecute(file.path(dir, "hello.R"))
#'
#'
#' fileConn <- file(file.path(dir, "hello.Rmd"))
#' writeLines(text, fileConn)
#' close(fileConn)
#'
#' axecute(file.path(dir, "hello.Rmd"))
axecute <- function(file, log_name = NA,
log_path = NA,
remove_log_object = TRUE,
Expand Down
24 changes: 22 additions & 2 deletions R/get.R
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,16 @@ get_masked_functions <- function(){
#'
get_used_functions <- function(file){

# if markdown, write R code, including inline, to a script
# use this script to find functions used
if (grepl("*.Rmd$", file, ignore.case = TRUE)){
tmpfile <- tempfile(fileext = ".R")
on.exit(unlink(tmpfile))
withr::local_options(list(knitr.purl.inline = TRUE))
knitr::purl(file, tmpfile)
file <- tmpfile
}

# catch error
retfun <- safely(parse,
quiet = FALSE,
Expand Down Expand Up @@ -191,14 +201,24 @@ get_used_functions <- function(file){
names_from = "token") %>%
ungroup()

combine_tokens <- wide_tokens %>%
# if package is present, but symbol or special is not, a function did not follow the ::
bms63 marked this conversation as resolved.
Show resolved Hide resolved
# ex. knitr::opts_chunk$set()
# for this case, remove row that contains the package
# set will still be captured but we will be able to link it to a package in this current version
wide_tokens_wo_orphans <- wide_tokens[!(!is.na(wide_tokens$SYMBOL_PACKAGE) & is.na(wide_tokens$SYMBOL_FUNCTION_CALL) & is.na(wide_tokens$SPECIAL)),]

combine_tokens <- wide_tokens_wo_orphans %>%
mutate(function_name = coalesce(.data[["SYMBOL_FUNCTION_CALL"]],
.data[["SPECIAL"]]))

get_library(combine_tokens) %>%
distinct_use <- get_library(combine_tokens) %>%
select(all_of(c("function_name", "library"))) %>%
distinct()

distinct_use[is.na(distinct_use)] <- "!!! NOT FOUND !!!"

distinct_use

}


Expand Down
15 changes: 14 additions & 1 deletion R/interact.R
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,13 @@ set_log_name_path <- function(log_name = NA, log_path = NA) {
#' @noRd
run_safely <- function(file) "dummy"

#' Is this a R Markdown file
#' @param file String. Path to file to execute
#' @noRd
is_rmarkdown <- function(file) {
grepl("*.Rmd$", file, ignore.case = TRUE)
}

#' Dummy function for running a file
#' @noRd
run_file <- function(file){
Expand All @@ -118,7 +125,13 @@ run_file <- function(file){
} else{
exec_env <- getOption("log.rx.exec.env")
}
source(file, local = exec_env)

if(is_rmarkdown(file)){
rmarkdown::render(file, envir = exec_env)
bms63 marked this conversation as resolved.
Show resolved Hide resolved
} else{
source(file, local = exec_env)
}

}

#' Safely run an R script and record results, outputs, messages, errors, warnings
Expand Down
2 changes: 1 addition & 1 deletion R/log.R
Original file line number Diff line number Diff line change
Expand Up @@ -279,7 +279,7 @@ log_write <- function(file = NA,
}
if ("result" %in% to_report){
cleaned_log_vec <- c(cleaned_log_vec,
write_result())
write_result(file))
}

cleaned_log_vec <- c(cleaned_log_vec,
Expand Down
8 changes: 6 additions & 2 deletions R/writer.R
Original file line number Diff line number Diff line change
Expand Up @@ -260,10 +260,14 @@ write_output <- function() {
#'
#' @noRd
#'
write_result <- function() {
write_result <- function(file) {
result <- get_log_element("result")

c("\nResult:", paste0("\t", capture.output(result$value)))
if (is_rmarkdown(file)) {
c("\nResult:", paste0("\t", capture.output(result)))
} else {
c("\nResult:", paste0("\t", capture.output(result$value)))
}
}

#' Format lint results for writing
Expand Down
7 changes: 7 additions & 0 deletions man/axecute.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

31 changes: 31 additions & 0 deletions tests/testthat/ref/ex1.Rmd
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
---
title: "ex1"
date: "2023-07-06"
---

## R Markdown

This is an R Markdown document. Markdown is a simple formatting syntax for authoring HTML, PDF, and MS Word documents. For more details on using R Markdown see <http://rmarkdown.rstudio.com>.

When you click the **Knit** button a document will be generated that includes both content as well as the output of any embedded R code chunks within the document. You can embed an R code chunk like this:

```{r cars}
library(dplyr)
summary(cars)
```

## Including Plots

You can also embed plots, for example:

```{r pressure, echo=FALSE}
plot(pressure)
```

Note that the `echo = FALSE` parameter was added to the code chunk to prevent printing of the R code that generated the plot.

```{r}
mtcars %>%
dplyr::filter(mpg >= 20)
```
Let's test some inline code with `r print("print")`
39 changes: 39 additions & 0 deletions tests/testthat/test-axecute.R
Original file line number Diff line number Diff line change
Expand Up @@ -98,3 +98,42 @@ test_that("include_rds works to output log as rds", {
rm(con, scriptPath, logDir, logRDS)
log_remove()
})

test_that("axecute will run a markdown file and create the necessary log", {
options("log.rx" = NULL)

scriptPath <- test_path("ref", "ex1.Rmd")
logDir <- tempdir()

# check no log is currently written out
expect_warning(expect_error(file(file.path(logDir, "rmd_log_out"), "r"), "cannot open the connection"))

axecute(scriptPath, log_name = "rmd_log_out", log_path = logDir, remove_log_object = FALSE)
con <- file(file.path(logDir, "rmd_log_out"), "r")
flines <- readLines(con)
close(con)

# check that the output file is populated
expect_gt(length(flines), 1)
# check all the elements are there
expect_true(grepl(paste(write_log_header("logrx Metadata"), collapse = ','),
paste(flines,collapse = ',')))
expect_true(grepl(paste(write_log_header("User and File Information"), collapse = ','),
paste(flines,collapse = ',')))
expect_true(grepl(paste(write_log_header("Session Information"), collapse = ','),
paste(flines,collapse = ',')))
expect_true(grepl(paste(write_log_header("Masked Functions"), collapse = ','),
paste(flines,collapse = ',')))
expect_true(grepl(paste(write_log_header("Program Run Time Information"), collapse = ','),
paste(flines,collapse = ',')))
expect_true(grepl(paste(write_log_header("Errors and Warnings"), collapse = ','),
paste(flines,collapse = ',')))
expect_true(grepl(paste(write_log_header("Messages, Output, and Result"), collapse = ','),
paste(flines,collapse = ',')))
expect_true(grepl(paste(write_log_header("Log Output File"), collapse = ','),
paste(flines,collapse = ',')))

# remove all the stuff we added
rm(flines, con, scriptPath, logDir)
log_remove()
})
25 changes: 25 additions & 0 deletions tests/testthat/test-get.R
Original file line number Diff line number Diff line change
Expand Up @@ -159,3 +159,28 @@ test_that("lint returns expected result when option is not set", {

expect_identical(get_lint_results(filename), NULL)
})

test_that("functions used are returned correctly for rmd files", {
filename <- test_path("ref", "ex1.Rmd")

tmpfile <- tempfile(fileext = ".R")

withr::local_options(list(knitr.purl.inline = TRUE))

knitr::purl(filename, tmpfile)

source(tmpfile, local = TRUE)

expected <- tibble::tribble(
~function_name, ~library,
"library", "package:base",
"summary", "package:base",
"plot", "package:graphics",
"%>%", "package:dplyr",
"filter", "package:dplyr",
"print", "package:base"
)

expect_identical(get_used_functions(tmpfile), expected)

})
2 changes: 1 addition & 1 deletion tests/testthat/test-writer.R
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,7 @@ test_that("write_result will return a formatted log result element", {

run_safely_loudly(fp)

expect_identical(write_result(),
expect_identical(write_result(fp),
c("\nResult:", paste0("\t", capture.output(data.frame(test = c(8, 6, 7, 5, 3, 0, 9))))))

log_remove()
Expand Down
6 changes: 6 additions & 0 deletions vignettes/approved.Rmd
Original file line number Diff line number Diff line change
Expand Up @@ -173,3 +173,9 @@ logrx::log_remove()

unlink(dir, recursive = TRUE)
```

# A Few Words of Caution

All packages should be attached at the top of the script to set a consistent `?base::searchpaths()` throughout the entire script. This will ensure the functions you use in your script are linked to the correct package. A lint feature is available to test your scripts follow this best practice.

Some functions are stored within a list, for example `knitr::opts_chunck$get()` and `knitr::opts_current$get()`. We do not currently identify `get()` as a knitr function since it is not exported.
Loading