Learn R Programming

formatR (version 0.2-4)

tidy.source: `Tidy up' R code while preserving comments

Description

This function has nothing to do with code optimization; it just returns parsed source code, but also tries to preserve comments, which is different with parse. See `Details'.

Usage

tidy.source(source = "clipboard", keep.comment, keep.blank.line, 
    keep.space, replace.assign, output = TRUE, text = NULL, width.cutoff = 0.75 * 
        getOption("width"), ...)

Arguments

source
a string: location of the source code (default to be the clipboard; this means we can copy the code to clipboard and use tidy.souce() without specifying the argument source)
keep.comment
logical value: whether to keep comments or not? (TRUE by default)
keep.blank.line
logical value: whether to keep blank lines or not? (FALSE by default)
keep.space
logical: whether to preserve the leading spaces in the single lines of comments (default FALSE)
replace.assign
logical: whether to replace the assign operator = with <-
output
output to the console or a file using cat?
text
an alternative way to specify the input: if it is NULL, the function will read the source code from the source argument; alternatively, if text is a character vector containing the source code, it will be use
width.cutoff
passed to deparse: integer in [20, 500] determining the cutoff at which line-breaking is tried (default to be 0.75 * getOption("width"))
...
other arguments passed to cat, e.g. file (this can be useful for batch-processing R scripts, e.g. tidy.source(source = 'input.R', file = 'output.R'))

Value

  • A list with components
  • text.tidyThe reformatted code as a character vector.
  • text.maskThe code containing comments, which are masked in assignments or with the weird operator.
  • begin.comment,end.commentidentifiers used to mark the comments

Details

This function helps the users to tidy up their source code in a sense that necessary indents and spaces will be added, etc. See parse. But comments will be preserved if keep.comment = TRUE.

The method to preserve comments is to protect them as strings in disguised assignments. For example, there is a single line of comments in the source code: # asdf

It will be first masked as

.IDENTIFIER1 <- " # asdf.IDENTIFIER2"

which is a legal R expression, so parse can deal with it and will no longer remove the disguised comments. In the end the identifiers will be removed to restore the original comments, i.e. the strings '.IDENTIFIER1 <- "' and '.IDENTIFIER2"' are replaced with empty strings.

``Inline'' comments are handled differently: two spaces will be added before the hash symbol #}, e.g. 1+1# comments

will become 1+1 # comments

Inline comments are first disguised as a weird operation with its preceding R code, which is essentially meaningless but syntactically correct! For example, 1+1 %InLiNe_IdEnTiFiEr% "# comments"

then parse will deal with this expression; again, the disguised comments will not be removed. In the end, inline comments will be freed as well (remove the operator %InLiNe_IdEnTiFiEr% and surrounding double quotes).

All these special treatments to comments are due to the fact that parse and deparse can tidy the R code at the price of dropping all the comments. When keep.comment == TRUE, all your double quotes in the comments will be replaced by single quotes!! For example,

1 + 1 # here is "comment"

will become 1 + 1 # here is 'comment'

There are hidden options which can control the behaviour of this function: the argument keep.comment gets its value from options('keep.comment') by default; keep.blank.line from options('keep.blank.line'), keep.space from options('keep.space'), and replace.assign from options('replace.assign'). If these options are NULL, the default values will be TRUE, FALSE, FALSE and FALSE respectively.

Also note that if keep.space is FALSE, single lines of long comments will be wrapped into shorter ones automatically. Otherwise, long comments will not be wrapped, so they may exceed the page margin, and \\t will be replaced with \t. Roxygen comments will not be wrapped in any case.

Warning
{ The best strategy to avoid failure is to put comments in complete lines or after complete R expressions. Here are some examples which could make tidy.source fail:

1 + 2 +## comments after an incomplete line

3 + 4

The same is true for blank lines, e.g.

if (TRUE)

{'this is a BAD style of R programming!'}

There should not be a blank line after the if statement.

And the comments right after the curly brace will be moved to the next line, e.g.

if (TRUE) {## comments

}

will become if (TRUE) {

## comments

} } library(formatR)

## use the 'text' argument src = c(" # a single line of comments is preserved", "1+1", " ", "if(TRUE){", "x=1 # inline comments", "}else{", "x=2;print('Oh no... ask the right bracket to go away!')}", "1*3 # one space before this comment will become two!", "2+2+2 # 'short comments'", " ", "lm(y~x1+x2, data=data.frame(y=rnorm(100),x1=rnorm(100),x2=rnorm(100))) ### only 'single quotes' are allowed in comments", "1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1 ## comments after a long line", "## tabs/spaces before comments: use keep.space=TRUE to keep them", "'a character string with in it'", "# note tabs will be converted to spaces when keep.space = TRUE", paste("## here is a", paste(rep("long", 20), collapse = " "), "comment"))

## source code cat(src, sep = "")

## the formatted version tidy.source(text = src)

## other options: preserve leading spaces tidy.source(text = src, keep.space = TRUE)

## preserve blank lines tidy.source(text = src, keep.blank.line = TRUE)

## discard comments! tidy.source(text = src, keep.comment = FALSE)

## wanna see the gory truth?? tidy.source(text = src, output = FALSE)$text.mask

## tidy up the source code of image demo x = file.path(system.file(package = "graphics"), "demo", "image.R")

# to console tidy.source(x)

# to a file f = tempfile() tidy.source(x, keep.blank.line = TRUE, file = f)

## check the original code here and see the difference file.show(x) file.show(f)

## use global options options(keep.comment = TRUE, keep.blank.line = FALSE) tidy.source(x)

## if you've copied R code into the clipboard if (interactive()) { tidy.source("clipboard") ## write into clipboard again tidy.source("clipboard", file = "clipboard") }

## the if-else structure tidy.source(text = c("{if(TRUE)1 else 2; if(FALSE){1+1", "## comments", "} else 2}")) [object Object] http://yihui.name/en/2010/04/formatr-farewell-to-ugly-r-code/ parse, deparse, cat IO