tests/testthat/roxygen-examples-complete/10-styler-r-ui-in.R

#' @api
#' @import tibble
#' @importFrom magrittr %>%
NULL

#' Prettify R source code
#'
#' Performs various substitutions in all `.R` files in a package
#' (code and tests).
#' Carefully examine the results after running this function!
#'
#' @param pkg Path to a (subdirectory of an) R package.
#' @param ... Arguments passed on to the `style` function.
#' @param style A function that creates a style guide to use, by default
#'   [tidyverse_style()] (without the parentheses). Not used
#'   further except to construct the argument `transformers`. See
#'   [style_guides()] for details.
#' @param transformers A set of transformer functions. This argument is most
#'   conveniently constructed via the `style` argument and `...`. See
#'   'Examples'.
#' @param filetype Vector of file extensions indicating which file types should
#'   be styled. Case is ignored, and the `.` is optional, e.g. `c(".R", ".Rmd")`
#'   or `c("r", "rmd")`.
#' @param exclude_files Character vector with paths to files that should be
#'   excluded from styling.
#' @param include_roxygen_examples Whether or not to style code in roxygen
#'   examples.
#' @section Warning:
#' This function overwrites files (if styling results in a change of the
#' code to be formatted). It is strongly suggested to only style files
#' that are under version control or to create a backup copy.
#'
#' We suggest to first style with `scope < "tokens"` and inspect and commit
#' changes, because these changes are guaranteed to leave the abstract syntax
#' tree (AST) unchanged. See section 'Roundtrip Validation' for details.
#'
#' Then, we suggest to style with `scope = "tokens"` (if desired) and carefully
#' inspect the changes to make sure the AST is not changed in an unexpected way
#' that invalidates code.
#' @section Roundtrip Validation:
#' The following section describes when and how styling is guaranteed to
#' yield correct code.
#'
#' If the style guide has `scope < "tokens"`, no tokens are changed and the
#' abstract syntax tree (AST) should not change.
#' Hence, it is possible to validate the styling by comparing whether the parsed
#' expression before and after styling have the same AST.
#' This comparison omits comments. styler compares
#' error if the AST has changed through styling.
#'
#' Note that with `scope = "tokens"` such a comparison is not conducted because
#' the AST might well change and such a change is intended. There is no way
#' styler can validate styling, that is why we inform the user to carefully
#' inspect the changes.
#'
#' See section 'Warning' for a good strategy to apply styling safely.
#' @inheritSection transform_files Value
#' @family stylers
#' @examples
#' \dontrun{
#' style_pkg(style = tidyverse_style, strict = TRUE)
#' style_pkg(
#'   scope = "line_breaks",
#'   math_token_spacing = specify_math_token_spacing(zero = "'+'")
#' )
#' }
#' @export
style_pkg <- function(pkg = ".",
                      ...,
                      style = tidyverse_style,
                      transformers = style(...),
                      filetype = "R",
                      exclude_files = "R/RcppExports.R",
                      include_roxygen_examples = TRUE) {
  pkg_root <- rprojroot::find_package_root_file(path = pkg)
  changed <- withr::with_dir(pkg_root, prettify_pkg(
    transformers, filetype, exclude_files, include_roxygen_examples
  ))
  invisible(changed)
}

prettify_pkg <- function(transformers,
                         filetype,
                         exclude_files,
                         include_roxygen_examples) {
  filetype <- set_and_assert_arg_filetype(filetype)
  r_files <- vignette_files <- readme <- NULL

  if ("\\.r" %in% filetype) {
    r_files <- dir(
      path = c("R", "tests", "data-raw"), pattern = "\\.r$",
      ignore.case = TRUE, recursive = TRUE, full.names = TRUE
    )
  }

  if ("\\.rmd" %in% filetype) {
    vignette_files <- dir(
      path = "vignettes", pattern = "\\.rmd$",
      ignore.case = TRUE, recursive = TRUE, full.names = TRUE
    )
    readme <- dir(pattern = "^readme\\.rmd$", ignore.case = TRUE)
  }

  files <- setdiff(c(r_files, vignette_files, readme), exclude_files)
  transform_files(files, transformers, include_roxygen_examples)
}


#' Style a string
#'
#' Styles a character vector. Each element of the character vector corresponds
#' to one line of code.
#' @param text A character vector with text to style.
#' @inheritParams style_pkg
#' @family stylers
#' @examples
#' style_text("call( 1)")
#' style_text("1    + 1", strict = FALSE)
#' style_text("a%>%b", scope = "spaces")
#' style_text("a%>%b; a", scope = "line_breaks")
#' style_text("a%>%b; a", scope = "tokens")
#' # the following is identical but the former is more convenient:
#' style_text("a<-3++1", style = tidyverse_style, strict = TRUE)
#' style_text("a<-3++1", transformers = tidyverse_style(strict = TRUE))
#' @export
style_text <- function(text,
                       ...,
                       style = tidyverse_style,
                       transformers = style(...),
                       include_roxygen_examples = TRUE) {
  transformer <- make_transformer(transformers, include_roxygen_examples)
  styled_text <- transformer(text)
  construct_vertical(styled_text)
}

#' Prettify arbitrary R code
#'
#' Performs various substitutions in all `.R` files in a directory.
#' Carefully examine the results after running this function!
#' @param path Path to a directory with files to transform.
#' @param recursive A logical value indicating whether or not files in subdirectories
#'   of `path` should be styled as well.
#' @inheritParams style_pkg
#' @inheritSection transform_files Value
#' @inheritSection style_pkg Warning
#' @inheritSection style_pkg Roundtrip Validation
#' @family stylers
#' @examples
#' \dontrun{
#' style_dir(file_type = "r")
#' }
#' @export
style_dir <- function(path = ".",
                      ...,
                      style = tidyverse_style,
                      transformers = style(...),
                      filetype = "R",
                      recursive = TRUE,
                      exclude_files = NULL,
                      include_roxygen_examples = TRUE) {
  changed <- withr::with_dir(
    path, prettify_any(
      transformers, filetype, recursive, exclude_files, include_roxygen_examples
    )
  )
  invisible(changed)
}

#' Prettify R code in current working directory
#'
#' This is a helper function for style_dir.
#' @inheritParams style_pkg
#' @param recursive A logical value indicating whether or not files in subdirectories
#'   should be styled as well.
#' @keywords internal
prettify_any <- function(transformers,
                         filetype,
                         recursive,
                         exclude_files,
                         include_roxygen_examples) {
  files <- dir(
    path = ".", pattern = map_filetype_to_pattern(filetype),
    ignore.case = TRUE, recursive = recursive, full.names = TRUE
  )
  transform_files(
    setdiff(files, exclude_files), transformers, include_roxygen_examples
  )
}

#' Style `.R` and/or `.Rmd` files
#'
#' Performs various substitutions in the files specified.
#' Carefully examine the results after running this function!
#' @section Encoding:
#' UTF-8 encoding is assumed. Please convert your code to UTF-8 if necessary
#' before applying styler.
#' @param path A character vector with paths to files to style.
#' @inheritParams style_pkg
#' @inheritSection transform_files Value
#' @inheritSection style_pkg Warning
#' @inheritSection style_pkg Roundtrip Validation
#' @examples
#' # the following is identical but the former is more convenient:
#' file <- tempfile("styler", fileext = ".R")
#' xfun::write_utf8("1++1", file)
#' style_file(file, style = tidyverse_style, strict = TRUE)
#' style_file(file, transformers = tidyverse_style(strict = TRUE))
#' xfun::read_utf8(file)
#' unlink(file)
#' @family stylers
#' @export
style_file <- function(path,
                       ...,
                       style = tidyverse_style,
                       transformers = style(...),
                       include_roxygen_examples = TRUE) {
  changed <- withr::with_dir(
    dirname(path),
    transform_files(basename(path), transformers, include_roxygen_examples)
  )
  invisible(changed)
}
krlmlr/styler documentation built on April 8, 2024, 7:53 p.m.