vignettes/how-to/build-rhino-apps-with-llm-tools.Rmd
build-rhino-apps-with-llm-tools.RmdLLM tools like GitHub Copilot can be extremely helpful when building apps with Rhino. However, the unique project structure and the use of the box package for module imports can make it harder for these tools to understand and assist effectively. The good news is that their performance can be significantly improved by providing custom instructions.
To optimize GitHub Copilot for working with Rhino projects, you can
create a file named copilot-instructions.md in the
.github/ directory of your repository. To see instructions
below as markdown visit
vignette source.
Example instructions:
Use only box::use for imports. Using
library and :: is forbidden.
box::use statement (if needed) should be located at the
top of the file.
There can be two box::use statements per file. First one
should include only R packages, second should only import other
scripts.
Imports in box::use should be sorted alphabetically.
Using [...] is forbidden.
All external functions in a script should be imported. This includes
operators, like %>%.
A script should only import functions that it uses.
There are two ways a package or a script can be imported:
Use it if there are no more than 8 functions imported from this package/script.
$
box::use(
dplyr,
)
dplyr$filter(mtcars, cyl > 4)When moving function into a different script, remember to adjust
imports in box::use:
Use it if there are more than 8 functions imported from this package/script.
When creating a new module in app/view, use the
template:
box::use(
shiny[moduleServer, NS]
)
#' @export
ui <- function(id) {
ns <- NS(id)
}
#' @export
server <- function(id) {
moduleServer(id, function(input, output, session) {
})
}All R unit tests are located in tests/testthat.
There should be only one test file per script, named
test-{script name}.R.
If testing private functions (ones that are not exported), use this pattern:
box::use(app/logic/mymod)
impl <- attr(mymod, "namespace")
test_that('{test description}', {
expect_true(impl$this_works())
})When testing a box module that contains both exported and non-exported functions:
box::use(
app/logic/mymodule,
)$:
test_that("exported function works", {
expect_equal(mymodule$exported_function(1), 2)
})
impl <- attr(mymodule, "namespace")
test_that("non-exported function works", {
expect_equal(impl$internal_function(1), 2)
})This pattern allows testing both public and private functions while maintaining proper encapsulation.