Skip to content

Commit

Permalink
feat: Run examples from any package (#4005)
Browse files Browse the repository at this point in the history
* chore: `inst/shiny` -> `inst/examples-shiny`

* feat(runExamples): Find examples in any package

* refactor: code style

* refactor: small code style changes

* docs: fix runApp typo

* chore: include package name in valid examples message

* chore(runExample): check that `package` is installed

* chore: use braced package name

* Update news

---------

Co-authored-by: Carson Sievert <[email protected]>
  • Loading branch information
gadenbuie and cpsievert authored Mar 21, 2024
1 parent c73e1a2 commit 43698f0
Show file tree
Hide file tree
Showing 3 changed files with 59 additions and 23 deletions.
2 changes: 2 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@

* Added `onUnhandledError()` to register a function that will be called when an unhandled error occurs in a Shiny app. Note that this handler doesn't stop the error or prevent the session from closing, but it can be used to log the error or to clean up session-specific resources. (thanks @JohnCoene, #3993)

* `runExamples()` now uses the `{bslib}` package to build the user interface (UI). It also gains a `package` argument so that other packages can leverage this same function to run Shiny app examples. For more, see `?runExamples`. (#3963, #4005)

## Bug fixes

* Notifications are now constrained to the width of the viewport for window widths smaller the default notification panel size. (#3949)
Expand Down
66 changes: 44 additions & 22 deletions R/runapp.R
Original file line number Diff line number Diff line change
Expand Up @@ -447,6 +447,16 @@ stopApp <- function(returnValue = invisible()) {
#' @param display.mode The mode in which to display the example. Defaults to
#' `showcase`, but may be set to `normal` to see the example without
#' code or commentary.
#' @param package The package in which to find the example (defaults to
#' `"shiny"`).
#'
#' To provide examples in your package, store examples in the
#' `inst/examples-shiny` directory of your package. Each example should be
#' in its own subdirectory and should be runnable when [runApp()] is called
#' on the subdirectory. Example apps can include a `DESCRIPTION` file and a
#' `README.md` file to provide metadata and commentary about the example. See
#' the article on [Display Modes](https://shiny.posit.co/r/articles/build/display-modes/)
#' on the Shiny website for more information.
#' @inheritParams runApp
#'
#' @examples
Expand All @@ -462,34 +472,46 @@ stopApp <- function(returnValue = invisible()) {
#' system.file("examples", package="shiny")
#' }
#' @export
runExample <- function(example=NA,
port=getOption("shiny.port"),
launch.browser = getOption('shiny.launch.browser', interactive()),
host=getOption('shiny.host', '127.0.0.1'),
display.mode=c("auto", "normal", "showcase")) {
legacy <- getOption('shiny.legacy.examples', FALSE)
examplesDir <- if (isTRUE(legacy)) 'examples' else 'examples-shiny'
examplesDir <- system_file(examplesDir, package='shiny')
runExample <- function(
example = NA,
port = getOption("shiny.port"),
launch.browser = getOption("shiny.launch.browser", interactive()),
host = getOption("shiny.host", "127.0.0.1"),
display.mode = c("auto", "normal", "showcase"),
package = "shiny"
) {
if (!identical(package, "shiny") && !is_installed(package)) {
rlang::check_installed(package)
}

use_legacy_shiny_examples <-
identical(package, "shiny") &&
isTRUE(getOption('shiny.legacy.examples', FALSE))

examplesDir <- system_file(
if (use_legacy_shiny_examples) "examples" else "examples-shiny",
package = package
)

dir <- resolve(examplesDir, example)

if (is.null(dir)) {
valid_examples <- sprintf(
'Valid examples in {%s}: "%s"',
package,
paste(list.files(examplesDir), collapse = '", "')
)

if (is.na(example)) {
errFun <- message
errMsg <- ''
}
else {
errFun <- stop
errMsg <- paste('Example', example, 'does not exist. ')
message(valid_examples)
return(invisible())
}

errFun(errMsg,
'Valid examples are "',
paste(list.files(examplesDir), collapse='", "'),
'"')
}
else {
runApp(dir, port = port, host = host, launch.browser = launch.browser,
display.mode = display.mode)
stop("Example '", example, "' does not exist. ", valid_examples)
}

runApp(dir, port = port, host = host, launch.browser = launch.browser,
display.mode = display.mode)
}

#' Run a gadget
Expand Down
14 changes: 13 additions & 1 deletion man/runExample.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 43698f0

Please sign in to comment.