├── .Rbuildignore ├── .gitignore ├── DESCRIPTION ├── NAMESPACE ├── R ├── namespace.R ├── plot.R └── shiny.R ├── README.md ├── app.R ├── man └── my_app.Rd └── tests ├── testthat.R └── testthat └── test-example.R /.Rbuildignore: -------------------------------------------------------------------------------- 1 | # The app.R file is not needed for the package. Only for the remote Shiny app on the server. 2 | ^app.R 3 | 4 | 5 | 6 | ##################################################################### 7 | 8 | # Git and GitHub 9 | .git 10 | .gitignore 11 | README.md 12 | 13 | # For Mac users 14 | .DS_Store 15 | 16 | # History files 17 | .Rhistory 18 | .Rapp.history 19 | 20 | # Session Data files 21 | .RData 22 | 23 | # Output files from R CMD build 24 | /*.tar.gz 25 | 26 | # Output files from R CMD check 27 | /*.Rcheck/ 28 | 29 | # RStudio files 30 | .Rproj.user/ 31 | 32 | # produced vignettes 33 | vignettes/*.html 34 | vignettes/*.pdf 35 | 36 | # OAuth2 token, see https://github.com/hadley/httr/releases/tag/v0.3 37 | .httr-oauth 38 | 39 | # knitr and R markdown default cache directories 40 | /*_cache/ 41 | /cache/ 42 | 43 | # Temporary files created by R markdown 44 | /*.utf8.md 45 | /*.knit.md 46 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | 3 | # History files 4 | .Rhistory 5 | .Rapp.history 6 | 7 | # Session Data files 8 | .RData 9 | 10 | # Example code in package build process 11 | *-Ex.R 12 | 13 | # Output files from R CMD build 14 | /*.tar.gz 15 | 16 | # Output files from R CMD check 17 | /*.Rcheck/ 18 | 19 | # RStudio files 20 | .Rproj.user/ 21 | 22 | # produced vignettes 23 | vignettes/*.html 24 | vignettes/*.pdf 25 | 26 | # OAuth2 token, see https://github.com/hadley/httr/releases/tag/v0.3 27 | .httr-oauth 28 | 29 | # knitr and R markdown default cache directories 30 | /*_cache/ 31 | /cache/ 32 | 33 | # Temporary files created by R markdown 34 | *.utf8.md 35 | *.knit.md 36 | -------------------------------------------------------------------------------- /DESCRIPTION: -------------------------------------------------------------------------------- 1 | Package: appPackage 2 | Type: Package 3 | Title: This Shiny App is a Package! This Package is a Shiny App! 4 | Version: 0.0.0.9000 5 | Date: 2016-11-01 6 | Authors@R: person(family = "Landau", given = "William", email = 7 | "will.landau@gmail.com", role = c("aut", "cre")) 8 | Description: This project can either be deployed to a server as a Shiny app or 9 | installed locally as a package that runs the app. Either way, the 10 | functionality is the same. 11 | License: GPL (>=3) 12 | Depends: R (>= 3.0.0) 13 | Imports: shiny 14 | URL: https://github.com/wlandau/appPackage 15 | RoxygenNote: 5.0.1 16 | NeedsCompilation: no 17 | Packaged: 2016-11-01 21:48:32 UTC; landau 18 | Suggests: testthat 19 | -------------------------------------------------------------------------------- /NAMESPACE: -------------------------------------------------------------------------------- 1 | # Generated by roxygen2: do not edit by hand 2 | 3 | export(my_app) 4 | import(shiny) 5 | importFrom(graphics,hist) 6 | importFrom(stats,rnorm) 7 | -------------------------------------------------------------------------------- /R/namespace.R: -------------------------------------------------------------------------------- 1 | #' @import shiny 2 | #' @importFrom graphics hist 3 | #' @importFrom stats rnorm 4 | NULL 5 | -------------------------------------------------------------------------------- /R/plot.R: -------------------------------------------------------------------------------- 1 | my_plot = function(number_observations){ 2 | hist(rnorm(number_observations), col = 'darkgray', border = 'white') 3 | } -------------------------------------------------------------------------------- /R/shiny.R: -------------------------------------------------------------------------------- 1 | my_server <- function(input, output) { 2 | output$distPlot <- renderPlot({ 3 | my_plot(input$obs) 4 | }) 5 | } 6 | 7 | # Needs to be a function so nested dependencies are lazily loaded. 8 | my_ui <- function(){fluidPage( 9 | sidebarLayout( 10 | sidebarPanel( 11 | sliderInput("obs", "Number of observations:", min = 10, max = 500, value = 100) 12 | ), 13 | mainPanel(plotOutput("distPlot")) 14 | ) 15 | )} 16 | 17 | #' @title Function \code{my_app} 18 | #' @description Runs the Shiny app. 19 | #' @export 20 | my_app = function(){ 21 | shinyApp(ui = my_ui(), server = my_server) 22 | } 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Do you like the interactivity of [Shiny apps](http://shiny.rstudio.com/)? Do you also like the modularity and [unit testing](http://r-pkgs.had.co.nz/tests.html) of [R packages](http://r-pkgs.had.co.nz/)? Check out this small example to get the best of both worlds. 2 | 3 | # It's a Shiny app! 4 | 5 | The customary [`app.R`](http://shiny.rstudio.com/articles/single-file.html) is in the root directory, so you can launch the project as a Shiny app on a server as is. No package installation is required. Instead, `devtools::load_all()` in `app.R` automatically loads all the required R scripts and data files. 6 | 7 | # It's a package! 8 | 9 | Since `app.R` is listed in [`.Rbuildignore`](http://r-pkgs.had.co.nz/package.html), you can install the package as is. 10 | 11 | ```r 12 | install_github("wlandau/appPackage") 13 | ``` 14 | 15 | Then, you can run the Shiny app locally. 16 | 17 | ```r 18 | library(appPackage) 19 | my_app() 20 | ``` 21 | 22 | # But what if my app uses compiled code? 23 | 24 | Follow the [CRAN directions](https://cran.r-project.org/doc/manuals/r-release/R-exts.html#System-and-foreign-language-interfaces) to build your package on top of [C](https://en.wikipedia.org/wiki/C_(programming_language)), [Fortran](https://en.wikipedia.org/wiki/Fortran), or whatever [compiled language](https://en.wikipedia.org/wiki/Compiled_language) you're using. Then, all you need is an `app.R` that installs the package on the server and then launches your app with a function call. For this example, the server-side `app.R` would look like this. 25 | 26 | ```r 27 | install_github("wlandau/appPackage") 28 | library(appPackage) 29 | my_app() 30 | ``` 31 | 32 | Here, feel free to discard the `app.R` inside the package and remove the `app.R` listing from `.Rbuildignore`. 33 | 34 | 35 | # What of my project gets too big and messy? 36 | 37 | Overambitious projects tend to get bloated, cluttered, and slow, especially when substance and interactivity fall under the same roof. If you do serious computation behind the scenes in xyzShinyApp, you could encapsulate the hidden core functionality in a separate package: say, xyzEngine. I used this exact approach in my dissertation project. Package fbseq processes user input and Monte Carlo output, and fbseqCUDA actually fits the model given an already-parsed set of instructions. 38 | 39 | -------------------------------------------------------------------------------- /app.R: -------------------------------------------------------------------------------- 1 | devtools::load_all() 2 | my_app() 3 | -------------------------------------------------------------------------------- /man/my_app.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/shiny.R 3 | \name{my_app} 4 | \alias{my_app} 5 | \title{Function \code{my_app}} 6 | \usage{ 7 | my_app() 8 | } 9 | \description{ 10 | Runs the Shiny app. 11 | } 12 | 13 | -------------------------------------------------------------------------------- /tests/testthat.R: -------------------------------------------------------------------------------- 1 | library(testthat) 2 | library(appPackage) 3 | 4 | test_check("appPackage") 5 | -------------------------------------------------------------------------------- /tests/testthat/test-example.R: -------------------------------------------------------------------------------- 1 | context("example") 2 | 3 | test_that("example of a test runs as expected", { 4 | expect_silent(my_plot(5)) 5 | unlink("Rplots.pdf") 6 | }) --------------------------------------------------------------------------------