knitr使代码中的PDF成为(在我的情况下)R和LaTEX的组合.可以从子文档中组装文档.
正如我现在使用的那样,文档是由全局变量组合而成,传入和传出每个子文档.这样可以轻松生成意大利面条代码.
有没有办法让R变量成为子文档的"本地"?如何明确导出变量?
我可以在子doc的末尾将每个局部变量都清空,但我想知道是否有一些合理的正式机制来放松子文档之间的代码耦合.
knitr
评估公共环境中的所有块(返回者knit_global()
).这是设计的; 就像源文件中的所有代码都在同一环境中运行一样,所有块都在公共环境中执行.这同样适用于子文档,因为它们(原则上,在技术上不是)只是主文档的一部分,外部化到另一个文件.
这并不一定会导致意大利面条代码:没有什么能阻止用户使用函数和其他对象来组织knitr
文档中的代码/数据.但可能很少有用户这样做......
因此,没有用于块/子文档的封装机制的原因是它们应该共享公共环境,因为它们是一个(主)文档的一部分.
但是,它是可能包括在给出了对象子文档和主文档共享的用户控制的一种方式子文档.该解决方案基于knit_child()
与块选项 非常相似的功能child
.knit_child()
直接调用(相对于通过child
选项隐式调用)的优点是可以设置envir
定义"要评估代码块的环境"的参数(from ?knit
).
在周围knit_child()
,我写了包装器IsolatedChild
来简化问题:
IsolatedChild <- function(input, ...) { evaluationEnv <- list2env(x = list(...), parent = as.environment(2)) cat(asis_output(knit_child(input = input, envir = evaluationEnv, quiet = TRUE))) return(evaluationEnv) }
传递给的参数...
将在子文档中提供.(将它们命名,请参见下面的示例.)该函数返回已评估子文档的环境.
指定parent
中list2env
是至关重要的,我选择as.environment(2)
按照这个答案.否则parent
将默认为parent.frame()
,从而将对象暴露knit_global()
给子文档.
assign
可用于使IsolatedChild
全局环境中可用的对象返回.
请注意,无论当前块中的设置如何,cat(asis_output())
围绕knit_child
该构造都可确保子文档的输出正确包含在主文档results
中.
在转向示例之前,最后两个评论:
如果孩子和主文档不应该共享任何对象,这种方法过于复杂.只需knit
将子文档用于\include{}
将其包含在主文档中.
这种方法可能会带来一些陷阱.特别是"孤立的孩子"的封闭环境需要谨慎,因为搜索路径可能看起来与预期不同.请注意主文档和子文档共享knitr
选项.此外,这两个文件可以通过副作用互动(options()
,par()
,打开设备...).
下面是一个完整的示例/演示:
块inputNormal
没有什么特别之处,它只是对正常行为的证明.inputHidden
演示了如何使用IsolatedChild()
,将两个变量传递给子文档.
IsolatedChild()
返回这两个值以及在子项中创建的第三个对象.
check
表明传递给"孤立子"的对象/创建的对象不会污染全局环境.
import
展示了如何assign
使用"导入"对象从"孤立子"到全局环境.
main.Rnw
:
\documentclass{article} \begin{document} <>= library(knitr) objInMain <- TRUE IsolatedChild <- function(input, ...) { evaluationEnv <- list2env(x = list(...), parent = as.environment(2)) cat(asis_output(knit_child(input = input, envir = evaluationEnv, quiet = TRUE))) return(evaluationEnv) } @ < >= @ < >= returned <- IsolatedChild(input = "child_hidden.Rnw", passedValue = 42, otherPassedValue = 3.14) cat(sprintf("Returned from hidden child: \\texttt{%s}", paste(ls(returned), collapse = ", "))) @ < >= cat(sprintf("In global evaluation environment: \\texttt{%s}", paste(ls(), collapse = ", "))) @ < >= assign("objInChildHidden", returned$objInChildHidden) cat(sprintf("In global evaluation environment: \\texttt{%s}", paste(ls(), collapse = ", "))) @ \end{document}
child_normal.Rnw
:
<>= objInChildNormal <- TRUE # visible in main.Rnw (standard behaviour) @
child_hidden.Rnw
:
Text in \texttt{child\_hidden.Rnw}. <>= objInChildHidden <- TRUE print(sprintf("In hidden child: %s", paste(ls(), collapse = ", "))) # Returns FALSE. # Would be TRUE if "parent" weren't specifiet in list2env(). exists("objInMain", inherits = TRUE) @
main.pdf
: