rfmt: A new formatter for R

The rfmt package is intended to improve the formatting of R code to aid readability (in the same mold as gofmt tool for Go, and clang-format for C/C++). It shares many of the objectives of Yihui Xie's formatR package, though with its more eleborate layout algorithm (documented in this technical report, also included in the package documentation) and general approach to code formatting, it aims to produce more ''aesthetically appealing'' results.

Installation


To be completed

Like all R packages, rfmt is available from CRAN, and can be installed simply using R's install.packages function:

install.packages("rfmt")
library(rfmt)

If you'd like to download the latest development version of rfmt, it's to be found in this Google repository on GitHub. To install from GitHub, either check out the repository and install from source using install.packages or install directly using R's devtools package:

require(devtools)
install_github("google/rfmt")
library(rfmt)

Python

Unlike the majority of R packages, much of rfmt is implemented in the Python programming language. In contrast to R, Python is reasonably well suited to the sort of fine-grained iterative processing required in rfmt's layout algorithms, and there are a selection of compiler generators in Python the support the analysis of R code necessary for proper layout. Generally, package implementors turn to C or C++ to circumvent these and similar shortcomings in R, but we found it much easier to rework our formatting algorithms in Python than in C/C++. Ease of rework is important in code formatting, which is an inherently subjective exercise; in the last analysis, the only real way of validating the output of a formatter is to present it to prospective users, and to address any objections by amending the program.

Consequently, to use rfmt, you'll need to have a Python (v. 2.7 or later) installation available (in fact the library will complain if it's unable to find one). This is usually the case, but if it isn't, you can download one yourself from python.org.

Usage

Once installed, you can use rfmt in three ways:

  1. From R, format a single file using the rfmt() function, or format all source files in a directory with the rfmtdir() function.
  2. On systems (in particular, Linux and OS/X, or Windows with Cygwin) with the [bash shell](https://en.wikipedia.org/wiki/Bash_(Unix_shell) or C shell, the install_rfmt_shell() function in R makes the command rfmt available from the command line.
  3. You can use rfmt to layout code as you edit in vim or emacs.

These choices are described in detail in the following sections.

Formatting files and directories from R

The function rfmt() allows you to format a file, a string or the contents of the clipboard. For example, the file test.R, supplied with the package, contains the following (rather eccentrically) formatted code:

## Not run:
new.data <- new.data[,object$vars$all,drop = FALSE]

if(others > 0 && others < 10) { object$model <- gsub("parm1", # Alter model in accordance with new data
                       paste("parm1=",
                             others, 
                             sep = ""),
                       object$model)}

## Make data file
data.fn <- makeNewDataFile(x = newdata, 
    y = NULL)

## Finally, compute forecast for new data
Z <- .C("forecast", # See src/top.c
      as.character(data.fn),
        as.character(object$names), as.character(object$data),
            as.character(object$model),
                pred = double(nrow(new.data)),    
                    output = character(1),
                        PACKAGE = "test"      )
## End(**Not run**)

The following code copies this file to a temporary location, and calls rfmt() to format it, printing the result to the console:

fn <- tempfile()
file.copy(system.file("demo", "test.R", package = "rfmt"), fn)
rfmt(fn)
cat(readLines(fn), sep = "\n")

The result you see should closely resemble the following:

## Not run:
new.data <- new.data[, object$vars$all, drop = FALSE]

if (others > 0 && others < 10) {
  object$model <- gsub("parm1",  # Alter model in accordance with new data
                       paste("parm1=", others, sep = ""), object$model)
}

## Make data file
data.fn <- makeNewDataFile(x = newdata, y = NULL)

## Finally, compute forecast for new data
Z <- .C("forecast",  # See src/top.c
        as.character(data.fn), as.character(object$names),
        as.character(object$data), as.character(object$model),
        pred = double(nrow(new.data)), output = character(1), PACKAGE = "test")
## End(**Not run**)

You can provide a string to the formatter directly using the text argument of rfmt(); with neither file name nor text provided, the function formats the contents of the system clipboard. In both these cases, the output of the formatter is printed to the console and returned (invisibly, in the latter case) as a character vector.

To format all the R source files in a directory, use the rfmt_dir() function. This searches a directory for file names that conform to a given pattern (by default, files with extensions ".R", ".r", ".S" or ".s") and formats them each in turn.

From the command line

It's also possible to use it directly from the command line. To facilitate this, the package provides a function install_rfmt_shell() that (by default) makes the formatter available as the bash shell

Editor integration

If you're a user of the Emacs or Vim editors, the package offers two functions, install_rfmt_emacs() and install_rfmt_vim(), that make the formatter available in each of those editors (use the key combination Ctrl-x Ctrl-i to format the current buffer in Emacs, and Ctrl-I in Vim). Calling these functions in R will add the appropriate initialization code to the respective editor's initialization file (~/.vimrc in the case of Vim, and ~/.emacs or ~/.emacs.d/init.el for Emacs), making a back-up copy of the original.

Formatting options

A number of aspects of the formatter's behavior may be affected by setting options in R (using the function option_rfmt()), on the command line, in the environment variable RFMTOPTS or in an initialization file (by default, ~/.rfmtrc, or a file named by the environment variable RFMTRC).

Option | Default value | Description --------------|-----------------|------------------ backup | TRUE | Backup source 'FILE' to 'FILE.bak' before formatting margin0 | 0 | Position of the first (soft) right margin margin1 | 80 | Position of the second (hard) right margin cost0 | 0.05 | Cost (per character) beyond margin 0 cost1 | 100 | Cost (per character) beyond margin 1 costb | 2 | Cost per line break indent | 2 | Number of spaces for each indent force.brace | 0 | Ensure that control flow constructs have braces space.arg.eq | 1 | Ensure spaces around equals signs in arguments quiet | 1 | Suppress all diagnostic messages adj.comment | 0.5 | Adjustment to line break cost in inline comments adj.flow | 0.3 | Adjustment to line break cost in control flow constructs adj.call | 0.5 | Adjustment to line break cost in function calls adj.arg | 5 | Adjustment to line break cost in argument expressions cpack | 0.001 | Cost used to pack elements in justified layouts



google/rfmt documentation built on May 17, 2019, 7:59 a.m.