Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
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
2 changes: 1 addition & 1 deletion DESCRIPTION
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
Package: quarto
Title: R Interface to 'Quarto' Markdown Publishing System
Version: 1.4.4.9021
Version: 1.4.4.9022
Authors@R: c(
person("JJ", "Allaire", , "[email protected]", role = "aut",
comment = c(ORCID = "0000-0003-0174-9868")),
Expand Down
1 change: 1 addition & 0 deletions NAMESPACE
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
# Generated by roxygen2: do not edit by hand

export(add_spin_preamble)
export(check_newer_version)
export(is_using_quarto)
export(new_blog_post)
Expand Down
2 changes: 2 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# quarto (development version)

- Added `add_spin_preamble()` function to add YAML preambles to R scripts for use with Quarto Script rendering support. The function automatically detects existing preambles and provides flexible customization options through `title` and `preamble` parameters (#164).

- `quarto_create_project()` gains a `title` argument to set the project title independently from the directory name. This allows creating projects with custom titles, including when using `name = "."` to create a project in the current directory (thanks, @davidkane9, #148). This matches with `--title` addition for `quarto create project` in Quarto CLI v1.5.15.

- `quarto_use_template()` now supports using templates in another empty directory via the `dir` argument. However, the function will fail with a clear error message when used in non-empty directories, as interactive prompting is required and handled by Quarto CLI directly (requires Quarto 1.5.15+). Follow for [quarto-dev/quarto-cli#11127](https://github.com/quarto-dev/quarto-cli/issues/11127) for change with `--no-prompt` behavior in future Quarto versions.
Expand Down
3 changes: 1 addition & 2 deletions R/blog.R
Original file line number Diff line number Diff line change
Expand Up @@ -89,8 +89,7 @@
if (length(yml_values$categories) == 0) {
yml_values <- yml_values[names(yml_values) != "categories"]
}
yml_values <- as_yaml(yml_values)
yml_values <- paste0("---\n", yml_values, "---\n")
yml_values <- as_yaml_block(yml_values)

Check warning on line 92 in R/blog.R

View check run for this annotation

Codecov / codecov/patch

R/blog.R#L92

Added line #L92 was not covered by tests
yml_values
}

Expand Down
3 changes: 1 addition & 2 deletions R/metadata.R
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,6 @@ write_yaml_metadata_block <- function(..., .list = NULL) {
if (length(meta) == 0) {
return()
}
res <- as_yaml(meta)
yaml_block <- paste0("---\n", res, "---\n")
yaml_block <- as_yaml_block(meta)
knitr::asis_output(yaml_block)
}
106 changes: 106 additions & 0 deletions R/spin.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
#' Add spin preamble to R script
#'
#' Adds a minimal spin preamble to an R script file if one doesn't already exist.
#' The preamble includes a title derived from the filename and is formatted as
#' a YAML block suitable preprended with `#'` for [knitr::spin()].
#'
#' This is useful to prepare R scripts for use with
#' Quarto Script rendering support.
#' See <https://quarto.org/docs/computations/render-scripts.html#knitr>
#'
#' @section Preamble format:
#' For a script named `analysis.R`, the function adds this preamble by default:
#' ```
#' #' ---
#' #' title: analysis
#' #' ---
#' #'
#'
#' # Original script content starts here
#' ```
#'
#' This is the minimal preamble required for Quarto Script rendering, so that
#' [Engine Bindings](https://quarto.org/docs/computations/execution-options.html#engine-binding) works.
#'
#' @param script Path to the R script file
#' @param title Custom title for the preamble. If provided, overrides any title
#' in the `preamble` list. If NULL, uses `preamble$title` or filename as fallback.
#' @param preamble Named list of YAML metadata to include in preamble.
#' The `title` parameter takes precedence over `preamble$title` if both are provided.
#' @return Invisibly returns the script path if modified, otherwise invisible NULL
#'
#' @examples
#' \dontrun{
#' # Basic usage with default title
#' add_spin_preamble("analysis.R")
#'
#' # Custom title
#' add_spin_preamble("analysis.R", title = "My Analysis")
#'
#' # Custom preamble with multiple fields
#' add_spin_preamble("analysis.R", preamble = list(
#' title = "Advanced Analysis",
#' author = "John Doe",
#' date = Sys.Date(),
#' format = "html"
#' ))
#'
#' # Title parameter overrides preamble title
#' add_spin_preamble("analysis.R",
#' title = "Final Title", # This takes precedence
#' preamble = list(
#' title = "Ignored Title",
#' author = "John Doe"
#' )
#' )
#' }
#' @export
add_spin_preamble <- function(script, title = NULL, preamble = NULL) {
if (!fs::file_exists(script)) {
cli::cli_abort(c(
"File {.file {script}} does not exist.",
"Please provide a valid file path."
))
}

content <- xfun::read_utf8(script)

# if files starts with a spin preamble, do nothing
if (grepl("^\\s*#'", content[1])) {
cli::cli_inform(c(
"File {.file {script}} already has a spin preamble.",
"No changes made. Edit manually if needed."
))
return(invisible())
}

# Build preamble metadata
metadata <- list()

# Start with preamble list if provided
if (!is.null(preamble)) {
if (!is.list(preamble)) {
cli::cli_abort("`preamble` must be a named list.")
}
metadata <- preamble
}

# Add or override title
if (!is.null(title)) {
metadata$title <- title
} else if (is.null(metadata$title)) {
# Use filename as default title if none provided
metadata$title <- fs::path_file(fs::path_ext_remove(script))
}

preamble_text <- paste(
"#'",
xfun::split_lines(as_yaml_block(metadata))
)

new_content <- c(preamble_text, "", content)
xfun::write_utf8(new_content, con = script)

cli::cli_inform("Added spin preamble to {.file {script}}")
return(invisible(script))
}
6 changes: 6 additions & 0 deletions R/utils.R
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,12 @@ write_yaml <- function(x, file) {
yaml::write_yaml(x, file, handlers = yaml_handlers)
}

as_yaml_block <- function(x) {
# Convert to YAML and wrap in a block
yaml_content <- as_yaml(x)
paste0("---\n", yaml_content, "---\n")
}


# inline knitr:::merge_list()
merge_list <- function(x, y) {
Expand Down
1 change: 1 addition & 0 deletions _pkgdown.yml
Original file line number Diff line number Diff line change
Expand Up @@ -68,3 +68,4 @@ reference:
These functions are used to help with Quarto documents and projects:
contents:
- write_yaml_metadata_block
- add_spin_preamble
72 changes: 72 additions & 0 deletions man/add_spin_preamble.Rd

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

17 changes: 17 additions & 0 deletions tests/testthat/_snaps/spin.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# add_spin_preamble checks for file existence

Code
add_spin_preamble("non_existent_file.R")
Condition
Error in `add_spin_preamble()`:
! File 'non_existent_file.R' does not exist.
Please provide a valid file path.

# add_spin_preamble validates preamble argument

Code
add_spin_preamble(tmp_file, preamble = "not a list")
Condition
Error in `add_spin_preamble()`:
! `preamble` must be a named list.

9 changes: 9 additions & 0 deletions tests/testthat/_snaps/spin/spin_preamble-custom-preamble.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#' ---
#' title: My Report
#' author: John Doe
#' format: html
#' ---
#'

library(ggplot2)
plot(1:10)
7 changes: 7 additions & 0 deletions tests/testthat/_snaps/spin/spin_preamble-custom-title.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#' ---
#' title: Custom Analysis
#' ---
#'

x <- 1
y <- 2
6 changes: 6 additions & 0 deletions tests/testthat/_snaps/spin/spin_preamble-empty.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#' ---
#' title: report
#' ---
#'


7 changes: 7 additions & 0 deletions tests/testthat/_snaps/spin/spin_preamble-preamble-title.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#' ---
#' title: Preamble Title
#' author: Jane Doe
#' ---
#'

x <- 1
7 changes: 7 additions & 0 deletions tests/testthat/_snaps/spin/spin_preamble-title-override.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#' ---
#' title: Override Title
#' author: John Doe
#' ---
#'

x <- 1
7 changes: 7 additions & 0 deletions tests/testthat/_snaps/spin/spin_preamble.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#' ---
#' title: report
#' ---
#'

x <- 1
y <- 2
Loading