diff --git a/R/cran.R b/R/cran.R index 7201fe6..bed04ce 100644 --- a/R/cran.R +++ b/R/cran.R @@ -134,7 +134,7 @@ find_exports_without_examples <- function(lines) { line <- lines[i] # Start of doc block - if (grepl("^#'", line)) { + if (grepl("^##?'", line)) { if (!in_doc_block) { in_doc_block <- TRUE has_export <- FALSE @@ -143,12 +143,12 @@ find_exports_without_examples <- function(lines) { } # Check for export tag - if (grepl("^#'\\s*@export", line)) { + if (grepl("^##?'\\s*@export", line)) { has_export <- TRUE } # Check for examples tag - if (grepl("^#'\\s*@examples", line)) { + if (grepl("^##?'\\s*@examples", line)) { has_examples <- TRUE } } else if (in_doc_block) { @@ -183,14 +183,14 @@ find_dontrun_examples <- function(lines) { for (i in seq_along(lines)) { line <- lines[i] - if (grepl("^#'", line)) { + if (grepl("^##?'", line)) { if (!in_doc_block) { in_doc_block <- TRUE has_export <- FALSE has_dontrun <- FALSE } - if (grepl("^#'\\s*@export", line)) { + if (grepl("^##?'\\s*@export", line)) { has_export <- TRUE } @@ -226,25 +226,25 @@ find_long_example_lines <- function(lines, filename) { for (i in seq_along(lines)) { line <- lines[i] - if (!grepl("^#'", line)) { + if (!grepl("^##?'", line)) { in_examples <- FALSE next } - if (grepl("^#'\\s*@examples", line)) { + if (grepl("^##?'\\s*@examples", line)) { in_examples <- TRUE next } # Other tags end the examples block - if (grepl("^#'\\s*@[a-zA-Z]", line)) { + if (grepl("^##?'\\s*@[a-zA-Z]", line)) { in_examples <- FALSE next } if (in_examples) { # Strip the #' prefix to get the actual example content - content <- sub("^#'\\s?", "", line) + content <- sub("^##?'\\s?", "", line) if (nchar(content) > 100) { found <- c(found, paste0(filename, ":", i, " (", nchar(content), " chars)")) diff --git a/R/parse.R b/R/parse.R index 45f9721..716d304 100644 --- a/R/parse.R +++ b/R/parse.R @@ -14,7 +14,7 @@ parse_file <- function(file) { lines <- readLines(file, encoding = "UTF-8", warn = FALSE) # Find documentation blocks (consecutive #' lines) - doc_lines <- grep("^#'", lines) + doc_lines <- grep("^##?'", lines) if (length(doc_lines) == 0) { return(list()) @@ -43,8 +43,8 @@ parse_file <- function(file) { result <- list() for (block_lines in blocks) { - # Extract the comment text (strip #' prefix) - comment_text <- sub("^#'\\s?", "", lines[block_lines]) + # Extract the comment text (strip #' or ##' prefix) + comment_text <- sub("^##?'\\s?", "", lines[block_lines]) # Find the object definition after the block. Blank lines and plain # comments between the block and its object are allowed; another #' @@ -52,12 +52,12 @@ parse_file <- function(file) { next_line <- max(block_lines) + 1 while (next_line <= length(lines) && - !grepl("^\\s*#'", lines[next_line]) && + !grepl("^\\s*##?'", lines[next_line]) && grepl("^\\s*(#|$)", lines[next_line])) { next_line <- next_line + 1 } - if (next_line > length(lines) || grepl("^\\s*#'", lines[next_line])) { + if (next_line > length(lines) || grepl("^\\s*##?'", lines[next_line])) { warning("Documentation block at ", basename(file), ":", block_lines[1], " is not followed by an object ", "definition; its tags are ignored.", call. = FALSE) diff --git a/inst/tinytest/test_parse.R b/inst/tinytest/test_parse.R index 533ee16..d1b01c8 100644 --- a/inst/tinytest/test_parse.R +++ b/inst/tinytest/test_parse.R @@ -110,3 +110,33 @@ expect_equal(length(big$formals$names), 30L) expect_equal(big$formals$names[30], "a30") expect_true(all(grepl("= NULL$", big$formals$usage))) unlink(tmp) + +# ESS-style ##' comments parse like #' (PR #27). +tmp <- tempfile(fileext = ".R") +writeLines(c( + "##' Add one", + "##' @param x A number.", + "##' @export", + "add_one <- function(x) x + 1" +), tmp) +blocks <- tinyrox:::parse_file(tmp) +expect_equal(length(blocks), 1) +expect_equal(blocks[[1]]$object, "add_one") +unlink(tmp) + +# The orphaned-block detector must recognise ##' too, so a stray ##' block +# can't bleed into the next object (the #18 regression for double-hash). +tmp <- tempfile(fileext = ".R") +writeLines(c( + "##' Orphaned block (its object was moved away)", + "##' @export", + "", + "##' Real", + "##' @export", + "real_fn <- function() 1" +), tmp) +expect_warning(blocks <- tinyrox:::parse_file(tmp), + pattern = "not followed by an object definition") +expect_equal(length(blocks), 1) +expect_equal(blocks[[1]]$object, "real_fn") +unlink(tmp)