检测shiny是否运行R代码

Detecting whether shiny runs the R code

我想 运行 在两个位置编写 R 代码,一个是 Rnw 文件,另一个是交互式 shiny R markdown 文档。

因此,由于交互式闪亮组件在 Rnw 文件中不起作用,我需要的是 R 中的代码片段,用于检测是否加载交互式代码。

似乎 可行,但感觉像是一个快速破解:

if (exists("input")) { # input is provided by shiny
    # interactive components like renderPlot for shiny
} else {
    # non-interactive code for Rnw file
}

是否有稳定的解决方案或我可以访问的全局变量之类的东西来说明 shiny 目前是否 运行ning?或者我应该检查是否加载了 shiny 包?

什么最安全?

更新:在 Konrad Rudolphs 发表评论后,我重新考虑了我的方法。我的原始答案可以在下面找到。

我的方法与 Konrad Rudolphs 不同,可能与 OP 最初的想法不同。代码不言自明:

if (identical(rmarkdown::metadata$runtime, "shiny")) {
  "shinyApp" 
} else {
  "static part"
}

我不会 运行 来自应用程序内部的这段代码,而是将其用作应用程序的包装器。如果代码位于 YAML 前端的 .Rmdruntime: shiny 中,它将启动应用程序,否则,它将显示静态部分。

我想这应该可以满足您的要求,并且尽可能稳定。


我最初的想法是无论您是否在交互式文档中都进行硬编码:

document_is_interactive <- TRUE

if (document_is_interactive) {
    # interactive components like renderPlot for shiny
} else {
    # non-interactive code for Rnw file
}

虽然可能,但这可能会导致问题,因此会比 rmarkdown::metadata$runtime 的其他方法更不稳定。

此信息直接通过 Shiny 的 isRunning function.

提供

以下已过时的答案:

您可以执行以下操作:

shiny_running = function () {
    # Look for `runApp` call somewhere in the call stack.
    frames = sys.frames()
    calls = lapply(sys.calls(), `[[`, 1)
    call_name = function (call)
        if (is.function(call)) '<closure>' else deparse(call)
    call_names = vapply(calls, call_name, character(1))

    target_call = grep('^runApp$', call_names)

    if (length(target_call) == 0)
        return(FALSE)
    
    # Found a function called `runApp`, verify that it’s Shiny’s.
    target_frame = frames[[target_call]]
    namespace_frame = parent.env(target_frame)
    isNamespace(namespace_frame) && environmentName(namespace_frame) == 'shiny'
}

现在您可以简单地在代码中使用 shiny_running() 并返回一个逻辑值,该值指示文档是否 运行 作为 Shiny 应用程序。

根据 discussion on Shiny the mailing list 的说法,这可能是(接近)最好的方法 — 但请注意讨论中提到的注意事项。

改编自code in the “modules” package

或者,以下工作。它可能更适合 Shiny/RMarkdown 用例,但需要 YAML 前端的存在:它通过从中读取 runtime 值来工作。

shiny_running = function ()
    identical(rmarkdown::metadata$runtime, 'shiny')

现在有一个函数 shiny::isRunning()