2013-05-08 71 views
17

當我金銀絲/糾結的文件提取將R塊到一個腳本,有沒有什麼辦法:knitr - 從`purl(...)`排除塊?

  • 排除任意塊(由名字說)?
  • 如果不是,排除一個塊如果eval=F(或者我可以定義一個塊鉤子/選項include=F)?

例如,假設我有以下RMD:

```{r setup, echo=F} 
library(MASS) 
``` 
First, we perform the setup (assume for some reason I need to evaluate `setup` 
silently before I wish to display the chunk to the user, hence the repetition) 
```{r setup, eval=F} 
``` 

Here's the function I've been explaining: 
```{r function} 
plus <- function (a, b) a + b 
``` 

And here's an example of its use: 
```{r example} 
plus(1, 2) 
``` 

糾結的腳本是這樣的:

## @knitr setup, echo=F 
library(MASS) 

## @knitr setup, eval=F 
library(MASS) 

## @knitr function 
plus <- function (a, b) a + b 

## @knitr example 
plus(1, 2) 

我有這個想法,因爲我沒」 t想要評估特定的塊,它們至少不應該出現在輸出中(在上面的例子中,th e second setup chunk)。

此外,對於我來說,將某些塊標記爲「不可見」就糾結輸出而言是不錯的選擇。我不希望在我的輸出腳本中使用example塊(爲了文檔的目的,它在Rmd中很不錯,但是我希望能夠糾結Rmd,如果我想使用plus函數,則只需source('myfile.r'),而不必擔心這些額外的例子執行目前我糾結Rmd然後手動編輯出我不想出來的腳本塊,這似乎違反了只編寫一個Rmd將提供文檔和腳本的原則沒有額外的努力。)

+0

注 - 標記塊用'包括= F'將從'purl''d輸出中刪除它,但也* *從RMD(在從GitHub即knitr的版本;特徵沒有按」 t似乎在我的計算機的版本1.2),所以這是不理想的我的'示例'塊(我想要它*包括*在Rmd並從purl'd輸出中刪除) – 2013-05-08 05:53:59

+0

當然有很多空間改進'purl()',這是不太常用的,因此開發得不太好 – 2013-05-23 06:58:03

+0

有沒有辦法只從Rmd中提取r塊? – KLDavenport 2013-06-15 02:16:34

回答

20

由於knitr 1.3,有一個新的塊選項purl = TRUE/FALSE允許包含/排除purl()的某些代碼塊。

```{r test, purl=FALSE} 
library(MASS) 
``` 
7

糾結處理模塊目前不擴大PARAMS,但我們可以把它這樣做...

# See `?trace` documentation for details. 
bdy <- as.list(body(knitr:::process_tangle.block)) 
trace.at <- which(grepl(".*opts_chunk\\$merge.*", 
         as.list(body(knitr:::process_tangle.block)))) 
tracer <- quote({ 
    # Code borrowed from normal chunk procesing. 
    af = opts_knit$get('eval.after'); al = opts_knit$get('aliases') 
    if (!is.null(al) && !is.null(af)) af = c(af, names(al[af %in% al])) 
    for (o in setdiff(names(params), af)) params[o] = list(eval_lang(params[[o]])) 
    # Omit this if using lastest knitr source from github. 
    if(isFALSE(params$include)) { 
    tmp <- knit_code$get(); 
    tmp[[params$label]] <- ""; 
    knit_code$restore(tmp) 
    } 
}) 

trace(knitr:::process_tangle.block, tracer=tracer, at=trace.at, print=FALSE) 

然後金銀絲()排除可以通過選項參數來控制......

```{r setup, echo=TRUE, results='hide'} 
library(MASS) 
```` 

First, we perform the setup (assume for some reason I need to evaluate `setup` 
silently before I wish to display the chunk to the user, hence the repetition) 
```{r setup2, ref.label="setup", echo=FALSE, results='markup'} 
``` 

Here's the function I've been explaining: 
```{r function} 
plus <- function (a, b) a + b 
``` 

And here's an example of its use: 
```{r example, eval=!opts_knit$get("tangle") } 
plus(1, 2) 
``` 

And here's another example of its use: 
```{r example2, include=!opts_knit$get("tangle") } 
plus(3, 3) 
``` 
+0

但是,這仍然不允許我*排除*塊(例如,在我給出的問題中,我想排除「示例」塊) – 2013-06-18 02:03:12

+0

@ mathematical.coffee,請參閱編輯;應該現在工作正常。 – Thell 2013-06-19 22:41:19

+0

@ mathematicalcalc @ thell謝謝您的探索;我想我會添加一個單獨的塊選項來允許某些塊從'purl()'中排除;讓我多想一想。 – 2013-06-20 23:28:32

3

雖然這更多的是一種技巧比的解決方案,你仍然可以修改從一些正則表達式金銀絲產生的腳本。

例如用下面的函數(可能存在用於正則表達式的更簡單的解決方案):

dropchunks <- function(scriptname, what.to.drop){ 
    script <- readLines(scriptname) 
    script <- do.call(paste, list(script, collapse = "\n")) 
    subpattern = paste0("(", do.call(paste, list(what.to.drop, collapse="|")), ")") 
    mainpattern <- paste('(?s)## @knitr ((?!## @knitr).)*?', subpattern, '.*?((?=## @knitr)|$)', sep="") 
    script <- gsub(pattern = mainpattern, replacement = "", x = script, perl=TRUE) 
    writeLines(text = script, con= scriptname) 
} 

然後可以做到這一點,以除去含有的eval = F所有代碼塊:

library(knitr) 
purl("test.Rmd") 
dropchunks("test.R", "eval=F") 

您可以這樣做,以刪除名爲「函數」或「示例」的塊(實際上,它將刪除任何包含這些單詞的塊,但可以通過更改正則表達式來更改):

purl("test.Rmd") 
dropchunks("test.R", c("function", "example")) 
+0

我喜歡這個主意!由於knitr不會抱怨塊中的未知參數,因此可以將簡單的'''{r test,purl = F}設置爲默認的「what.to.drop」。 – Thell 2013-06-17 23:32:33