Merge pull request #479 from rstudio/not-just-last-expressions

Allow shinyUI and shinyServer calls to not be the last expression in ui....
This commit is contained in:
Joe Cheng
2014-05-14 09:06:28 -07:00
4 changed files with 34 additions and 15 deletions

35
R/app.R
View File

@@ -106,14 +106,18 @@ shinyAppDir <- function(appDir, options=list()) {
# ui.R as a webpage. The "cachedFuncWithFile" call makes sure that the closure
# we're creating here only gets executed when ui.R's contents change.
uiHandlerSource <- cachedFuncWithFile(appDir, "ui.R", case.sensitive = FALSE,
function() {
# Have to use file.path.ci every time in case the case of ui.R has
# changed. (Hmmm, overengineering a bit?)
uiR <- file.path.ci(appDir, "ui.R")
function(uiR) {
if (file.exists(uiR)) {
# If ui.R contains a call to shinyUI (which sets .globals$ui), use that.
# If not, then take the last expression that's returned from ui.R.
.globals$ui <- NULL
on.exit(.globals$ui <- NULL, add = FALSE)
ui <- source(uiR,
local = new.env(parent = globalenv()),
keep.source = TRUE)$value
if (!is.null(.globals$ui)) {
ui <- .globals$ui[[1]]
}
return(uiHttpHandler(ui))
} else {
return(function(req) NULL)
@@ -126,14 +130,29 @@ shinyAppDir <- function(appDir, options=list()) {
wwwDir <- file.path.ci(appDir, "www")
fallbackWWWDir <- system.file("www-dir", package = "shiny")
serverSource <- cachedSource(appDir, "server.R", case.sensitive = FALSE)
serverSource <- cachedFuncWithFile(appDir, "server.R", case.sensitive = FALSE,
function(serverR) {
# If server.R contains a call to shinyServer (which sets .globals$server),
# use that. If not, then take the last expression that's returned from
# server.R.
.globals$server <- NULL
on.exit(.globals$server <- NULL, add = TRUE)
result <- source(
serverR,
local = new.env(parent = globalenv()),
keep.source = TRUE
)$value
if (!is.null(.globals$server)) {
result <- .globals$server[[1]]
}
return(result)
}
)
# This function stands in for the server function, and reloads the
# real server function as necessary whenever server.R changes
serverFuncSource <- function() {
serverFunction <- serverSource(
local = new.env(parent = globalenv()),
keep.source = TRUE)$value
serverFunction <- serverSource()
if (is.null(serverFunction)) {
return(function(input, output) NULL)
} else if (is.function(serverFunction)) {

View File

@@ -240,6 +240,7 @@ resourcePathHandler <- function(req) {
#'
#' @export
shinyServer <- function(func) {
.globals$server <- list(func)
invisible(func)
}

View File

@@ -246,7 +246,10 @@ renderPage <- function(ui, connection, showcase=0) {
#' @return The user interface definition, without modifications or side effects.
#'
#' @export
shinyUI <- function(ui) ui
shinyUI <- function(ui) {
.globals$ui <- list(ui)
ui
}
uiHttpHandler <- function(ui, path = "/") {

View File

@@ -714,7 +714,7 @@ cachedFuncWithFile <- function(dir, file, func, case.sensitive = FALSE) {
now <- file.info(fname)$mtime
if (!identical(mtime, now)) {
value <<- func(...)
value <<- func(fname, ...)
mtime <<- now
}
value
@@ -725,11 +725,7 @@ cachedFuncWithFile <- function(dir, file, func, case.sensitive = FALSE) {
# calls, unless the file's mtime changes.
cachedSource <- function(dir, file, case.sensitive = FALSE) {
dir <- normalizePath(dir, mustWork=TRUE)
cachedFuncWithFile(dir, file, function(...) {
fname <- if (case.sensitive)
file.path(dir, file)
else
file.path.ci(dir, file)
cachedFuncWithFile(dir, file, function(fname, ...) {
if (file.exists(fname))
return(source(fname, ...))
else