# app/view/display.R
# import data and plot modules
box::use(
app / logic / data,
app / logic / plot
)25 rhino
This chapter briefly describes a version of sap built using the rhino framework. The branch in this chapter is slightly different than the previous golem and leprechaun frameworks, because rap is not an R package. If youβre developing in RStudio
, instead of loading, documenting, and installing rap, weβre going to re-initialize the IDE by selecting Session > Terminate Rβ¦
When RStudio
re-opens, we see the rap files and notice the Build pane has been removed:
To reiterate, the Build pane is deactivated because rhino applications arenβt R packages.1
Launch the application in rap by opening the app.R file and clicking Run App (or by passing rhino::app() into the Console).
Launch app with the shinypak package:
launch('25_rhino')25.1 rap (a rhino app)
The files in rap are below:
βββ .git
βββ .github
β βββ workflows
β βββ rhino-test.yml
βββ .gitignore
βββ .lintr
βββ .renvignore
βββ .rhino
β βββ .eslintrc.json
β βββ .gitignore
β βββ .stylelintrc.json
β βββ babel.config.json
β βββ node_modules
β βββ package-lock.json
β βββ package.json
β βββ prettier.config.mjs
β βββ webpack.config.js
βββ .Rhistory
βββ .Rprofile
βββ .rscignore
βββ app
β βββ js
β β βββ index.js
β βββ logic
β β βββ __init__.R
β β βββ data.R
β β βββ plot.R
β βββ main.R
β βββ static
β β βββ css
β β βββ favicon.ico
β β βββ js
β βββ styles
β β βββ main.scss
β βββ view
β βββ __init__.R
β βββ aes_inputs.R
β βββ clicks.R
β βββ display.R
β βββ message.R
β βββ var_inputs.R
βββ app.R
βββ config.yml
βββ dependencies.R
βββ README.md
βββ renv
β βββ .gitignore
β βββ activate.R
β βββ library
β β βββ macos
β βββ settings.json
β βββ staging
βββ renv.lock
βββ rhino.yml
βββ sap.Rproj
βββ tests
βββ cypress
β βββ .gitignore
β βββ e2e
βββ cypress.config.js
βββ testthat
β βββ _snaps
β βββ setup-shinytest2.R
β βββ test-aes_inputs.R
β βββ test-data.R
β βββ test-display.R
β βββ test-main.R
β βββ test-plot.R
β βββ test-rap-feature-01.R
β βββ test-shinytest2.R
β βββ test-var_inputs.R
βββ testthat.R- 1
-
CI/CD via GitHub actions
- 2
-
Lintr (from
lintrpackage) - 3
-
renvignore (works like.gitignore) - 4
-
rhinoapp dependencies - 5
-
Activates the
renvpackage - 6
-
renvlibrary of packages in app project
As we can see, most of the standard R package folders and files are missing from rap, because rhino applications use the box package for importing dependencies and organizing code.2
25.2 rhino features
The rhino website explains the philosophy behind the application structure above, so I wonβt repeat that information here. However, I highly recommend reading the available documentation on rhino and box before deciding to adopt this framework.3
25.3 box modules
A box module (not to be confused with a Shiny module) is a collection of .R scripts in a specified folder. The modules in a new rhino app are stored in the app/logic/ and app/view/ folders:4
app
βββ js/
βββ logic/
βββ main.R
βββ static/
βββ styles/
βββ view/
6 directories, 1 file 1. JavaScript code 2. Non-shiny code
3. Primary app file
4. Static .js or .css
5. App CSS files 6. Shiny modules and app code
25.3.1 Utility functions
In rap, Iβve placed the non-Shiny utility functions (i.e., the business logic) in app/logic:
app/logic
βββ __init__.R
βββ data.R
βββ plot.R
1 directory, 4 files 1. Load movies data
2. scatter_plot() utility function
25.3.2 Shiny modules
Our Shiny box modules are placed in app/view, and separated into inputs and display:
app/view
βββ __init__.R
βββ aes_inputs.R
βββ display.R
βββ var_inputs.R
1 directory, 6 files 1. similar to the code from R/mod_aes_input.R
2. similar to the code from R/mod_scatter_display.R 3. similar to the code from R/mod_var_input.R
app/view/aes_inputs and app/view/var_inputs collect and return the reactive values from the UI. The app/view/display module includes the app/logic/data and app/logic/plot modules.
25.4 app/main.R
The app/main.R file contains the primary UI and Server functions for the application. This file adds the shiny functions and the aes_inputs, var_inputs, and display modules from app/view:
# app/main.R
# shiny functions
box::use(
shiny[
NS, span, tags, icon, moduleServer
],
# bslib functions
bslib[
page_fillable, layout_sidebar, sidebar,
card, card_header, card_body, bs_theme
]
)
# import modules ----
box::use(
## load inputs module
app / view / var_inputs,
app / view / aes_inputs,
## load display module
app / view / display
)Note that we donβt need to import app/logic modules in app/main.R, because theyβre imported in their respective app/view modules.
25.5 Tests
rhino apps have support for testing with testthat, shiny::testServer(), shinytest2, and Cypress.
βββ tests
βββ cypress
β βββ e2e
β βββ app.cy.js
βββ cypress.config.js
βββ testthat
β βββ test-main.R
βββ testthat.R 1. Cypress test infrastructure
1. testthat test infrastructure
Below is the boilerplate test code in the tests/testthat/test-main.R file:
box::use(
shiny[testServer],
testthat[...],
)
box::use(
app/main[...],
)
test_that("main server works", {
testServer(server, {
expect_equal(output$message, "Hello!")
})
})- 1
-
boxmodule importing test package functions - 2
-
Using
shiny::testServer()andtestthat::test_that()functions in test.
Iβve included tests for the utility functions and modules in the 25_rhino branch, but Iβll cover testing with rhino elsewhere.5
25.6 rhino dependencies
In rhino apps, dependencies are managed by renv and the dependencies.R file. The renv package is designed to,
βcreate[s] and manage[s] project-local R libraries, save[s] the state of these libraries to a βlockfileβ, and later restore[s] the library as required.β 6
The rhino::pkg_install() helper function updates both the dependencies.R file and renv library. Using dependencies.R, renv, and box modules removes the need to manage dependencies in a DESCRIPTION or NAMESPACE file.7
Recap
I re-initialize the session on the
25_rhinobranch so Iβm not tempted to load, document, install, or test the code using the IDE.β©οΈImported dependencies in
rhinoapps useboxmodules instead of theDESCRIPTIONandNAMESPACE.β©οΈBe sure to read up on testing box modules and
rhinoapplications with cypress andshinytest2.β©οΈrhinorecommends placing non-Shiny code in theapp/logicfolder and keeping all Shiny modules and reactive code inapp/view.β©οΈSee the Shiny frameworks supplemental website for more information on testing your
rhinoapp.β©οΈAs described in
renvβs DESCRIPTION fileβ©οΈBe sure to read the
renvconfiguration article for a better understanding on how it works with rhino apps.β©οΈCheck for yourself on cran-downloadsβ©οΈ




