From bec750e167ed6fc8eebe3e4a23a8e3c7fc0f4aab Mon Sep 17 00:00:00 2001 From: topepo Date: Fri, 12 Apr 2024 14:25:38 -0400 Subject: [PATCH 01/29] initial version of new_blog_post --- DESCRIPTION | 2 ++ NAMESPACE | 1 + R/new-blog-post.R | 80 ++++++++++++++++++++++++++++++++++++++++++++ man/new_blog_post.Rd | 44 ++++++++++++++++++++++++ 4 files changed, 127 insertions(+) create mode 100644 R/new-blog-post.R create mode 100644 man/new_blog_post.Rd diff --git a/DESCRIPTION b/DESCRIPTION index 4259b018..67732d8f 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -18,6 +18,7 @@ Depends: R (>= 3.6) Imports: cli, + fs, jsonlite, later, processx, @@ -26,6 +27,7 @@ Imports: rstudioapi, tools, utils, + whoami, yaml Suggests: curl, diff --git a/NAMESPACE b/NAMESPACE index 9e9fa9fc..dfaa8000 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -1,6 +1,7 @@ # Generated by roxygen2: do not edit by hand export(is_using_quarto) +export(new_blog_post) export(quarto_add_extension) export(quarto_binary_sitrep) export(quarto_create_project) diff --git a/R/new-blog-post.R b/R/new-blog-post.R new file mode 100644 index 00000000..600e0473 --- /dev/null +++ b/R/new-blog-post.R @@ -0,0 +1,80 @@ +#' Create a new blog post +#' +#' @param title A character string for the title of the post. It is converted +#' to title case via [tools::toTitleCase()]. +#' @param dest A character string (or NULL) for the path within `posts`. By +#' default, the title is adapted as the directory name. +#' @param open A logical: have the default editor open a window to edit the +#' `index.qmd` file? +#' @param call A call object for reporting errors. +#' @param ... A named list of values to be added to the yaml header, such as +#' `description`, `author`, `categories`, etc. +#' @return The path to the index file. +#' @export +#' @examples +#' \dontrun{ +#' \donttest{ +#' new_blog_post("making quarto blog posts", categories = c("R")) +#' +#' } +#' } +#' +new_blog_post <- function(title, dest = NULL, open = rlang::is_interactive(), + call = rlang::current_env(), ...) { + + if (is.null(dest)) { + # Scrub title to make directory name + dest <- gsub("[[:space:]]", "-", tolower(title)) + } + dest_path <- make_post_dir(dest, call) + post_yaml <- make_post_yaml(title, ...) + qmd_path <- write_post_yaml(post_yaml, dest_path, call) + if (open) { + file.edit(qmd_path) + } + invisible(qmd_path) +} + +make_post_dir <- function(dest, call) { + working <- fs::path_wd() + + post_path <- fs::path(working, "posts", dest) + + if (fs::dir_exists(post_path)) { + cli::cli_abort("There is already a {.code {path}} directory in 'posts/'", + call = call) + } else { + ret <- fs::dir_create(post_path) + } + ret +} + +make_post_yaml <- function(title, ...) { + default_values <- list( + title = tools::toTitleCase(title), + author = tools::toTitleCase(whoami::fullname("Your name")), + date = format(Sys.Date(), "%Y-%m-%d"), + categories = character(0) + ) + + user_values <- list(...) + + yml_values <- utils::modifyList(default_values, user_values) + if (length(yml_values$categories) == 0) { + yml_values <- yml_values[names(yml_values) != "categories"] + } + yml_values <- yaml::as.yaml(yml_values) + yml_values <- paste0("---\n", yml_values, "---\n") + yml_values +} + +write_post_yaml <- function(x, dest, call) { + dest_file <- fs::path(dest, "index.qmd") + if (fs::file_exists(dest_file)) { + cli::cli_abort("There is already am index.qmd file at {.code {path}}", + call = call) + } else { + ret <- cat(x, file = dest_file) + } + dest_file +} diff --git a/man/new_blog_post.Rd b/man/new_blog_post.Rd new file mode 100644 index 00000000..1c507ac3 --- /dev/null +++ b/man/new_blog_post.Rd @@ -0,0 +1,44 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/new-blog-post.R +\name{new_blog_post} +\alias{new_blog_post} +\title{Create a new blog post} +\usage{ +new_blog_post( + title, + dest = NULL, + open = rlang::is_interactive(), + call = rlang::current_env(), + ... +) +} +\arguments{ +\item{title}{A character string for the title of the post. It is converted +to title case via \code{\link[tools:toTitleCase]{tools::toTitleCase()}}.} + +\item{dest}{A character string (or NULL) for the path within \code{posts}. By +default, the title is adapted as the directory name.} + +\item{open}{A logical: have the default editor open a window to edit the +\code{index.qmd} file?} + +\item{call}{A call object for reporting errors.} + +\item{...}{A named list of values to be added to the yaml header, such as +\code{description}, \code{author}, \code{categories}, etc.} +} +\value{ +The path to the index file. +} +\description{ +Create a new blog post +} +\examples{ +\dontrun{ + \donttest{ +new_blog_post("making quarto blog posts", categories = c("R")) + + } +} + +} From b41f130322e5928964e2dc9ed8856dd571826fbe Mon Sep 17 00:00:00 2001 From: topepo Date: Fri, 12 Apr 2024 14:29:33 -0400 Subject: [PATCH 02/29] add namespace to call --- R/new-blog-post.R | 4 +++- man/new_blog_post.Rd | 2 +- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/R/new-blog-post.R b/R/new-blog-post.R index 600e0473..0c4b0b27 100644 --- a/R/new-blog-post.R +++ b/R/new-blog-post.R @@ -1,5 +1,7 @@ #' Create a new blog post #' +#' Creates (and potentially opens) the `index.qmd` file for a new blog post. +#' #' @param title A character string for the title of the post. It is converted #' to title case via [tools::toTitleCase()]. #' @param dest A character string (or NULL) for the path within `posts`. By @@ -30,7 +32,7 @@ new_blog_post <- function(title, dest = NULL, open = rlang::is_interactive(), post_yaml <- make_post_yaml(title, ...) qmd_path <- write_post_yaml(post_yaml, dest_path, call) if (open) { - file.edit(qmd_path) + utils::file.edit(qmd_path) } invisible(qmd_path) } diff --git a/man/new_blog_post.Rd b/man/new_blog_post.Rd index 1c507ac3..175935c9 100644 --- a/man/new_blog_post.Rd +++ b/man/new_blog_post.Rd @@ -31,7 +31,7 @@ default, the title is adapted as the directory name.} The path to the index file. } \description{ -Create a new blog post +Creates (and potentially opens) the \code{index.qmd} file for a new blog post. } \examples{ \dontrun{ From a8e7d13dc4f6e1b0ae8037038ec15b98068db58b Mon Sep 17 00:00:00 2001 From: topepo Date: Fri, 12 Apr 2024 15:12:18 -0400 Subject: [PATCH 03/29] initial unit tests --- R/new-blog-post.R | 2 +- tests/testthat/_snaps/new-blog-post.md | 8 ++++ tests/testthat/test-new-blog-post.R | 57 ++++++++++++++++++++++++++ 3 files changed, 66 insertions(+), 1 deletion(-) create mode 100644 tests/testthat/_snaps/new-blog-post.md create mode 100644 tests/testthat/test-new-blog-post.R diff --git a/R/new-blog-post.R b/R/new-blog-post.R index 0c4b0b27..ed40ed46 100644 --- a/R/new-blog-post.R +++ b/R/new-blog-post.R @@ -43,7 +43,7 @@ make_post_dir <- function(dest, call) { post_path <- fs::path(working, "posts", dest) if (fs::dir_exists(post_path)) { - cli::cli_abort("There is already a {.code {path}} directory in 'posts/'", + cli::cli_abort("There is already a {.code {dest}} directory in 'posts/'", call = call) } else { ret <- fs::dir_create(post_path) diff --git a/tests/testthat/_snaps/new-blog-post.md b/tests/testthat/_snaps/new-blog-post.md new file mode 100644 index 00000000..0ded61f9 --- /dev/null +++ b/tests/testthat/_snaps/new-blog-post.md @@ -0,0 +1,8 @@ +# Create a blog post + + Code + new_blog_post("Intro to Felt Surrogacy", data = "1999-12-31", open = FALSE) + Condition + Error in `new_blog_post()`: + ! There is already a `intro-to-felt-surrogacy` directory in 'posts/' + diff --git a/tests/testthat/test-new-blog-post.R b/tests/testthat/test-new-blog-post.R new file mode 100644 index 00000000..f3f97447 --- /dev/null +++ b/tests/testthat/test-new-blog-post.R @@ -0,0 +1,57 @@ +test_that("Create a blog post", { + skip_if_no_quarto("1.4") + + tempdir <- withr::local_tempdir() + withr::local_dir(tempdir) + quarto_create_project(name = "test-blog-project", type = "blog", + dir = tempdir(), quiet = TRUE) + + # ------------------------------------------------------------------------------ + + post_1 <- new_blog_post("Intro to Felt Surrogacy", date = "March 25, 2010", + open = FALSE) + expect_true(fs::file_exists(post_1)) + expect_equal(fs::path_file(post_1), "index.qmd") + + post_1_dir <- fs::path_split(post_1)[[1]] + post_1_dir <- post_1_dir[length(post_1_dir) - 1] + expect_equal(post_1_dir, "intro-to-felt-surrogacy") + + post_1_content <- readLines(post_1) + post_1_content <- paste0(post_1_content, collapse = "\n") + expect_equal( + post_1_content, + "---\ntitle: Intro to Felt Surrogacy\nauthor: Max Kuhn\ndate: March 25, 2010\n---" + ) + + # ------------------------------------------------------------------------------ + + expect_snapshot( + new_blog_post("Intro to Felt Surrogacy", data = "1999-12-31", open = FALSE), + error = TRUE + ) + + # ------------------------------------------------------------------------------ + + post_2 <- + new_blog_post( + "Intro to Felt Surrogacy", + dest = "The Science of Illusion", + author = "Annie Edison", + categories = c("shenanigans", "security"), + open = FALSE) + + expect_true(fs::file_exists(post_2)) + expect_equal(fs::path_file(post_2), "index.qmd") + + post_2_dir <- fs::path_split(post_2)[[1]] + post_2_dir <- post_2_dir[length(post_2_dir) - 1] + expect_equal(post_2_dir, "The Science of Illusion") + + post_2_content <- readLines(post_2) + post_2_exp <- c( + "---", "title: Intro to Felt Surrogacy", "author: Annie Edison", + "date: '2024-04-12'", "categories:", "- shenanigans", "- security", "---") + expect_equal(post_2_content, post_2_exp) +}) + From ad0a01b89e54d81b8be5521d9b816b494be7a409 Mon Sep 17 00:00:00 2001 From: topepo Date: Fri, 12 Apr 2024 15:27:00 -0400 Subject: [PATCH 04/29] news file update related to #22 --- NEWS.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/NEWS.md b/NEWS.md index 3e1f13e9..ccb46fa6 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,5 +1,7 @@ # quarto (development version) +- Added a `new_blog_post()` function (#22). + # quarto 1.4 - This version is now adapted to Quarto 1.4 latest stable release. From 56be9fb75697ec6064e9ace045b94bb419b1ecd7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=98topepo=E2=80=99?= <‘mxkuhn@gmail.com’> Date: Tue, 16 Apr 2024 09:32:47 -0400 Subject: [PATCH 05/29] use test fixtures --- tests/testthat/test-new-blog-post.R | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/tests/testthat/test-new-blog-post.R b/tests/testthat/test-new-blog-post.R index f3f97447..72204f36 100644 --- a/tests/testthat/test-new-blog-post.R +++ b/tests/testthat/test-new-blog-post.R @@ -1,10 +1,18 @@ test_that("Create a blog post", { skip_if_no_quarto("1.4") - tempdir <- withr::local_tempdir() - withr::local_dir(tempdir) + current_dir <- getwd() + + temp_dir <- withr::local_tempdir() + dir_path <- fs::path(temp_dir, "test-blog-project") + + withr::defer(fs::dir_delete(dir_path), envir = rlang::current_env()) + quarto_create_project(name = "test-blog-project", type = "blog", - dir = tempdir(), quiet = TRUE) + dir = temp_dir, quiet = TRUE) + + setwd(dir_path) + withr::defer(setwd(current_dir), envir = rlang::current_env()) # ------------------------------------------------------------------------------ @@ -38,6 +46,7 @@ test_that("Create a blog post", { "Intro to Felt Surrogacy", dest = "The Science of Illusion", author = "Annie Edison", + date = '2024-04-12', categories = c("shenanigans", "security"), open = FALSE) From 0f2942daecf0d97cf73046559a8ebeda5810523e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=98topepo=E2=80=99?= <‘mxkuhn@gmail.com’> Date: Thu, 18 Apr 2024 11:14:42 -0400 Subject: [PATCH 06/29] set env var for testing --- tests/testthat/test-new-blog-post.R | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/testthat/test-new-blog-post.R b/tests/testthat/test-new-blog-post.R index 72204f36..93a9b46b 100644 --- a/tests/testthat/test-new-blog-post.R +++ b/tests/testthat/test-new-blog-post.R @@ -14,6 +14,8 @@ test_that("Create a blog post", { setwd(dir_path) withr::defer(setwd(current_dir), envir = rlang::current_env()) + Sys.setenv(FULLNAME="Max Kuhn") + # ------------------------------------------------------------------------------ post_1 <- new_blog_post("Intro to Felt Surrogacy", date = "March 25, 2010", From cc2adcf1c5ccf624b78da4bdb237ad86c4a2c22a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E2=80=98topepo=E2=80=99?= <‘mxkuhn@gmail.com’> Date: Wed, 17 Jul 2024 21:02:20 -0400 Subject: [PATCH 07/29] conditionally use whoami --- DESCRIPTION | 2 +- R/new-blog-post.R | 1 + tests/testthat/test-new-blog-post.R | 1 + 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/DESCRIPTION b/DESCRIPTION index e97d593f..f89a5bed 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -27,7 +27,6 @@ Imports: rstudioapi, tools, utils, - whoami, yaml Suggests: curl, @@ -35,6 +34,7 @@ Suggests: rsconnect (>= 0.8.26), testthat (>= 3.1.7), withr, + whoami, xfun VignetteBuilder: quarto diff --git a/R/new-blog-post.R b/R/new-blog-post.R index ed40ed46..058e5540 100644 --- a/R/new-blog-post.R +++ b/R/new-blog-post.R @@ -23,6 +23,7 @@ #' new_blog_post <- function(title, dest = NULL, open = rlang::is_interactive(), call = rlang::current_env(), ...) { + rlang::check_installed("whoami") if (is.null(dest)) { # Scrub title to make directory name diff --git a/tests/testthat/test-new-blog-post.R b/tests/testthat/test-new-blog-post.R index 93a9b46b..d805e2e0 100644 --- a/tests/testthat/test-new-blog-post.R +++ b/tests/testthat/test-new-blog-post.R @@ -1,5 +1,6 @@ test_that("Create a blog post", { skip_if_no_quarto("1.4") + skip_if_not_installed("whoami") current_dir <- getwd() From dbc286c10317152a724c8fccf3c0a9147565d72f Mon Sep 17 00:00:00 2001 From: Christophe Dervieux Date: Tue, 10 Jun 2025 14:25:10 +0200 Subject: [PATCH 08/29] Rename file and reformat --- R/{new-blog-post.R => blog.R} | 21 +++++++++++++++------ man/new_blog_post.Rd | 2 +- 2 files changed, 16 insertions(+), 7 deletions(-) rename R/{new-blog-post.R => blog.R} (85%) diff --git a/R/new-blog-post.R b/R/blog.R similarity index 85% rename from R/new-blog-post.R rename to R/blog.R index 058e5540..35e1fb61 100644 --- a/R/new-blog-post.R +++ b/R/blog.R @@ -21,8 +21,13 @@ #' } #' } #' -new_blog_post <- function(title, dest = NULL, open = rlang::is_interactive(), - call = rlang::current_env(), ...) { +new_blog_post <- function( + title, + dest = NULL, + open = rlang::is_interactive(), + call = rlang::current_env(), + ... +) { rlang::check_installed("whoami") if (is.null(dest)) { @@ -44,8 +49,10 @@ make_post_dir <- function(dest, call) { post_path <- fs::path(working, "posts", dest) if (fs::dir_exists(post_path)) { - cli::cli_abort("There is already a {.code {dest}} directory in 'posts/'", - call = call) + cli::cli_abort( + "There is already a {.code {dest}} directory in 'posts/'", + call = call + ) } else { ret <- fs::dir_create(post_path) } @@ -74,8 +81,10 @@ make_post_yaml <- function(title, ...) { write_post_yaml <- function(x, dest, call) { dest_file <- fs::path(dest, "index.qmd") if (fs::file_exists(dest_file)) { - cli::cli_abort("There is already am index.qmd file at {.code {path}}", - call = call) + cli::cli_abort( + "There is already am index.qmd file at {.code {path}}", + call = call + ) } else { ret <- cat(x, file = dest_file) } diff --git a/man/new_blog_post.Rd b/man/new_blog_post.Rd index 175935c9..460b65f3 100644 --- a/man/new_blog_post.Rd +++ b/man/new_blog_post.Rd @@ -1,5 +1,5 @@ % Generated by roxygen2: do not edit by hand -% Please edit documentation in R/new-blog-post.R +% Please edit documentation in R/blog.R \name{new_blog_post} \alias{new_blog_post} \title{Create a new blog post} From be42dbd775f47907aa998e525d623062287bb61d Mon Sep 17 00:00:00 2001 From: Christophe Dervieux Date: Tue, 10 Jun 2025 15:06:12 +0200 Subject: [PATCH 09/29] let's use .call like other places in this package --- R/blog.R | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/R/blog.R b/R/blog.R index 35e1fb61..94403174 100644 --- a/R/blog.R +++ b/R/blog.R @@ -25,7 +25,7 @@ new_blog_post <- function( title, dest = NULL, open = rlang::is_interactive(), - call = rlang::current_env(), + .call = rlang::current_env(), ... ) { rlang::check_installed("whoami") @@ -34,16 +34,16 @@ new_blog_post <- function( # Scrub title to make directory name dest <- gsub("[[:space:]]", "-", tolower(title)) } - dest_path <- make_post_dir(dest, call) + dest_path <- make_post_dir(dest, .call) post_yaml <- make_post_yaml(title, ...) - qmd_path <- write_post_yaml(post_yaml, dest_path, call) + qmd_path <- write_post_yaml(post_yaml, dest_path, .call) if (open) { utils::file.edit(qmd_path) } invisible(qmd_path) } -make_post_dir <- function(dest, call) { +make_post_dir <- function(dest, .call) { working <- fs::path_wd() post_path <- fs::path(working, "posts", dest) @@ -51,7 +51,7 @@ make_post_dir <- function(dest, call) { if (fs::dir_exists(post_path)) { cli::cli_abort( "There is already a {.code {dest}} directory in 'posts/'", - call = call + call = .call ) } else { ret <- fs::dir_create(post_path) @@ -78,12 +78,12 @@ make_post_yaml <- function(title, ...) { yml_values } -write_post_yaml <- function(x, dest, call) { +write_post_yaml <- function(x, dest, .call) { dest_file <- fs::path(dest, "index.qmd") if (fs::file_exists(dest_file)) { cli::cli_abort( "There is already am index.qmd file at {.code {path}}", - call = call + call = .call ) } else { ret <- cat(x, file = dest_file) From 0722da05ff5b2e35e153541680311e839fb1e530 Mon Sep 17 00:00:00 2001 From: Christophe Dervieux Date: Tue, 10 Jun 2025 15:08:33 +0200 Subject: [PATCH 10/29] leverage usethis if it is installed to open the file --- R/blog.R | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/R/blog.R b/R/blog.R index 94403174..b372f34b 100644 --- a/R/blog.R +++ b/R/blog.R @@ -38,7 +38,13 @@ new_blog_post <- function( post_yaml <- make_post_yaml(title, ...) qmd_path <- write_post_yaml(post_yaml, dest_path, .call) if (open) { - utils::file.edit(qmd_path) + edit_file <- utils::file.edit + if ( + rlang::is_installed("usethis") && rlang::is_callable(usethis::edit_file) + ) { + edit_file <- getFromNamespace("edit_file", "usethis") + } + edit_file(qmd_path) } invisible(qmd_path) } From 08d1bad52508968020969776faab0f3b63180fec Mon Sep 17 00:00:00 2001 From: Christophe Dervieux Date: Tue, 10 Jun 2025 15:24:14 +0200 Subject: [PATCH 11/29] xfun is an import --- DESCRIPTION | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/DESCRIPTION b/DESCRIPTION index b410ab75..bf8b520e 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -28,6 +28,7 @@ Imports: rstudioapi, tools, utils, + xfun, yaml Suggests: bslib, @@ -49,8 +50,7 @@ Suggests: thematic, tidyverse, withr, - whoami, - xfun + whoami VignetteBuilder: quarto Config/testthat/edition: 3 From a049e0344fd8c1fd006522b862317eb5c8af2a94 Mon Sep 17 00:00:00 2001 From: Christophe Dervieux Date: Tue, 10 Jun 2025 15:24:33 +0200 Subject: [PATCH 12/29] use .file iniline markup --- R/blog.R | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/R/blog.R b/R/blog.R index b372f34b..102e4f1a 100644 --- a/R/blog.R +++ b/R/blog.R @@ -56,7 +56,7 @@ make_post_dir <- function(dest, .call) { if (fs::dir_exists(post_path)) { cli::cli_abort( - "There is already a {.code {dest}} directory in 'posts/'", + "There is already a {.file {dest}} directory in 'posts/'", call = .call ) } else { From e2d1c99ef2e0930a0873c9c2b8a48be2aa559e79 Mon Sep 17 00:00:00 2001 From: Christophe Dervieux Date: Tue, 10 Jun 2025 15:25:30 +0200 Subject: [PATCH 13/29] Add as_yaml to use same handler as write_yaml --- R/blog.R | 4 ++-- R/utils.R | 26 +++++++++++++++++--------- 2 files changed, 19 insertions(+), 11 deletions(-) diff --git a/R/blog.R b/R/blog.R index 102e4f1a..c689dd5f 100644 --- a/R/blog.R +++ b/R/blog.R @@ -79,7 +79,7 @@ make_post_yaml <- function(title, ...) { if (length(yml_values$categories) == 0) { yml_values <- yml_values[names(yml_values) != "categories"] } - yml_values <- yaml::as.yaml(yml_values) + yml_values <- as_yaml(yml_values) yml_values <- paste0("---\n", yml_values, "---\n") yml_values } @@ -92,7 +92,7 @@ write_post_yaml <- function(x, dest, .call) { call = .call ) } else { - ret <- cat(x, file = dest_file) + ret <- xfun::write_utf8(x, con = dest_file) } dest_file } diff --git a/R/utils.R b/R/utils.R index 476048e8..2fdfd689 100644 --- a/R/utils.R +++ b/R/utils.R @@ -3,17 +3,25 @@ relative_to_wd <- function(path) { rmarkdown::relative_to(getwd(), path) } +# Specific YAML handlers +# as quarto expects YAML 1.2 and yaml R package supports 1.1 +yaml_handlers <- list( + # Handle yes/no from 1.1 to 1.2 + # https://github.com/vubiostat/r-yaml/issues/131 + logical = function(x) { + value <- ifelse(x, "true", "false") + structure(value, class = "verbatim") + } +) + +#' @importFrom yaml as_yaml +as_yaml <- function(x) { + yaml::as.yaml(x, handlers = yaml_handlers) +} + #' @importFrom yaml write_yaml write_yaml <- function(x, file) { - handlers <- list( - # Handle yes/no from 1.1 to 1.2 - # https://github.com/vubiostat/r-yaml/issues/131 - logical = function(x) { - value <- ifelse(x, "true", "false") - structure(value, class = "verbatim") - } - ) - yaml::write_yaml(x, file, handlers = handlers) + yaml::write_yaml(x, file, handlers = yaml_handlers) } From 380f65b76d223f491858bba23c9f7890a6d2ea2b Mon Sep 17 00:00:00 2001 From: Christophe Dervieux Date: Tue, 10 Jun 2025 15:27:38 +0200 Subject: [PATCH 14/29] Revert "let's use .call like other places in this package" This reverts commit be42dbd775f47907aa998e525d623062287bb61d. --- R/blog.R | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/R/blog.R b/R/blog.R index c689dd5f..a2849458 100644 --- a/R/blog.R +++ b/R/blog.R @@ -25,7 +25,7 @@ new_blog_post <- function( title, dest = NULL, open = rlang::is_interactive(), - .call = rlang::current_env(), + call = rlang::current_env(), ... ) { rlang::check_installed("whoami") @@ -34,9 +34,9 @@ new_blog_post <- function( # Scrub title to make directory name dest <- gsub("[[:space:]]", "-", tolower(title)) } - dest_path <- make_post_dir(dest, .call) + dest_path <- make_post_dir(dest, call) post_yaml <- make_post_yaml(title, ...) - qmd_path <- write_post_yaml(post_yaml, dest_path, .call) + qmd_path <- write_post_yaml(post_yaml, dest_path, call) if (open) { edit_file <- utils::file.edit if ( @@ -49,7 +49,7 @@ new_blog_post <- function( invisible(qmd_path) } -make_post_dir <- function(dest, .call) { +make_post_dir <- function(dest, call) { working <- fs::path_wd() post_path <- fs::path(working, "posts", dest) @@ -57,7 +57,7 @@ make_post_dir <- function(dest, .call) { if (fs::dir_exists(post_path)) { cli::cli_abort( "There is already a {.file {dest}} directory in 'posts/'", - call = .call + call = call ) } else { ret <- fs::dir_create(post_path) @@ -84,12 +84,12 @@ make_post_yaml <- function(title, ...) { yml_values } -write_post_yaml <- function(x, dest, .call) { +write_post_yaml <- function(x, dest, call) { dest_file <- fs::path(dest, "index.qmd") if (fs::file_exists(dest_file)) { cli::cli_abort( "There is already am index.qmd file at {.code {path}}", - call = .call + call = call ) } else { ret <- xfun::write_utf8(x, con = dest_file) From e3a7edd8501a77940727f9fa36a5d496c0e60b71 Mon Sep 17 00:00:00 2001 From: Christophe Dervieux Date: Tue, 10 Jun 2025 15:30:00 +0200 Subject: [PATCH 15/29] fixup YAML importFrom --- NAMESPACE | 1 + R/utils.R | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/NAMESPACE b/NAMESPACE index 2f3dd068..f51f5a2c 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -43,4 +43,5 @@ importFrom(rstudioapi,isAvailable) importFrom(rstudioapi,viewer) importFrom(tools,vignetteEngine) importFrom(utils,browseURL) +importFrom(yaml,as.yaml) importFrom(yaml,write_yaml) diff --git a/R/utils.R b/R/utils.R index 2fdfd689..7fdb6572 100644 --- a/R/utils.R +++ b/R/utils.R @@ -14,7 +14,7 @@ yaml_handlers <- list( } ) -#' @importFrom yaml as_yaml +#' @importFrom yaml as.yaml as_yaml <- function(x) { yaml::as.yaml(x, handlers = yaml_handlers) } From 7ed3c8916631423fe346b0f1357b59b6300acffc Mon Sep 17 00:00:00 2001 From: Christophe Dervieux Date: Tue, 10 Jun 2025 15:30:33 +0200 Subject: [PATCH 16/29] inherits call doc from rlang --- R/blog.R | 2 +- man/new_blog_post.Rd | 5 ++++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/R/blog.R b/R/blog.R index a2849458..ad0653ae 100644 --- a/R/blog.R +++ b/R/blog.R @@ -2,13 +2,13 @@ #' #' Creates (and potentially opens) the `index.qmd` file for a new blog post. #' +#' @inheritParams rlang::args_error_context #' @param title A character string for the title of the post. It is converted #' to title case via [tools::toTitleCase()]. #' @param dest A character string (or NULL) for the path within `posts`. By #' default, the title is adapted as the directory name. #' @param open A logical: have the default editor open a window to edit the #' `index.qmd` file? -#' @param call A call object for reporting errors. #' @param ... A named list of values to be added to the yaml header, such as #' `description`, `author`, `categories`, etc. #' @return The path to the index file. diff --git a/man/new_blog_post.Rd b/man/new_blog_post.Rd index 460b65f3..88aa2231 100644 --- a/man/new_blog_post.Rd +++ b/man/new_blog_post.Rd @@ -22,7 +22,10 @@ default, the title is adapted as the directory name.} \item{open}{A logical: have the default editor open a window to edit the \code{index.qmd} file?} -\item{call}{A call object for reporting errors.} +\item{call}{The execution environment of a currently +running function, e.g. \code{caller_env()}. The function will be +mentioned in error messages as the source of the error. See the +\code{call} argument of \code{\link[rlang:abort]{abort()}} for more information.} \item{...}{A named list of values to be added to the yaml header, such as \code{description}, \code{author}, \code{categories}, etc.} From 36d05c087decd8e0444adeff9f3ca29296e4804f Mon Sep 17 00:00:00 2001 From: Christophe Dervieux Date: Tue, 10 Jun 2025 15:31:36 +0200 Subject: [PATCH 17/29] use internal merge_list --- R/blog.R | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/R/blog.R b/R/blog.R index ad0653ae..e2ee9b09 100644 --- a/R/blog.R +++ b/R/blog.R @@ -75,7 +75,7 @@ make_post_yaml <- function(title, ...) { user_values <- list(...) - yml_values <- utils::modifyList(default_values, user_values) + yml_values <- merge_list(default_values, user_values) if (length(yml_values$categories) == 0) { yml_values <- yml_values[names(yml_values) != "categories"] } From 34c52aff1e35a4457d396c8904c5440458f81f96 Mon Sep 17 00:00:00 2001 From: Christophe Dervieux Date: Tue, 10 Jun 2025 15:34:21 +0200 Subject: [PATCH 18/29] document usage of `whoami` --- R/blog.R | 4 +++- man/new_blog_post.Rd | 4 +++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/R/blog.R b/R/blog.R index e2ee9b09..2e58953c 100644 --- a/R/blog.R +++ b/R/blog.R @@ -10,7 +10,9 @@ #' @param open A logical: have the default editor open a window to edit the #' `index.qmd` file? #' @param ... A named list of values to be added to the yaml header, such as -#' `description`, `author`, `categories`, etc. +#' `date`, `author`, `categories`, `description`, etc. +#' If no `date` is provided, the current date is used. +#' If no `author` is provided, `whoami::fullname()` is used to get the user's name. #' @return The path to the index file. #' @export #' @examples diff --git a/man/new_blog_post.Rd b/man/new_blog_post.Rd index 88aa2231..08f1b115 100644 --- a/man/new_blog_post.Rd +++ b/man/new_blog_post.Rd @@ -28,7 +28,9 @@ mentioned in error messages as the source of the error. See the \code{call} argument of \code{\link[rlang:abort]{abort()}} for more information.} \item{...}{A named list of values to be added to the yaml header, such as -\code{description}, \code{author}, \code{categories}, etc.} +\code{date}, \code{author}, \code{categories}, \code{description}, etc. +If no \code{date} is provided, the current date is used. +If no \code{author} is provided, \code{whoami::fullname()} is used to get the user's name.} } \value{ The path to the index file. From 8305306f7237f036746668db71d5477c95f0c28b Mon Sep 17 00:00:00 2001 From: Christophe Dervieux Date: Tue, 10 Jun 2025 15:34:59 +0200 Subject: [PATCH 19/29] fixup rename test file --- tests/testthat/{test-new-blog-post.R => test-blog.R} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename tests/testthat/{test-new-blog-post.R => test-blog.R} (100%) diff --git a/tests/testthat/test-new-blog-post.R b/tests/testthat/test-blog.R similarity index 100% rename from tests/testthat/test-new-blog-post.R rename to tests/testthat/test-blog.R From 3045268df58db271adba91d6ddbf847dd29ef1e0 Mon Sep 17 00:00:00 2001 From: Christophe Dervieux Date: Tue, 10 Jun 2025 17:18:18 +0200 Subject: [PATCH 20/29] Update test --- tests/testthat/_snaps/blog.md | 8 +++++ tests/testthat/test-blog.R | 64 ++++++++++++++++------------------- 2 files changed, 37 insertions(+), 35 deletions(-) create mode 100644 tests/testthat/_snaps/blog.md diff --git a/tests/testthat/_snaps/blog.md b/tests/testthat/_snaps/blog.md new file mode 100644 index 00000000..b17d62c9 --- /dev/null +++ b/tests/testthat/_snaps/blog.md @@ -0,0 +1,8 @@ +# Create a blog post + + Code + new_blog_post("Intro to Felt Surrogacy", data = "1999-12-31", open = FALSE) + Condition + Error in `new_blog_post()`: + ! There is already a 'intro-to-felt-surrogacy' directory in 'posts/' + diff --git a/tests/testthat/test-blog.R b/tests/testthat/test-blog.R index d805e2e0..c8035afc 100644 --- a/tests/testthat/test-blog.R +++ b/tests/testthat/test-blog.R @@ -2,38 +2,35 @@ test_that("Create a blog post", { skip_if_no_quarto("1.4") skip_if_not_installed("whoami") - current_dir <- getwd() - - temp_dir <- withr::local_tempdir() - dir_path <- fs::path(temp_dir, "test-blog-project") - - withr::defer(fs::dir_delete(dir_path), envir = rlang::current_env()) - - quarto_create_project(name = "test-blog-project", type = "blog", - dir = temp_dir, quiet = TRUE) - - setwd(dir_path) - withr::defer(setwd(current_dir), envir = rlang::current_env()) + dir_path <- withr::local_tempdir(pattern = "test-blog-project-") + withr::local_dir(dir_path) + + quarto_create_project( + name = "test-blog-project", + type = "blog", + dir = dir_path, + quiet = TRUE, + no_prompt = TRUE + ) - Sys.setenv(FULLNAME="Max Kuhn") + withr::local_envvar(list(FULLNAME = "Max Kuhn")) # ------------------------------------------------------------------------------ - post_1 <- new_blog_post("Intro to Felt Surrogacy", date = "March 25, 2010", - open = FALSE) + post_1 <- new_blog_post( + "Intro to Felt Surrogacy", + date = "March 25, 2010", + open = FALSE + ) expect_true(fs::file_exists(post_1)) expect_equal(fs::path_file(post_1), "index.qmd") - post_1_dir <- fs::path_split(post_1)[[1]] - post_1_dir <- post_1_dir[length(post_1_dir) - 1] - expect_equal(post_1_dir, "intro-to-felt-surrogacy") + expect_equal(fs::path_file(fs::path_dir(post_1)), "intro-to-felt-surrogacy") - post_1_content <- readLines(post_1) - post_1_content <- paste0(post_1_content, collapse = "\n") - expect_equal( - post_1_content, - "---\ntitle: Intro to Felt Surrogacy\nauthor: Max Kuhn\ndate: March 25, 2010\n---" - ) + post_1_content <- rmarkdown::yaml_front_matter(post_1) + expect_equal(post_1_content$title, "Intro to Felt Surrogacy") + expect_equal(post_1_content$author, "Max Kuhn") + expect_equal(post_1_content$date, "March 25, 2010") # ------------------------------------------------------------------------------ @@ -51,19 +48,16 @@ test_that("Create a blog post", { author = "Annie Edison", date = '2024-04-12', categories = c("shenanigans", "security"), - open = FALSE) + open = FALSE + ) expect_true(fs::file_exists(post_2)) expect_equal(fs::path_file(post_2), "index.qmd") + expect_equal(fs::path_file(fs::path_dir(post_2)), "The Science of Illusion") - post_2_dir <- fs::path_split(post_2)[[1]] - post_2_dir <- post_2_dir[length(post_2_dir) - 1] - expect_equal(post_2_dir, "The Science of Illusion") - - post_2_content <- readLines(post_2) - post_2_exp <- c( - "---", "title: Intro to Felt Surrogacy", "author: Annie Edison", - "date: '2024-04-12'", "categories:", "- shenanigans", "- security", "---") - expect_equal(post_2_content, post_2_exp) + post_2_content <- rmarkdown::yaml_front_matter(post_2) + expect_equal(post_2_content$title, "Intro to Felt Surrogacy") + expect_equal(post_2_content$author, "Annie Edison") + expect_equal(post_2_content$date, "2024-04-12") + expect_equal(post_2_content$categories, c("shenanigans", "security")) }) - From 21541e02bbc32fb6893651814197e5925ed85fca Mon Sep 17 00:00:00 2001 From: Christophe Dervieux Date: Tue, 10 Jun 2025 17:23:13 +0200 Subject: [PATCH 21/29] Check that this is run in the project root directory --- R/blog.R | 8 ++++++++ tests/testthat/test-blog.R | 10 ++++++++++ 2 files changed, 18 insertions(+) diff --git a/R/blog.R b/R/blog.R index 2e58953c..e1a7bb6a 100644 --- a/R/blog.R +++ b/R/blog.R @@ -54,6 +54,14 @@ new_blog_post <- function( make_post_dir <- function(dest, call) { working <- fs::path_wd() + # is this a quarto project for blog ? Expecting _quarto.yml in working dir + if (!fs::file_exists(fs::path(working, "_quarto.yml"))) { + cli::cli_abort( + "You need to be at root of a Quarto project to create a blog post in the {.file posts/} directory.", + call = call + ) + } + post_path <- fs::path(working, "posts", dest) if (fs::dir_exists(post_path)) { diff --git a/tests/testthat/test-blog.R b/tests/testthat/test-blog.R index c8035afc..7f85580e 100644 --- a/tests/testthat/test-blog.R +++ b/tests/testthat/test-blog.R @@ -61,3 +61,13 @@ test_that("Create a blog post", { expect_equal(post_2_content$date, "2024-04-12") expect_equal(post_2_content$categories, c("shenanigans", "security")) }) + +test_that("Error if not quarto project", { + dir_path <- withr::local_tempdir(pattern = "test-blog-project-") + withr::local_dir(dir_path) + + expect_snapshot( + new_blog_post("Intro to Felt Surrogacy", open = FALSE), + error = TRUE + ) +}) From 9ee37848650d112b9ffb7635bd609e2b16cd7c25 Mon Sep 17 00:00:00 2001 From: Christophe Dervieux Date: Tue, 10 Jun 2025 17:29:45 +0200 Subject: [PATCH 22/29] Add a way to change working directory --- R/blog.R | 9 +++++---- tests/testthat/_snaps/blog.md | 17 +++++++++++++++++ tests/testthat/test-blog.R | 11 ++++++++++- 3 files changed, 32 insertions(+), 5 deletions(-) diff --git a/R/blog.R b/R/blog.R index e1a7bb6a..900ac35e 100644 --- a/R/blog.R +++ b/R/blog.R @@ -26,6 +26,7 @@ new_blog_post <- function( title, dest = NULL, + wd = NULL, open = rlang::is_interactive(), call = rlang::current_env(), ... @@ -36,7 +37,7 @@ new_blog_post <- function( # Scrub title to make directory name dest <- gsub("[[:space:]]", "-", tolower(title)) } - dest_path <- make_post_dir(dest, call) + dest_path <- make_post_dir(dest, wd, call) post_yaml <- make_post_yaml(title, ...) qmd_path <- write_post_yaml(post_yaml, dest_path, call) if (open) { @@ -51,13 +52,13 @@ new_blog_post <- function( invisible(qmd_path) } -make_post_dir <- function(dest, call) { - working <- fs::path_wd() +make_post_dir <- function(dest, wd, call) { + working <- if (is.null(wd)) fs::path_wd() else fs::path_abs(wd) # is this a quarto project for blog ? Expecting _quarto.yml in working dir if (!fs::file_exists(fs::path(working, "_quarto.yml"))) { cli::cli_abort( - "You need to be at root of a Quarto project to create a blog post in the {.file posts/} directory.", + "You need to be at root of a Quarto project to create a blog post in the {.file posts/} directory at {.file {working}}.", call = call ) } diff --git a/tests/testthat/_snaps/blog.md b/tests/testthat/_snaps/blog.md index b17d62c9..3ad941b2 100644 --- a/tests/testthat/_snaps/blog.md +++ b/tests/testthat/_snaps/blog.md @@ -6,3 +6,20 @@ Error in `new_blog_post()`: ! There is already a 'intro-to-felt-surrogacy' directory in 'posts/' +# Error if not a quarto project + + Code + new_blog_post("Intro to Felt Surrogacy", open = FALSE) + Condition + Error in `new_blog_post()`: + ! You need to be at root of a Quarto project to create a blog post in the 'posts/' directory at 'C:/Users/chris/AppData/Local/Temp/RtmpU72EnV/test-blog-project-415061be69e8'. + +--- + + Code + new_blog_post("Intro to Felt Surrogacy", wd = withr::local_tempdir(pattern = "test-blog-project-2-"), + open = FALSE) + Condition + Error in `new_blog_post()`: + ! You need to be at root of a Quarto project to create a blog post in the 'posts/' directory at 'C:/Users/chris/AppData/Local/Temp/RtmpU72EnV/test-blog-project-2-4150447c3b64'. + diff --git a/tests/testthat/test-blog.R b/tests/testthat/test-blog.R index 7f85580e..773d8904 100644 --- a/tests/testthat/test-blog.R +++ b/tests/testthat/test-blog.R @@ -62,7 +62,7 @@ test_that("Create a blog post", { expect_equal(post_2_content$categories, c("shenanigans", "security")) }) -test_that("Error if not quarto project", { +test_that("Error if not a quarto project", { dir_path <- withr::local_tempdir(pattern = "test-blog-project-") withr::local_dir(dir_path) @@ -70,4 +70,13 @@ test_that("Error if not quarto project", { new_blog_post("Intro to Felt Surrogacy", open = FALSE), error = TRUE ) + + expect_snapshot( + new_blog_post( + "Intro to Felt Surrogacy", + wd = withr::local_tempdir(pattern = "test-blog-project-2-"), + open = FALSE + ), + error = TRUE + ) }) From f0e7198333bdd629fa93e91201d7e784a7d5362b Mon Sep 17 00:00:00 2001 From: Christophe Dervieux Date: Tue, 10 Jun 2025 17:30:15 +0200 Subject: [PATCH 23/29] document --- R/blog.R | 1 + man/new_blog_post.Rd | 3 +++ 2 files changed, 4 insertions(+) diff --git a/R/blog.R b/R/blog.R index 900ac35e..2cac266e 100644 --- a/R/blog.R +++ b/R/blog.R @@ -7,6 +7,7 @@ #' to title case via [tools::toTitleCase()]. #' @param dest A character string (or NULL) for the path within `posts`. By #' default, the title is adapted as the directory name. +#' @param wd An optional working directory. If `NULL`, the current working is used. #' @param open A logical: have the default editor open a window to edit the #' `index.qmd` file? #' @param ... A named list of values to be added to the yaml header, such as diff --git a/man/new_blog_post.Rd b/man/new_blog_post.Rd index 08f1b115..f85067e7 100644 --- a/man/new_blog_post.Rd +++ b/man/new_blog_post.Rd @@ -7,6 +7,7 @@ new_blog_post( title, dest = NULL, + wd = NULL, open = rlang::is_interactive(), call = rlang::current_env(), ... @@ -19,6 +20,8 @@ to title case via \code{\link[tools:toTitleCase]{tools::toTitleCase()}}.} \item{dest}{A character string (or NULL) for the path within \code{posts}. By default, the title is adapted as the directory name.} +\item{wd}{An optional working directory. If \code{NULL}, the current working is used.} + \item{open}{A logical: have the default editor open a window to edit the \code{index.qmd} file?} From b19582d29e6daba0950895a6e0119eed7f6512ce Mon Sep 17 00:00:00 2001 From: Christophe Dervieux Date: Tue, 10 Jun 2025 17:30:36 +0200 Subject: [PATCH 24/29] bump version --- DESCRIPTION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DESCRIPTION b/DESCRIPTION index bf8b520e..a0bfd8c8 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,6 +1,6 @@ Package: quarto Title: R Interface to 'Quarto' Markdown Publishing System -Version: 1.4.4.9011 +Version: 1.4.4.9012 Authors@R: c( person("JJ", "Allaire", , "jj@posit.co", role = "aut", comment = c(ORCID = "0000-0003-0174-9868")), From b09e75da00f8aaf634da057ae7a8534dac9d398c Mon Sep 17 00:00:00 2001 From: Christophe Dervieux Date: Tue, 10 Jun 2025 17:32:33 +0200 Subject: [PATCH 25/29] Add new function to pkgdown --- _pkgdown.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/_pkgdown.yml b/_pkgdown.yml index 11e5dfa7..afdeb699 100644 --- a/_pkgdown.yml +++ b/_pkgdown.yml @@ -34,6 +34,7 @@ reference: More about Quarto extensions at contents: - quarto_create_project + - new_blog_post - title: "Configuration" desc: > From dde5346adf400ff6b1e8e52151928485e17920fb Mon Sep 17 00:00:00 2001 From: Christophe Dervieux Date: Tue, 10 Jun 2025 17:37:02 +0200 Subject: [PATCH 26/29] bump again to avoid conflict --- DESCRIPTION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DESCRIPTION b/DESCRIPTION index a0bfd8c8..2772e337 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -1,6 +1,6 @@ Package: quarto Title: R Interface to 'Quarto' Markdown Publishing System -Version: 1.4.4.9012 +Version: 1.4.4.9013 Authors@R: c( person("JJ", "Allaire", , "jj@posit.co", role = "aut", comment = c(ORCID = "0000-0003-0174-9868")), From dd0880efb2005bd8766083bf40490d41a9f4b64b Mon Sep 17 00:00:00 2001 From: Christophe Dervieux Date: Tue, 10 Jun 2025 17:48:25 +0200 Subject: [PATCH 27/29] Correct snapshot by hidding path --- R/utils.R | 10 ++++++++++ tests/testthat/_snaps/blog.md | 15 +++------------ tests/testthat/test-blog.R | 13 ++++++++----- 3 files changed, 21 insertions(+), 17 deletions(-) diff --git a/R/utils.R b/R/utils.R index 7fdb6572..49945c4e 100644 --- a/R/utils.R +++ b/R/utils.R @@ -42,3 +42,13 @@ in_positron <- function() { in_rstudio <- function() { identical(Sys.getenv("RSTUDIO"), "1") } + + +# for test + +hide_path <- function(path) { + function(x) { + x <- gsub(path, "", x, fixed = TRUE) + gsub(fs::path_norm(path), "", x, fixed = TRUE) + } +} diff --git a/tests/testthat/_snaps/blog.md b/tests/testthat/_snaps/blog.md index 3ad941b2..10bcf111 100644 --- a/tests/testthat/_snaps/blog.md +++ b/tests/testthat/_snaps/blog.md @@ -1,25 +1,16 @@ -# Create a blog post - - Code - new_blog_post("Intro to Felt Surrogacy", data = "1999-12-31", open = FALSE) - Condition - Error in `new_blog_post()`: - ! There is already a 'intro-to-felt-surrogacy' directory in 'posts/' - # Error if not a quarto project Code new_blog_post("Intro to Felt Surrogacy", open = FALSE) Condition Error in `new_blog_post()`: - ! You need to be at root of a Quarto project to create a blog post in the 'posts/' directory at 'C:/Users/chris/AppData/Local/Temp/RtmpU72EnV/test-blog-project-415061be69e8'. + ! You need to be at root of a Quarto project to create a blog post in the 'posts/' directory at ''. --- Code - new_blog_post("Intro to Felt Surrogacy", wd = withr::local_tempdir(pattern = "test-blog-project-2-"), - open = FALSE) + new_blog_post("Intro to Felt Surrogacy", wd = tmp_dir, open = FALSE) Condition Error in `new_blog_post()`: - ! You need to be at root of a Quarto project to create a blog post in the 'posts/' directory at 'C:/Users/chris/AppData/Local/Temp/RtmpU72EnV/test-blog-project-2-4150447c3b64'. + ! You need to be at root of a Quarto project to create a blog post in the 'posts/' directory at ''. diff --git a/tests/testthat/test-blog.R b/tests/testthat/test-blog.R index 773d8904..8411644e 100644 --- a/tests/testthat/test-blog.R +++ b/tests/testthat/test-blog.R @@ -35,8 +35,8 @@ test_that("Create a blog post", { # ------------------------------------------------------------------------------ expect_snapshot( - new_blog_post("Intro to Felt Surrogacy", data = "1999-12-31", open = FALSE), - error = TRUE + error = TRUE, + new_blog_post("Intro to Felt Surrogacy", data = "1999-12-31", open = FALSE) ) # ------------------------------------------------------------------------------ @@ -67,16 +67,19 @@ test_that("Error if not a quarto project", { withr::local_dir(dir_path) expect_snapshot( + error = TRUE, + transform = hide_path(dir_path), new_blog_post("Intro to Felt Surrogacy", open = FALSE), - error = TRUE ) + tmp_dir <- withr::local_tempdir(pattern = "test-blog-project-2-") expect_snapshot( + error = TRUE, + transform = hide_path(tmp_dir), new_blog_post( "Intro to Felt Surrogacy", - wd = withr::local_tempdir(pattern = "test-blog-project-2-"), + wd = tmp_dir, open = FALSE ), - error = TRUE ) }) From 94f122929d53076ab0e7af1dd2e8ce5b87d2d2f4 Mon Sep 17 00:00:00 2001 From: Christophe Dervieux Date: Tue, 10 Jun 2025 18:36:12 +0200 Subject: [PATCH 28/29] fix tests --- R/blog.R | 2 +- R/utils.R | 2 +- tests/testthat/_snaps/blog.md | 8 ++++++++ tests/testthat/test-blog.R | 6 +++++- 4 files changed, 15 insertions(+), 3 deletions(-) diff --git a/R/blog.R b/R/blog.R index 2cac266e..09db2996 100644 --- a/R/blog.R +++ b/R/blog.R @@ -59,7 +59,7 @@ make_post_dir <- function(dest, wd, call) { # is this a quarto project for blog ? Expecting _quarto.yml in working dir if (!fs::file_exists(fs::path(working, "_quarto.yml"))) { cli::cli_abort( - "You need to be at root of a Quarto project to create a blog post in the {.file posts/} directory at {.file {working}}.", + "You need to be at root of a Quarto project to create a blog post in the {.file posts/} directory at {.file {fs::path_real(working)}}.", call = call ) } diff --git a/R/utils.R b/R/utils.R index 49945c4e..495395ff 100644 --- a/R/utils.R +++ b/R/utils.R @@ -49,6 +49,6 @@ in_rstudio <- function() { hide_path <- function(path) { function(x) { x <- gsub(path, "", x, fixed = TRUE) - gsub(fs::path_norm(path), "", x, fixed = TRUE) + gsub(fs::path_real(path), "", x, fixed = TRUE) } } diff --git a/tests/testthat/_snaps/blog.md b/tests/testthat/_snaps/blog.md index 10bcf111..966da801 100644 --- a/tests/testthat/_snaps/blog.md +++ b/tests/testthat/_snaps/blog.md @@ -1,3 +1,11 @@ +# Create a blog post + + Code + new_blog_post("Intro to Felt Surrogacy", data = "1999-12-31", open = FALSE) + Condition + Error in `new_blog_post()`: + ! There is already a 'intro-to-felt-surrogacy' directory in 'posts/' + # Error if not a quarto project Code diff --git a/tests/testthat/test-blog.R b/tests/testthat/test-blog.R index 8411644e..5f064013 100644 --- a/tests/testthat/test-blog.R +++ b/tests/testthat/test-blog.R @@ -5,14 +5,18 @@ test_that("Create a blog post", { dir_path <- withr::local_tempdir(pattern = "test-blog-project-") withr::local_dir(dir_path) + proj_name <- "test-blog-project" + quarto_create_project( - name = "test-blog-project", + name = proj_name, type = "blog", dir = dir_path, quiet = TRUE, no_prompt = TRUE ) + withr::local_dir(proj_name) + withr::local_envvar(list(FULLNAME = "Max Kuhn")) # ------------------------------------------------------------------------------ From 6327e8cf9f0df3a5ead2df2f289cbd2045c4f394 Mon Sep 17 00:00:00 2001 From: Christophe Dervieux Date: Tue, 10 Jun 2025 18:52:35 +0200 Subject: [PATCH 29/29] Correctly try usethis --- R/blog.R | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/R/blog.R b/R/blog.R index 09db2996..cb1561fc 100644 --- a/R/blog.R +++ b/R/blog.R @@ -44,9 +44,10 @@ new_blog_post <- function( if (open) { edit_file <- utils::file.edit if ( - rlang::is_installed("usethis") && rlang::is_callable(usethis::edit_file) + rlang::is_installed("usethis") && + is.function(asNamespace("usethis")$edit_file) ) { - edit_file <- getFromNamespace("edit_file", "usethis") + edit_file <- utils::getFromNamespace("edit_file", "usethis") } edit_file(qmd_path) }