formatR は、 CRAN からインストールすることができます。 最新バージョンは、 yihui.r-universe.dev からテストすることができます。
install.packages("formatR", repos = "http://cran.rstudio.com")
# or development version
options(repos = c(yihui = "https://yihui.r-universe.dev", CRAN = "https://cloud.r-project.org"))
install.packages("formatR")
または、github のことがわかるのであれば、 Github repository を checkout して、 ソースからインストールしてください。 このページは、常に開発バージョンです。
library(formatR)
sessionInfo()
## R version 3.6.3 (2020-02-29)
## Platform: x86_64-apple-darwin16.7.0 (64-bit)
## Running under: macOS Sierra 10.12.6
##
## Matrix products: default
## BLAS: /System/Library/Frameworks/Accelerate.framework/Versions/A/Frameworks/vecLib.framework/Versions/A/libBLAS.dylib
## LAPACK: /System/Library/Frameworks/Accelerate.framework/Versions/A/Frameworks/vecLib.framework/Versions/A/libLAPACK.dylib
##
## locale:
## [1] ja_JP.UTF-8/ja_JP.UTF-8/ja_JP.UTF-8/C/ja_JP.UTF-8/ja_JP.UTF-8
##
## attached base packages:
## [1] stats graphics grDevices utils datasets methods
## [7] base
##
## other attached packages:
## [1] formatR_1.9
##
## loaded via a namespace (and not attached):
## [1] digest_0.6.27 R6_2.5.0 jsonlite_1.7.1
## [4] magrittr_2.0.1 evaluate_0.14 rlang_0.4.10
## [7] stringi_1.5.3 jquerylib_0.1.3 bslib_0.2.4
## [10] rmarkdown_2.7 tools_3.6.3 stringr_1.4.0
## [13] xfun_0.22 yaml_2.2.1 compiler_3.6.3
## [16] htmltools_0.5.1.1 knitr_1.31 sass_0.3.1
formatR パッケージは、Rのコードを再フォーマットして読みやすくするために設計されました。 主な働きは、関数 tidy_source()
です。 機能は以下の通りです。
}
を除いた別の行にある else
ステートメントは、1行後ろに移動します。=
は、<-
に置き換えることができます。{
は、新しい行に移動できます。Below is an example of what tidy_source()
can do. The source code is:
## comments are retained;
# a comment block will be reflowed if it contains long comments;
#' roxygen comments will not be wrapped in any case
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 # only 'single quotes' are allowed in comments
lm(y~x1+x2, data=data.frame(y=rnorm(100),x1=rnorm(100),x2=rnorm(100))) ### a linear model
1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1+1 # comment after a long line
## here is a long long long long long long long long long long long long long comment that may be wrapped
上記のコードをクリップボードにコピーして、tidy_source(width.cutoff = 50)
と入力すると、以下のようになります。
## comments are retained; a comment block will be
## reflowed if it contains long comments;
#' roxygen comments will not be wrapped in any case
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 # only 'single quotes' are allowed in comments
lm(y ~ x1 + x2, data = data.frame(y = rnorm(100), x1 = rnorm(100),
x2 = rnorm(100))) ### a linear model
1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 +
1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 # comment after a long line
## here is a long long long long long long long long
## long long long long long comment that may be
## wrapped
tidy_source()
の2つのアプリケーション:
tidy_dir()
は、ディレクトリ内のすべての R スクリプトを再フォーマットする。
例えば、 usage()
と args()
のデフォルト出力を比較してみてください。
library(formatR)
usage(glm, width = 40) # can set arbitrary width here
## glm(formula, family = gaussian, data,
## weights, subset, na.action,
## start = NULL, etastart, mustart,
## offset, control = list(...),
## model = TRUE, method = "glm.fit",
## x = FALSE, y = TRUE,
## singular.ok = TRUE,
## contrasts = NULL, ...)
args(glm)
## function (formula, family = gaussian, data, weights, subset,
## na.action, start = NULL, etastart, mustart, offset, control = list(...),
## model = TRUE, method = "glm.fit", x = FALSE, y = TRUE, singular.ok = TRUE,
## contrasts = NULL, ...)
## NULL
もしshinyパッケージがインストールされていれば、関数 tidy_app()
で、 次のようにRコードを再フォーマットする Shiny アプリを起動することができま。 (live demo):
formatR::tidy_app()
Format
ボタンを押したあと:
訳注: 上の二つの絵は、もともとウェブ上にありましたが、エラーが出たためにローカル(同一サイト内)へのリンクに変更しました。
Rで実行された他の人のコードからRのコードをコピーしようとすると、面倒なことがあります。 コードの先頭にプロンプト文字(通常は>
)が付けられている場合、実行する前にすべてのプロンプト >
と+
を手動で削除しなければなりません。 しかし、コードの出力を添付することができれば、読者がコードを理解するのに便利です. これが、関数 tidy_eval()
の動機となっています。 この関数は、tidy_source()
を使ってソースコードを再フォーマットし、コードを chunk で評価し、各 chunk の出力をコメントとして添付します。 元のソースコードを壊すことはありません。 以下にその例を示します。
set.seed(123)
tidy_eval(text = c("a<-1+1;a # print the value", "matrix(rnorm(10),5)"))
a <- 1 + 1
a # print the value
## [1] 2
matrix(rnorm(10), 5)
## [,1] [,2]
## [1,] -0.56047565 1.7150650
## [2,] -0.23017749 0.4609162
## [3,] 1.55870831 -1.2650612
## [4,] 0.07050839 -0.6868529
## [5,] 0.12928774 -0.4456620
デフォルトのソースは、tidy_source()
のようにクリップボードからなので、コードをクリップボードにコピーして、これをRで実行するだけです。:
library(formatR)
tidy_eval()
# without specifying any arguments, it reads code from clipboard
セクション2のサンプルコードの続きで、tidy_source()
で異なる引数を使用します。 arrow
, blank
, indent
, brace.newline
, comment
などなど。
=
を <-
に置換if (TRUE) {
x <- 1 # inline comments
} else {
x <- 2
print("Oh no... ask the right bracket to go away!")
}
なお、5行目(空の行)は捨てられています。:
## comments are retained; a comment block will be reflowed if it
## contains long comments;
#' roxygen comments will not be wrapped in any case
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!
if (TRUE) {
x = 1 # inline comments
} else {
x = 2
print("Oh no... ask the right bracket to go away!")
}
%>%
formatR 1.9以降、演算子 %>%
, %T%
, %$%
, %<>%
を含むコード行は、これらの演算子の後に自動的にラップされます。 例えば、
mtcars %>% subset(am == 0) %>% lm(mpg~hp, data=.)
これは、以下のようになります。:
mtcars %>%
subset(am == 0) %>%
lm(mpg ~ hp, data = .)
{
を新しい行に移動させるif (TRUE)
{
x = 1 # inline comments
} else
{
x = 2
print("Oh no... ask the right bracket to go away!")
}
1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 +
1 + 1 + 1 + 1 + 1 # comment after a long line
## here is a long long long long long long long long long long long long long comment that may be wrapped
1 + 1
if (TRUE) {
x = 1
} else {
x = 2
print("Oh no... ask the right bracket to go away!")
}
1 * 3
2 + 2 + 2
lm(y ~ x1 + x2, data = data.frame(y = rnorm(100), x1 = rnorm(100),
x2 = rnorm(100)))
1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 +
1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1
このパッケージに使われているトリックはとても汚いものです。 formatR の中の関数を使うと危険なことがあるかもしれません。 次のセクションをよく読んで、コメントがどのように保存されるかを正確に知ってください。 失敗を避けるための最良の方法は、コメントを完全な行の中に入れるか、または完全なR式の後に入れることです。 以下は、tidy_source()
が失敗するいくつかの既知のケースです。
1 + 2 + ## comments after an incomplete line
3 + 4
x <- ## this is not a complete expression
5
x <- 1; # you should not use ; here!
不完全なR式の後にコメントがあるコードは、formatR で再フォーマットできません。 ちなみに、tidy_source()
は、{
以降のコメントを次の行に移動します。 例えば、
if (TRUE) {## comments
}
は、
if (TRUE) {
## comments
}
となります。
Rコードの完全なチャンクを分離するために、しばしば空行が使用されます。 任意の空行は、引数 blank = TRUE
の場合、tidy_source()
でも失敗する可能性があります。 例えば、
if (TRUE)
{'this is a BAD style of R programming!'} else 'failure!'
if
文の後に空行があってはいけません。 もちろん、blank = FALSE
でもこの場合は失敗しません。
?
とコメントクエスチョンマーク(?
) を使ってヘルプページを表示することができますが、 formatR パッケージは ?
を使ってコメントを含むコードを正しくフォーマットすることができません。 例えば、
?sd # help on sd()
In this case, it is recommended to use the function help()
instead of the short-hand version ?
.
->
with commentsWe can also use the right arrow ->
for assignment, e.g. 1:10 -> x
. I believe this flexibility is worthless, and it is amazing that a language has three assignment operators: <-
, =
and ->
(whereas almost all other languages uses =
for assignment). Bad news for formatR is that it is unable to format code using both ->
and comments in a line, e.g.
この場合、短縮版の?
ではなく、関数 help()
を使うことをお勧めします。
->
とコメント1:10 -> xのように、右矢印の
->を代入に使うこともできます。 私はこの柔軟性には価値がないと思っていて、1つの言語に3つの代入演算子があるというのは驚きです。
<-,
=,
->(他のほとんどの言語では代入に
=を使用しています)。 **formatR** の悪い点は、一行の中に
->` とコメントの両方を使ったコードをフォーマットできないことです。 例えば、
1:10 -> x # assignment with right arrow
<-
や =
を一貫して使用することをお勧めします。 もっと重要なことは 一貫性です。私はいつも =
を使いますが、それは混乱を招かないからです。 人が fun(a = 1)
を、変数 a
に 1
を代入すると解釈することはありえないと思います。 <-
はどこでも使えるのでより危険です。は、どこでも動作するので、より危険です (無意識のうちに、fun fun(a <- 1)
で無意識に新しい変数a
を作ってしまったかもしれません。 こちら を参照してください。) 唯一の欠点は 唯一の欠点は、ほとんどのRの人が<-`を使うので、他の人との共同作業が難しいかもしれません。
一言で言えば、tidy_source(text = code)
は基本的には deparse(parse(text = code))
です。 実際にはもっと複雑で、ただ一つの理由があります。
deparse(parse(text = "1+2-3*4/5 # a comment"))
## [1] "expression(1 + 2 - 3 * 4/5)"
コメントを保存する方法は、Rの式の中の文字列として保護することです。 例えば、ソースコードの中に1行のコメントがあるとします。:
# asdf
以下のように最初にマスクされます。
invisible(".IDENTIFIER1 # asdf.IDENTIFIER2")
これは合法的なRの表現なので、base::parse()
はこれを扱うことができ、偽装されたコメントを削除することはなくなります。 最終的には、元のコメントを復元するために識別子が削除されます。 つまり、文字列 invisible(".IDENTIFIER1
と .IDENTIFIER2")
は空の文字列に置き換えられます。
インラインコメントは別の方法で処理されます: ハッシュ記号 #
の前に2つのスペースが追加されます。
1+1# comments
これは
1+1 # comments
行内コメントはまず、コメント前のRコードと一緒になって、奇妙な操作に偽装されます。 これは本質的には無意味ですが、構文的には正しいのです。 例えば
1+1 %\b% "# comments"
とすると、base::parse()
がこの式を処理しますが、この場合も偽装されたコメントは削除されません。 最終的には、行内コメントも同様に解放されます。 (演算子 %\b%
とそれを囲む二重引用符を削除します)。
これらのコメントに対する特別な扱いは、base::parse()
と base::depase()
が、 すべてのコメントを削除する代償としてRコードを整頓することができるという事実に起因しています。
tidy_source()
のいくつかの引数をオーバーライドすることができるグローバル・オプションがあります。:
argument | global option | default |
---|---|---|
comment |
options('formatR.comment') |
TRUE |
blank |
options('formatR.blank') |
TRUE |
arrow |
options('formatR.arrow') |
FALSE |
indent |
options('formatR.indent') |
4 |
wrap |
options('formatR.wrap') |
TRUE |
width.cutoff |
options('formatR.width') |
options('width') |
brace.newline |
options('formatR.brace.newline') |
FALSE |
また、wrap = TRUE
の場合、1行の長いコメントは自動的に短いコメントに折り返されますが、roxygen のコメントは折り返されませんのでご注意ください (#'
で始まるコメントはラップされません)。