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

Don't keep code as a string #221

Closed
pawelru opened this issue Oct 4, 2023 · 6 comments · Fixed by #232
Closed

Don't keep code as a string #221

pawelru opened this issue Oct 4, 2023 · 6 comments · Fixed by #232
Assignees

Comments

@pawelru
Copy link
Contributor

pawelru commented Oct 4, 2023

Please change the below so that we don't keep executed code as a string:

format_code_block_function <- paste0(
c(
"code_block <- function (code_text) {",
" df <- data.frame(code_text)",
" ft <- flextable::flextable(df)",
" ft <- flextable::delete_part(ft, part = 'header')",
" ft <- flextable::autofit(ft, add_h = 0)",
" ft <- flextable::fontsize(ft, size = 7, part = 'body')",
" ft <- flextable::bg(x = ft, bg = 'lightgrey')",
" ft <- flextable::border_outer(ft)",
" if (flextable::flextable_dim(ft)$widths > 8) {",
" ft <- flextable::width(ft, width = 8)",
" }",
" ft",
"}"
),
collapse = "\n"
)

If string is really needed then please convert code object into a string

@chlebowa
Copy link
Contributor

chlebowa commented Oct 19, 2023

Would you prefer a function that is never called but whose body is pasted into the Rmd? That was the case during review but I didn't like having a function that is never called.

@pawelru
Copy link
Contributor Author

pawelru commented Oct 19, 2023

IMHO language (or expression if it's simple enough) is better choice to store a code rather than string. String should be just representation of it (e.g. used by print method). This obviously depends on the use case - I haven't analysed that one yet.
There is a big advantage of this being we don't hide code dependency. R CMD CHECK cannot interpret that code-string and detect package dependencies.

I didn't like having a function that is never called

I don't quite understand that. If it's not used why to keep it?
Are you sure we are not calling it?

do.call(rmarkdown::render, args)

@chlebowa
Copy link
Contributor

As you can see, the resulting string is a function definition statement. It is pasted into the resulting Rmd document and defined during rendering of that file. It is never called in the package itself.

I don't understand what you are linking to.

@pawelru
Copy link
Contributor Author

pawelru commented Oct 19, 2023

I think it's called

renderRmd = function(blocks, yaml_header, global_knitr = list()) {
checkmate::assert_list(blocks, c("TextBlock", "PictureBlock", "NewpageBlock", "TableBlock", "RcodeBlock"))
if (missing(yaml_header)) {
yaml_header <- md_header(yaml::as.yaml(list(title = "Report")))
}
private$report_type <- get_yaml_field(yaml_header, "output")
format_code_block_function <- paste0(
c(
"code_block <- function (code_text) {",
" df <- data.frame(code_text)",
" ft <- flextable::flextable(df)",
" ft <- flextable::delete_part(ft, part = 'header')",
" ft <- flextable::autofit(ft, add_h = 0)",
" ft <- flextable::fontsize(ft, size = 7, part = 'body')",
" ft <- flextable::bg(x = ft, bg = 'lightgrey')",
" ft <- flextable::border_outer(ft)",
" if (flextable::flextable_dim(ft)$widths > 8) {",
" ft <- flextable::width(ft, width = 8)",
" }",
" ft",
"}"
),
collapse = "\n"
)
parsed_global_knitr <- sprintf(
"\n```{r setup, include=FALSE}\nknitr::opts_chunk$set(%s)\n%s\n```\n",
capture.output(dput(global_knitr)),
if (identical(private$report_type, "powerpoint_presentation")) {
format_code_block_function
} else {
""
}
)
parsed_blocks <- paste(
unlist(
lapply(blocks, function(b) private$block2md(b))
),
collapse = "\n\n"
)
rmd_text <- paste0(yaml_header, "\n", parsed_global_knitr, "\n", parsed_blocks, "\n")
tmp <- tempfile(fileext = ".Rmd")
input_path <- file.path(
private$output_dir,
sprintf("input_%s.Rmd", gsub("[.]", "", format(Sys.time(), "%Y%m%d%H%M%OS3")))
)
cat(rmd_text, file = input_path)
input_path
},

This method is creates a .Rmd file and returns path to it

teal.reporter/R/Renderer.R

Lines 95 to 105 in b82c2ac

input_path <- self$renderRmd(blocks, yaml_header, global_knitr)
args <- append(args, list(
input = input_path,
output_dir = private$output_dir,
output_format = "all",
quiet = TRUE
))
args_nams <- unique(names(args))
args <- lapply(args_nams, function(x) args[[x]])
names(args) <- args_nams
do.call(rmarkdown::render, args)

Line 95: we call a method and store returned file path
Line 96-104: we add more args to the list
Line 105: we call render() on that newly created file which essentially means that we call a code inputted there.

@chlebowa
Copy link
Contributor

My mistake, I missed the fact that the report is rendered when it is saved.

Would you rather have

format_code_block_function <- quote(
    code_block <- function(code_text) {
        df <- data.frame(code_text)
        ft <- flextable::flextable(df)
        ft <- flextable::delete_part(ft, part = "header")
        ft <- flextable::autofit(ft, add_h = 0)
        ft <- flextable::fontsize(ft, size = 7, part = "body")
        ft <- flextable::bg(x = ft, bg = "lightgrey")
        ft <- flextable::border_outer(ft)
        if (flextable::flextable_dim(ft)$widths > 8) {
            ft <- flextable::width(ft, width = 8)
        }
        ft
    }
)

and then

paste(deparse(format_code_block_function), collapse = "\n")

?

@pawelru
Copy link
Contributor Author

pawelru commented Oct 19, 2023

Yes. Way way better than code code as a string.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants