r语言 - 匹配自定义引擎中的 knitr 文档环境



我有兴趣为knitr制作一个引擎,该引擎可以在发送代码块进行评估之前对其进行预处理,步骤如下:

  1. 预处理options$code
  2. 使用父环境evaluate::evaluate()评估代码
  3. 使用knitr::engine_output()格式化输出

我发现在这些自定义块中创建的任何变量在文档的其余部分中都不可用。经过一番修补,我发现如果我遍历调用堆栈并找到调用 knitr 的最后一个位置,我可以获取envir参数的值并将其用作evaluate::evaluate()的环境。不过,这感觉很笨拙。有没有更好的方法来匹配自定义块引擎中的文档环境?

一个引擎,将翻转附加到所有评论上

knitr::knit_engines$set(flip =
function(options) {
# pre-process code
code <- gsub("(#+?)", "\1 (╯°□°)╯︵", options$code)
# Find environment <--------------- IS THERE A BETTER WAY?
#
# grabbing the call stack
cstack <- vapply(sys.calls(), function(i) paste(as.character(deparse(i)), collapse = "n"), character(1))
fstack <- sys.frames()
# Finding the last instance of the knit function and grabbing the envir variable
knitting <- rev(grep("knit(", cstack, fixed = TRUE))[1]
e <- get("envir", fstack[[knitting]])
OUT <- evaluate::evaluate(code, envir = e)
knitr::engine_output(options, out = OUT)
}
)
tmp <- tempfile(fileext = ".Rmd")
tmpout <- tempfile(fileext = ".md")
txt <- "---noutput: md_documentn---nn```{r}na <- 'A'nan```nn```{flip}nb <- paste(a, 'and B') # FLIPPINnbn```nnSponsored by the letters `r try(b)`n"
cat(txt, file = tmp)
rmarkdown::render(tmp, output_file = tmpout, envir = new.env())
#> processing file: file3230dc4500b.Rmd
#> output file: file3230dc4500b.knit.md
#> /usr/bin/pandoc +RTS -K512m -RTS file3230dc4500b.utf8.md --to markdown_strict --from markdown+autolink_bare_uris+tex_math_single_backslash --output /tmp/Rtmpzc5qWO/file32306aeaf291.md --standalone
#> 
#> Output created: /tmp/Rtmpzc5qWO/file32306aeaf291.md
cat(readLines(tmp), sep = "n")
#> ---
#> output: md_document
#> ---
#> 
#> ```{r}
#> a <- 'A'
#> a
#> ```
#> 
#> ```{flip}
#> b <- paste(a, 'and B') # FLIPPIN
#> b
#> ```
#> 
#> Sponsored by the letters `r try(b)`
cat(readLines(tmpout), sep = "n")
#>     a <- 'A'
#>     a
#>     #> [1] "A"
#> 
#>     b <- paste(a, 'and B') # (╯°□°)╯︵ FLIPPIN
#>     b
#>     #> [1] "A and B"
#> 
#> Sponsored by the letters A and B

创建于 2020-06-16 由 reprex 软件包 (v0.3.0(

事实证明,{knitr} 中有一个函数正是针对这种情况的:knitr::knit_global(),恰好是计算内联代码时的环境:https://github.com/yihui/knitr/blob/0daf31be36eed8d8ec0ba51eedee909283afc45d/R/hooks.R#L13

knitr::knit_engines$set(flip = 
function(options) {
# pre-process code
code <- gsub("(#+?)", "\1 (╯°□°)╯︵", options$code)
e <- knitr::knit_global() # <----- SOLUTION ᕕ( ᐛ )ᕗ
OUT <- evaluate::evaluate(code, envir = e)
knitr::engine_output(options, out = OUT)
}
)
tmp <- tempfile(fileext = ".Rmd")
tmpout <- tempfile(fileext = ".md")
txt <- "---noutput: md_documentn---nn```{r}na <- 'A'nan```nn```{flip}nb <- paste(a, 'and B') # FLIPPINnbn```nnSponsored by the letters `r try(b)`n"
cat(txt, file = tmp)
rmarkdown::render(tmp, output_file = tmpout, envir = new.env())
#> processing file: file3b0117b9cb1f.Rmd
#> output file: file3b0117b9cb1f.knit.md
#> /usr/bin/pandoc +RTS -K512m -RTS file3b0117b9cb1f.utf8.md --to markdown_strict --from markdown+autolink_bare_uris+tex_math_single_backslash --output /tmp/Rtmp1KgoUj/file3b01702d22f0.md --standalone
#> 
#> Output created: /tmp/Rtmp1KgoUj/file3b01702d22f0.md
cat(readLines(tmp), sep = "n")
#> ---
#> output: md_document
#> ---
#> 
#> ```{r}
#> a <- 'A'
#> a
#> ```
#> 
#> ```{flip}
#> b <- paste(a, 'and B') # FLIPPIN
#> b
#> ```
#> 
#> Sponsored by the letters `r try(b)`
cat(readLines(tmpout), sep = "n")
#>     a <- 'A'
#>     a
#>     #> [1] "A"
#> 
#>     b <- paste(a, 'and B') # (╯°□°)╯︵ FLIPPIN
#>     b
#>     #> [1] "A and B"
#> 
#> Sponsored by the letters A and B

创建于 2020-06-16 由 reprex 软件包 (v0.3.0(

相关内容

最新更新