diff --git a/inst/WORDLIST b/inst/WORDLIST index 682b94f9..8d12f439 100644 --- a/inst/WORDLIST +++ b/inst/WORDLIST @@ -8,6 +8,7 @@ Init JS JSON JSX +LLM LatinR LibSass Pharmaverse diff --git a/pkgdown/_pkgdown.yml b/pkgdown/_pkgdown.yml index afd14cf8..a4f9d397 100644 --- a/pkgdown/_pkgdown.yml +++ b/pkgdown/_pkgdown.yml @@ -112,6 +112,8 @@ navbar: - text: User tools - text: Box-module auto-complete in VSCode href: articles/how-to/box-lsp.html + - text: Build Rhino apps with LLM tools + href: articles/how-to/build-rhino-apps-with-llm-tools.html - text: ------- - text: Migration guides - text: Migration to Rhino 1.6 diff --git a/vignettes/how-to/build-rhino-apps-with-llm-tools.Rmd b/vignettes/how-to/build-rhino-apps-with-llm-tools.Rmd new file mode 100644 index 00000000..3753f4cd --- /dev/null +++ b/vignettes/how-to/build-rhino-apps-with-llm-tools.Rmd @@ -0,0 +1,154 @@ +--- +title: "How-to: Build Rhino apps with LLM tools" +output: rmarkdown::html_vignette +vignette: > + %\VignetteIndexEntry{How-to: Build Rhino apps with LLM tools} + %\VignetteEngine{knitr::rmarkdown} + %\VignetteEncoding{UTF-8} +--- + +LLM tools like [GitHub Copilot](https://github.com/features/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. + +# Custom instructions for GitHub Copilot + +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](https://github.com/Appsilon/rhino/blob/main/vignettes/how-to/build-rhino-apps-with-llm-tools.Rmd). + +Example instructions: + +
+## Importing and exporting + +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. + +### Ways of importing + +There are two ways a package or a script can be imported: + +1. List imported functions - functions imported are listed in [] + +```r +box::use( + dplyr[filter], +) + +filter(mtcars, cyl > 4) +``` + +Use it if there are no more than 8 functions imported from this package/script. + +2. Import package and access functions with `$` + +```r +box::use( + dplyr, +) +dplyr$filter(mtcars, cyl > 4) +``` + +When moving function into a different script, remember to adjust imports in `box::use`: + +1. Add import for all required functions to the file where you moved the function. +2. Make sure to follow the correct way of importing (direct or using $) in the new file. Modify it if needed. +3. Remove redundant imports from the original file. +4. Import the moved function in the original file. + +Use it if there are more than 8 functions imported from this package/script. + +### Exporting + +If a function is used only inside a script, it should not be exported. + +If a function is used by other scripts, it should be exported by adding `#' @export` before the function. + +## Rhino modules + +When creating a new module in `app/view`, use the template: +```r +box::use( + shiny[moduleServer, NS] +) + +#' @export +ui <- function(id) { + ns <- NS(id) + +} + +#' @export +server <- function(id) { + moduleServer(id, function(input, output, session) { + + }) +} +``` + +## Unit tests + +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: + +```r +box::use(app/logic/mymod) + +impl <- attr(mymod, "namespace") + +test_that('{test description}', { + expect_true(impl$this_works()) +}) +``` + +### Testing exported and non-exported functions + +When testing a box module that contains both exported and non-exported functions: + +1. Import the entire module without specifying individual functions: + +```r +box::use( + app/logic/mymodule, +) +``` + +2. Access exported functions using the module name with `$`: + +```r +test_that("exported function works", { + expect_equal(mymodule$exported_function(1), 2) +}) +``` + +3. For testing non-exported functions, get the module's namespace at the start of the test file: + +```r +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. + +## Code style + +The maximum line length is 100 characters. +