diff --git a/.Rbuildignore b/.Rbuildignore index 53fa7515..bb6b2220 100644 --- a/.Rbuildignore +++ b/.Rbuildignore @@ -22,3 +22,4 @@ rstudio\_dotrstudio ^CONTRIBUTING\.md$ ^fusen2\.Rproj$ ^CRAN-SUBMISSION$ +^.vscode$ \ No newline at end of file diff --git a/.github/workflows/rhub.yaml b/.github/workflows/rhub.yaml new file mode 100644 index 00000000..48b12a46 --- /dev/null +++ b/.github/workflows/rhub.yaml @@ -0,0 +1,79 @@ +# R-hub's genetic GitHub Actions workflow file. It's canonical location is at +# https://github.com/r-hub/rhub2/blob/v1/inst/workflow/rhub.yaml +# You can update this file to a newer version using the rhub2 package: +# +# rhub2::rhub_setup() +# +# It is unlikely that you need to modify this file manually. + +name: R-hub +run-name: ${{ github.event.inputs.name || format('Manually run by {0}', github.triggering_actor) }} (${{ github.event.inputs.id }}) + +on: + workflow_dispatch: + inputs: + config: + description: 'A comma separated list of R-hub platforms to use.' + type: string + default: 'linux,windows,macos' + name: + description: 'Run name. You can leave this empty now.' + type: string + id: + description: 'Unique ID. You can leave this empty now.' + type: string + +jobs: + + setup: + runs-on: ubuntu-latest + outputs: + containers: ${{ steps.rhub-setup.outputs.containers }} + platforms: ${{ steps.rhub-setup.outputs.platforms }} + + steps: + # NO NEED TO CHECKOUT HERE + - uses: r-hub/rhub2/actions/rhub-setup@v1 + with: + config: ${{ github.event.inputs.config }} + id: rhub-setup + + linux-containers: + needs: setup + if: ${{ needs.setup.outputs.containers != '[]' }} + runs-on: ubuntu-latest + name: ${{ matrix.config.label }} + strategy: + fail-fast: false + matrix: + config: ${{ fromJson(needs.setup.outputs.containers) }} + container: + image: ${{ matrix.config.container }} + + steps: + - uses: actions/checkout@v3 + - uses: r-hub/rhub2/actions/rhub-check@v1 + with: + token: ${{ secrets.RHUB_TOKEN }} + job-config: ${{ matrix.config.job-config }} + + other-platforms: + needs: setup + if: ${{ needs.setup.outputs.platforms != '[]' }} + runs-on: ${{ matrix.config.os }} + name: ${{ matrix.config.label }} + strategy: + fail-fast: false + matrix: + config: ${{ fromJson(needs.setup.outputs.platforms) }} + + steps: + - uses: actions/checkout@v3 + - uses: r-hub/rhub2/actions/rhub-setup-r@v1 + with: + job-config: ${{ matrix.config.job-config }} + token: ${{ secrets.RHUB_TOKEN }} + - uses: r-hub/rhub2/actions/rhub-check@v1 + with: + job-config: ${{ matrix.config.job-config }} + token: ${{ secrets.RHUB_TOKEN }} diff --git a/.gitignore b/.gitignore index aad75ff2..b85ec8a0 100644 --- a/.gitignore +++ b/.gitignore @@ -12,3 +12,4 @@ check /Meta/ cran-comments.md CRAN-SUBMISSION +.vscode diff --git a/DESCRIPTION b/DESCRIPTION index 8446e523..003e529a 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -43,11 +43,12 @@ Suggests: rcmdcheck, rmarkdown, rstudioapi, + styler, testthat (>= 3.0.0), withr VignetteBuilder: knitr -Config/fusen/version: 0.5.2 +Config/fusen/version: 0.5.2.9000 Config/Needs/website: ThinkR-open/thinkrtemplate Config/testthat/edition: 3 Config/testthat/parallel: false diff --git a/NEWS.md b/NEWS.md index 451f881d..8e547804 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,5 +1,8 @@ # fusen (development version) +- Allow `organisation` in `init_share_on_github()` to send to a GitHub organisation +- Fix `load_flat_functions()` to work with VSCode + # fusen 0.5.2 ## New features diff --git a/R/globals.R b/R/globals.R index 8edbbd03..4e52b842 100644 --- a/R/globals.R +++ b/R/globals.R @@ -4,7 +4,5 @@ globalVariables(unique(c( # add_fun_to_parsed "fun_name", "rox_filename", "chunk_filename", ".", # get_functions - ".", - # split_rmd - "type", "lines", "title" + "." ))) diff --git a/R/inflate.R b/R/inflate.R index 5252e62f..b4fad73f 100644 --- a/R/inflate.R +++ b/R/inflate.R @@ -94,8 +94,9 @@ inflate <- function(pkg = ".", flat_file, # If flat_file empty if (missing(flat_file) && requireNamespace("rstudioapi") && rstudioapi::isAvailable() && - rstudioapi::hasFun("documentPath")) { - current_file <- rstudioapi::documentPath() + rstudioapi::hasFun("getSourceEditorContext")) { + curr_editor <- rstudioapi::getSourceEditorContext() + current_file <- curr_editor$path if (!is.null(current_file) && grepl("^flat.*[.](R|r|q)md$", basename(current_file))) { if (overwrite == "ask") { sure <- paste0( diff --git a/R/init_share_on_github.R b/R/init_share_on_github.R index a873bf45..cdb49359 100644 --- a/R/init_share_on_github.R +++ b/R/init_share_on_github.R @@ -7,6 +7,7 @@ #' #' @param ask Logical. `TRUE` (default) to ask the user to apply the instructions each time needed, #' or `FALSE` if the user already know what to do. +#' @inheritParams usethis::use_github #' #' @details #' @@ -35,7 +36,7 @@ #' # This modifies the current directory and send it on GitHub #' init_share_on_github() #' } -init_share_on_github <- function(ask = TRUE) { +init_share_on_github <- function(ask = TRUE, organisation = NULL) { pkg <- "." if (!requireNamespace("gert", quietly = TRUE)) { @@ -88,7 +89,7 @@ init_share_on_github <- function(ask = TRUE) { dont_do_it <- FALSE } if (do_it) { - usethis::use_github() + usethis::use_github(organisation = organisation) } else { cli::cli_text( cli::cli_alert_info( diff --git a/R/load_flat_functions.R b/R/load_flat_functions.R index de175d17..e81d3953 100644 --- a/R/load_flat_functions.R +++ b/R/load_flat_functions.R @@ -9,33 +9,54 @@ #' #' @examples #' \dontrun{ +#' # Use this command directly in the console +#' fusen::load_flat_functions() +#' +#' # Or choose a flat file to load functions from #' load_flat_functions(flat_file = "dev/flat_full.Rmd") #' load_flat_functions(flat_file = "dev/flat_clean_fusen_files.Rmd") #' } load_flat_functions <- function(flat_file, envir = globalenv()) { - if (missing(flat_file) && requireNamespace("rstudioapi") && rstudioapi::isAvailable() && - rstudioapi::hasFun("documentPath")) { - current_file <- rstudioapi::documentPath() - if (!is.null(current_file) && grepl("^flat.*[.](R|r|q)md$", basename(current_file))) { + if ( + missing(flat_file) && requireNamespace("rstudioapi") && + rstudioapi::isAvailable() && + rstudioapi::hasFun("getSourceEditorContext") + ) { + curr_editor <- rstudioapi::getSourceEditorContext() + current_file <- curr_editor$path + + if (!is.null(current_file)) { flat_file <- current_file } } + if (!grepl("^(flat|dev).*[.](R|r|q)md$", basename(flat_file))) { + stop( + "Please provide a Rmd or qmd flat file to load functions from", + " or open a flat file in the current IDE editor.", + "\n'flat_file' name should start with 'flat' or 'dev'", + " and end with '.Rmd' or '.qmd'." + ) + } + parsed_flat_file <- parse_rmd(flat_file) parsed_tbl <- as_tibble(parsed_flat_file) - which_parsed_fun <- which(!is.na(parsed_tbl$label) & - grepl(regex_functions, parsed_tbl$label)) + which_parsed_fun <- which( + !is.na(parsed_tbl$label) & + grepl(regex_functions, parsed_tbl$label) + ) if (nrow(parsed_tbl) > 0) { - # to_source <- tempfile() content <- unlist(rmd_node_code(parsed_tbl[which_parsed_fun, ][["ast"]])) eval(parse(text = content), envir) - # cat(content, file = to_source) - # - # source(to_source, ...) - # file.remove(to_source) - cli_alert_success(paste0("'function' chunks from '", flat_file, "' sourced in global env.")) + + cli_alert_success( + paste0( + "'function' chunks from '", + flat_file, "' sourced in global env." + ) + ) } else { cli_alert_warning("Nothing to source") } diff --git a/data-raw/DATASET.R b/data-raw/DATASET.R deleted file mode 100644 index 65f3c03e..00000000 --- a/data-raw/DATASET.R +++ /dev/null @@ -1,23 +0,0 @@ -## code to prepare `DATASET` dataset goes here - -# Create fake dataset using internal ThinkR package -library(dplyr) -library(fakir) -database <- fake_ticket_client(vol = 1500, n = 500, seed = 4321, split = TRUE) - -clients <- database$clients %>% - arrange(id_dpt, departement) %>% - tidyr::fill(departement) %>% - mutate( - entry_year = lubridate::year(entry_date), - age_class = cut(age, - breaks = c(18, 25, 40, 55, 70, 100), - include.lowest = TRUE - ) - ) - -# usethis::use_data(clients, overwrite = TRUE) - -readr::write_csv(clients, "inst/clients.csv") - -# usethis::use_data("DATASET") diff --git a/dev/config_attachment.yaml b/dev/config_attachment.yaml index 0c75fd2b..b0169ce3 100644 --- a/dev/config_attachment.yaml +++ b/dev/config_attachment.yaml @@ -10,6 +10,7 @@ extra.suggests: - rmarkdown - knitr - gert + - styler pkg_ignore: - testthat - dummypackage diff --git a/dev/dev_history_parse.Rmd b/dev/dev_history_parse.Rmd deleted file mode 100644 index 16a9f30a..00000000 --- a/dev/dev_history_parse.Rmd +++ /dev/null @@ -1,220 +0,0 @@ ---- -title: "dev_history.Rmd for working package" -author: "Sébastien Rochette" -date: "23/01/2021" -output: html_document ---- - -```{r development, include=FALSE} -library(testthat) -``` - -# Parse and split a Rmarkdown file, and transform as tibble - -```{r function} -#' Split Rmarkdown file -#' -#' @param file Path to Rmarkdown file -#' @importFrom utils head tail -#' -#' @export -#' -#' @return A tibble with a line for each Rmd part -split_rmd <- function(file) { - x <- xfun::read_utf8(file) - - target_labels <- c("description", "development", "function", "example", "test") - - groups <- group_rmd(file) - first_of_group <- c(TRUE, (head(groups, -1)) != tail(groups, -1)) - count_groups <- cumsum(first_of_group) - - extract_labels <- function(x, type, lines, target_labels) { - if (type[[x]] != "rmd_chunk") { - return(NA_character_) - } else { - stringi::stri_extract_first_regex(lines[[x]][1], paste(target_labels, collapse = "|")) - } - } - extract_title <- function(x, type, lines) { - if (type[[x]] != "rmd_heading") { - return(NA_character_) - } else { - gsub("^#+\\s+", "", lines[[x]]) - } - } - extract_code <- function(x, type, lines) { - if (type[[x]] != "rmd_chunk") { - return(NA_character_) - } else { - lines[[x]][-c(1, length(lines[[x]]))] - } - } - - parsed <- tibble::tibble( - groups = groups[first_of_group], - type = stringi::stri_extract_first_regex(groups, "(\\w+)"), - lines = split(x, count_groups), - labels = unlist( - lapply(seq_along(type), extract_labels, - type = type, lines = lines, target_labels = target_labels - ) - ), - title = unlist(lapply(seq_along(type), extract_title, - type = type, lines = lines - )), - section = c(NA_character_, title[!is.na(title)])[1 + cumsum(!is.na(title))], - code = lapply(seq_along(type), extract_code, - type = type, lines = lines - ) - ) - parsed -} - -#' Groupe parts of Rmarkdown file -#' -#' @param file path to Rmarkdown file -#' -#' @importFrom utils head tail -#' @export -#' -#' @return Character vector of groups of lines -#' -#' @examples -#' file <- system.file("dev-template-tests.Rmd", package = "fusen") -#' group_rmd(file) -group_rmd <- function(file) { - x <- xfun::read_utf8(file) - - # Info - x_info <- rep(NA_character_, length(x)) - - # Yaml - yaml_begin <- 1 - yaml_end <- which(grepl("^---", x))[2] - x_info[yaml_begin:yaml_end] <- "rmd_yaml_list" - - # Chunks - chunk.begin <- knitr::all_patterns$md$chunk.begin - chunk.end <- knitr::all_patterns$md$chunk.end - blks <- grepl(chunk.begin, x) - txts <- utils::getFromNamespace("filter_chunk_end", "knitr")(blks, grepl(chunk.end, x)) - if (length(blks) != length(txts)) { - stop("You may have let some not closed chunks") - } - chunks_lines_list <- lapply( - seq_along(which(blks)), - function(x) { - which(blks)[x]:which(txts)[x] - } - ) - count_chunks <- seq_along(chunks_lines_list) - count_chunks <- formatC(count_chunks, flag = "0", width = max(nchar(count_chunks))) - chunks_lines_nb <- unlist(lapply( - seq_along(chunks_lines_list), - function(x) { - rep( - paste0("rmd_chunk-", count_chunks[x]), - length(chunks_lines_list[[x]]) - ) - } - )) - chunks_lines_vec <- unlist(chunks_lines_list) - x_info[chunks_lines_vec] <- chunks_lines_nb - - # Comments - comment.begin <- "^" - starts <- which(grepl(comment.begin, x)) - starts <- starts[!starts %in% c(yaml_begin:yaml_end, chunks_lines_vec)] - ends <- which(grepl(comment.end, x)) - ends <- ends[!ends %in% c(yaml_begin:yaml_end, chunks_lines_vec)] - if (length(starts) != length(ends)) { - stop("You may have let some not closed comments tags like in your text") - } - comments_lines_list <- lapply( - seq_along(starts), - function(x) { - starts[x]:ends[x] - } - ) - count_comments <- seq_along(comments_lines_list) - count_comments <- formatC(count_comments, flag = "0", width = max(nchar(count_comments))) - comments_lines_nb <- unlist(lapply( - seq_along(comments_lines_list), - function(x) { - rep( - paste0("rmd_comment-", count_comments[x]), - length(comments_lines_list[[x]]) - ) - } - )) - comments_lines_vec <- unlist(comments_lines_list) - x_info[comments_lines_vec] <- comments_lines_nb - - - # hashtags - hashtag <- which(grepl("^#", x)) - titles <- hashtag[!hashtag %in% - c(yaml_begin:yaml_end, chunks_lines_vec, comments_lines_vec)] - count_titles <- seq_along(titles) - count_titles <- formatC(count_titles, flag = "0", width = max(nchar(count_titles))) - x_info[titles] <- paste0("rmd_heading-", count_titles) - - # text - all_text <- which(is.na(x_info)) - # Prev is text - count_text <- cumsum(c(TRUE, (head(all_text, -1) + 1) != tail(all_text, -1))) - count_text <- formatC(count_text, flag = "0", width = max(nchar(count_text))) - texts <- paste0("rmd_markdown-", count_text) - x_info[all_text] <- texts - - # Return groups - x_info -} -``` - -```{r examples} -file <- system.file("dev-template-tests.Rmd", package = "fusen") -# Attribute group to each line -group_rmd(file) -# Split Rmd by group into tibble -split_rmd(file) -``` - -```{r tests} -file <- system.file("dev-template-tests.Rmd", package = "fusen") -groups <- group_rmd(file) -test_that("group_rmd works properly", { - expect_true(all(groups[1:8] == "rmd_yaml_list")) - expect_true(all(groups[10:12] == "rmd_chunk-01")) - expect_true(all(groups[14:19] == "rmd_comment-1")) - expect_true(all(groups[21:35] == "rmd_chunk-02")) - expect_true(all(groups[37] == "rmd_heading-1")) -}) - -file <- system.file("dev-template-test-parse-nothing.Rmd", package = "fusen") -groups <- group_rmd(file) -test_that("group_rmd does not fail", { - expect_true(all(groups[1:8] == "rmd_yaml_list")) -}) - -file <- system.file("dev-template-tests.Rmd", package = "fusen") -tbl_rmd <- split_rmd(file) -test_that("split_rmd works", { - expect_true(nrow(tbl_rmd) == 47) - expect_true(ncol(tbl_rmd) == 7) - expect_true(all(tbl_rmd[["lines"]][[3]] == - c("```{r development, include=FALSE}", "library(testthat)", "```"))) - expect_true(tbl_rmd[["type"]][3] == "rmd_chunk") - expect_true(tbl_rmd[["type"]][9] == "rmd_heading") - expect_true(tbl_rmd[["labels"]][3] == "development") - expect_true(tbl_rmd[["title"]][9] == "Calculate the median of a vector") - expect_true(tbl_rmd[["section"]][10] == "Calculate the median of a vector") - expect_true(tbl_rmd[["code"]][[3]] == "library(testthat)") -}) -``` - -```{r development-2, eval=FALSE} -fusen::inflate(flat_file = file.path("dev", "dev_history_parse.Rmd"), vignette_name = NA, check = FALSE) -``` diff --git a/dev/flat_history_core.Rmd b/dev/flat_history_core.Rmd index dbc16a2c..32a0691c 100644 --- a/dev/flat_history_core.Rmd +++ b/dev/flat_history_core.Rmd @@ -838,16 +838,6 @@ create_vignette <- function(parsed_tbl, pkg, name) { grepl("rmd_yaml_list", parsed_tbl[["type"]])), ] - # Make chunk names unique - # vignette_tbl[["label"]] <- ifelse( - # is.na(vignette_tbl[["label"]]) & vignette_tbl[["type"]] == "rmd_chunk", - # gsub("[.]+", "-", make.names(name)), - # vignette_tbl[["label"]]) - # - # vignette_tbl[["label"]] <- make.unique(vignette_tbl[["label"]], sep = "-") - # # Not re-used in as_document() - - cleaned_name <- asciify_name(name) usethis::use_vignette(name = cleaned_name, title = name) diff --git a/man/init_share_on_github.Rd b/man/init_share_on_github.Rd index c99d137c..92d1146e 100644 --- a/man/init_share_on_github.Rd +++ b/man/init_share_on_github.Rd @@ -4,11 +4,17 @@ \alias{init_share_on_github} \title{Initiate GitHub to share your package on a website} \usage{ -init_share_on_github(ask = TRUE) +init_share_on_github(ask = TRUE, organisation = NULL) } \arguments{ \item{ask}{Logical. \code{TRUE} (default) to ask the user to apply the instructions each time needed, or \code{FALSE} if the user already know what to do.} + +\item{organisation}{If supplied, the repo will be created under this +organisation, instead of the login associated with the GitHub token +discovered for this \code{host}. The user's role and the token's scopes must be +such that you have permission to create repositories in this +\code{organisation}.} } \value{ The URL of the website created diff --git a/man/load_flat_functions.Rd b/man/load_flat_functions.Rd index 170e1742..a300c396 100644 --- a/man/load_flat_functions.Rd +++ b/man/load_flat_functions.Rd @@ -22,6 +22,10 @@ Load the code of all 'function' chunk in a flat file } \examples{ \dontrun{ +# Use this command directly in the console +fusen::load_flat_functions() + +# Or choose a flat file to load functions from load_flat_functions(flat_file = "dev/flat_full.Rmd") load_flat_functions(flat_file = "dev/flat_clean_fusen_files.Rmd") } diff --git a/tests/testthat/test-inflate-part2.R b/tests/testthat/test-inflate-part2.R index 3076fdab..ab8ab688 100644 --- a/tests/testthat/test-inflate-part2.R +++ b/tests/testthat/test-inflate-part2.R @@ -156,7 +156,8 @@ for (pkgname in create_choices_test) { # quiet and checkdir checkdir <- normalize_path_winslash( file.path(alltemp, paste0("checkout", pkgname)), - mustWork = FALSE) + mustWork = FALSE + ) extra_params <- glue( 'fusen::inflate(pkg = "{path_foosen}", check = TRUE, check_dir = "{checkdir}",