11.18 オプションフック (*)

あるチャンクオプションを, 他のチャンクオプションの値に応じて動的に変えたいことがあるかもしれません. これは, opts_hooks オブジェクトを使ってオプションフックを設定すればできます. オプションフックはオプションと関連付けられた関数で, 対応するチャンクオプションが NULL でないときに実行されます. この関数は入力引数として現在のチャンクのオプションのリストを受け取り, そのリストを (変更も加えて) 返します. 例えば fig.width オプションを常に fig.height より小さくならないように調整することができます.

knitr::opts_hooks$set(fig.width = function(options) {
  if (options$fig.width < options$fig.height) {
    options$fig.width <- options$fig.height
  }
  options
})

fig.widthNULL になることはないので, このフック関数は必ずコードチャンクの直前に実行され, チャンクオプションを更新します. 以下のコードチャンクは, 上記のオプションフックが設定されていれば, fig.width が初期値の5の代わりに実際には6になります.

```{r fig.width = 5, fig.height = 6}
plot(1:10)
```

別の例として, 第11.12説の最後の例を書き換えて, 単一のチャンクオプション console = TRUE を用いて comment = ""prompt = TRUE を意味できるようにしました. consoleknitr の固有のチャンクオプションでなく, 任意の名前のカスタムオプションであることに注意してください. デフォルト値は NULL です. 以下はその完全な例です.

```{r, include=FALSE}
knitr::opts_hooks$set(console = function(options) {
  if (isTRUE(options$console)) {
    options$comment <- ''; options$prompt <- TRUE
  }
  options
})
```

デフォルトの出力.

```{r}
1 + 1
if (TRUE) {
  2 + 2
}
```

`console = TRUE` で出力.

```{r, console=TRUE}
1 + 1
if (TRUE) {
  2 + 2
}
```

3つ目の例はどうやって自動的にソースコード・テキスト出力・メッセージ・警告・エラーの出力ブロックに行番号を追加するかに関するものです. 行番号を追加するために attr.source, attr.output といったチャンクオプションを使用する方法は5.7節で紹介しています. ここでは単一のチャンクオプション (この例では numberLines) で行番号を追加するかどうかを制御したいとします.

knitr::opts_hooks$set(
  numberLines = function(options) {
    attrs <- paste0("attr.", options$numberLines)
    options[attrs] <- lapply(options[attrs], c, ".numberLines")
    options
  }
)

knitr::opts_chunk$set(
  numberLines = c(
    "source", "output", "message", "warning", "error"
  )
)

基本的に, オプションフック numberLines.numberLines 属性を出力ブロックに追加します. opts_chunk$set() によってチャンクオプションnumberLunes が設定されオプションフックが確実に実行されます.

上記の設定では, チャンクオプション numberLines をコードチャンクで使用して, そのチャンクの出力ブロックのどの部分に行番号を付けるかを決めることができます. 例えば numberLines = c('source', 'output') のように. numberLines = NULL は行番号を完全に削除します.

このアプローチはチャンクオプションを直接設定するのと何が違うのでしょうか. 例えば第5.7節のように, 単に knitr::opts_chunk$set(attr.source = '.numberLines') とする場合と違って, ここでオプションフックを使う利点は .numberLines 属性をチャンクオプションに追加するというのみですが, これは既にあるチャンクオプションの値を上書きすることを意味しません. 例えば以下のチャンクのソースコードブロックは (既に設定してある) 行番号が付いていますが, 番号付を2行目から始めます.

```{r, attr.source='startFrom="2"'}
# このコメント行には番号がつかない
1 + 1
```

これは以下と同等です.

```{r, attr.source=c('startFrom="2"', '.numberLines'}
# このコメント行には番号がつかない
1 + 1
```