{"id":20665616,"url":"https://github.com/thinkr-open/elvis","last_synced_at":"2025-04-19T16:39:02.287Z","repository":{"id":69754252,"uuid":"542998440","full_name":"ThinkR-open/elvis","owner":"ThinkR-open","description":"'Shiny' renderers and observers made safer","archived":false,"fork":false,"pushed_at":"2025-01-03T15:38:40.000Z","size":48,"stargazers_count":8,"open_issues_count":0,"forks_count":0,"subscribers_count":7,"default_branch":"main","last_synced_at":"2025-03-29T10:12:22.825Z","etag":null,"topics":["golemverse","r","rstats","shiny"],"latest_commit_sha":null,"homepage":"","language":"R","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ThinkR-open.png","metadata":{"files":{"readme":"README.Rmd","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2022-09-29T08:12:36.000Z","updated_at":"2024-08-30T11:12:56.000Z","dependencies_parsed_at":null,"dependency_job_id":"99823986-2a2a-467a-882c-bdd627a92ab4","html_url":"https://github.com/ThinkR-open/elvis","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ThinkR-open%2Felvis","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ThinkR-open%2Felvis/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ThinkR-open%2Felvis/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ThinkR-open%2Felvis/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ThinkR-open","download_url":"https://codeload.github.com/ThinkR-open/elvis/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":249739800,"owners_count":21318656,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["golemverse","r","rstats","shiny"],"created_at":"2024-11-16T19:32:45.889Z","updated_at":"2025-04-19T16:39:02.246Z","avatar_url":"https://github.com/ThinkR-open.png","language":"R","funding_links":[],"categories":[],"sub_categories":[],"readme":"---\noutput: github_document\n---\n\n\u003c!-- README.md is generated from README.Rmd. Please edit that file --\u003e\n\n```{r, include = FALSE}\nknitr::opts_chunk$set(\n  collapse = TRUE,\n  eval = FALSE,\n  comment = \"#\u003e\",\n  fig.path = \"man/figures/README-\",\n  out.width = \"100%\"\n)\n```\n\n# elvis\n\n\u003c!-- badges: start --\u003e\n[![Lifecycle: experimental](https://img.shields.io/badge/lifecycle-experimental-orange.svg)](https://lifecycle.r-lib.org/articles/stages.html#experimental)\n[![R-CMD-check](https://github.com/thinkr-open/elvis/actions/workflows/R-CMD-check.yaml/badge.svg)](https://github.com/thinkr-open/elvis/actions/workflows/R-CMD-check.yaml)\n\u003c!-- badges: end --\u003e\n\n[EXPERIMENTAL, DO NOT USE]\n\nThe goal of `{elvis}` is to provide safer render* and observe* in `{shiny}` by providing a native tryCatch() mechanism.\n\nNote that this is an experimental package, so the API might change and some stuff might be buggy.\n\n## Installation\n\nYou can install the development version of elvis like so:\n\n``` r\nremotes::install_github(\"thinkr-open/elvis\")\n```\n\n## About\n\nYou're reading the doc about version : `r pkgload::pkg_version()`\n\nThis README has been compiled on the\n\n```{r eval = TRUE}\nSys.time()\n```\n\nHere are the test \u0026 coverage results :\n\n```{r eval = TRUE}\ndevtools::check(quiet = TRUE)\n```\n\n```{r echo = FALSE, eval = TRUE}\nunloadNamespace(\"elvis\")\n```\n\n```{r eval = TRUE}\ncovr::package_coverage()\n```\n\n## What the heck\n\nBy default, `{shiny}` observers and renderers are not safe, and might stop your app when they fail.\nOne solution is to wrap your code inside tryCatch, but that might be cumbersum to do this every time.\n\nHere comes `{elvis}`, a series of wrappers around `{shiny}` observers and renderers that have built in tryCatch.\n\n```r\noutput$plot \u003c- try_renderPlot({\n    stop(\"a\")\n  },\n  errorHandler = function(e){\n    showNotification(\"There was an error in the plot\")\n  }\n)\n```\n\nThe base idea is to prefix all the functions with `try_`, so that it's easier to port old code to `{elvis}`.\n\n## Examples\n\nHere is a simple example:\n\n```{r}\nlibrary(shiny)\nlibrary(elvis)\nui \u003c- fluidPage(\n  actionButton(\"go\", \"Go\"),\n  plotOutput(\"plot\")\n)\n\nserver \u003c- function(input, output, session) {\n  r \u003c- reactiveValues(count = 0)\n\n  output$plot \u003c- try_renderPlot(\n    {\n      if (input$go %% 2 == 0) {\n        plot(sample(1:100, 10))\n      } else {\n        stop(\"Nop\")\n      }\n    },\n    errorHandler = function(e) {\n      isolate({\n        r$count \u003c- r$count + 1\n      })\n    }\n  )\n\n  observeEvent(\n    r$count,\n    {\n      cli::cli_alert_danger(\n        sprintf(\"It's been %s times\", r$count)\n      )\n    }\n  )\n}\n\nshinyApp(ui, server)\n```\n\n### observers\n\n```{r example}\nlibrary(elvis)\nlibrary(shiny)\nui \u003c- fluidPage(\n  sliderInput(\"try_observeEvent\", \"try_observeEvent\", 1, 100, 10),\n  sliderInput(\"try_observe\", \"try_observe\", 1, 100, 10)\n)\n\nserver \u003c- function(input, output, session) {\n  try_observeEvent(\n    input$try_observeEvent,\n    ignoreInit = TRUE,\n    {\n      stop(\"pif\")\n    },\n    errorHandler = function(e) {\n      showModal(\n        modalDialog(\n          easyClose = TRUE,\n          title = \"There was an error in the try_observeEvent\"\n        )\n      )\n    }\n  )\n  # This one is here to prove that it works with non failing code\n  try_observeEvent(\n    input$try_observeEvent,\n    ignoreInit = TRUE,\n    {\n      print(input$try_observeEvent)\n    }\n  )\n  try_observe(\n    {\n      input$try_observe\n      stop(\"paf\")\n    },\n    errorHandler = function(e) {\n      showModal(\n        modalDialog(\n          easyClose = TRUE,\n          title = \"There was an error in the try_observe\"\n        )\n      )\n    }\n  )\n\n  # This one is here to prove that it works with non failing code\n  try_observe({\n    print(input$try_observe)\n  })\n}\n\nshinyApp(ui, server)\n```\n\n### renderers\n\n+ try_renderPlot\n\n```{r}\nlibrary(elvis)\nlibrary(shiny)\nui \u003c- fluidPage(\n  actionButton(\"plot\", \"Try to renderPlot\"),\n  plotOutput(\"plot\"),\n  plotOutput(\"plot2\")\n)\n\nserver \u003c- function(input, output, session) {\n  output$plot \u003c- try_renderPlot(\n    {\n      input$plot\n      stop(\"a\")\n    },\n    errorHandler = function(e) {\n      showNotification(\n        \"There was an error in the plot\",\n        type = \"error\"\n      )\n    }\n  )\n  # This one is here to prove that it works with non failing code\n  output$plot2 \u003c- try_renderPlot({\n    input$plot\n    plot(sample(1:100, 10))\n  })\n}\n\nshinyApp(ui, server)\n```\n\n+ try_renderDataTable\n\n```{r}\nlibrary(elvis)\nlibrary(shiny)\nui \u003c- fluidPage(\n  actionButton(\"dt\", \"Try to renderDataTable\"),\n  dataTableOutput(\"dt\"),\n  dataTableOutput(\"dt2\")\n)\n\nserver \u003c- function(input, output, session) {\n  output$dt \u003c- try_renderDataTable(\n    {\n      input$dt\n      stop(\"a\")\n    },\n    errorHandler = function(e) {\n      showNotification(\n        \"There was an error in the DT\",\n        type = \"error\"\n      )\n    }\n  )\n  # This one is here to prove that it works with non failing code\n  output$dt2 \u003c- try_renderDataTable({\n    input$dt\n\n    mtcars[\n      sample(1:nrow(mtcars), 10),\n    ]\n  })\n}\n\nshinyApp(ui, server)\n```\n\n\n+ try_renderImage\n\n```{r}\nlibrary(elvis)\nlibrary(shiny)\nlibrary(zeallot)\nc(img1, img2, img3) %\u003c-% replicate(\n  3,\n  (\\(x){\n    tempfile(fileext = \".jpg\")\n  })()\n)\ndownload.file(\n  \"https://www.widermag.com/media/krup1.jpg\",\n  img1\n)\ndownload.file(\n  \"https://www.cafeducycliste.com/fr_fr/wp/wp-content/uploads/2022/02/Anton-topbanner-10-02-22.jpg\",\n  img2\n)\ndownload.file(\n  \"https://www.suunto.com/globalassets/suunto-blogs/2021/03-march/anton-krupicka/2021-03-anton-blog-intro-body-1.jpg\",\n  img3\n)\n# Three images\nui \u003c- fluidPage(\n  actionButton(\"img\", \"Try to renderImage\"),\n  imageOutput(\"img\"),\n  imageOutput(\"img2\")\n)\n\nserver \u003c- function(input, output, session) {\n  output$img \u003c- try_renderImage(\n    {\n      input$img\n      stop(\"a\")\n    },\n    errorHandler = function(e) {\n      showNotification(\n        \"There was an error in the img\",\n        type = \"error\"\n      )\n    }\n  )\n  # This one is here to prove that it works with non failing code\n  output$img2 \u003c- try_renderImage({\n    input$img\n    outfile \u003c- sample(\n      c(\n        img1,\n        img2,\n        img3\n      ),\n      1\n    )\n    list(\n      src = outfile,\n      alt = \"This is alternate text\"\n    )\n  })\n}\n\nshinyApp(ui, server)\n```\n\n+ try_renderPrint\n\n```{r}\nlibrary(elvis)\nlibrary(shiny)\nui \u003c- fluidPage(\n  actionButton(\"rp\", \"Try to try_renderPrint\"),\n  verbatimTextOutput(\"rp\"),\n  verbatimTextOutput(\"rp2\")\n)\n\nserver \u003c- function(input, output, session) {\n  output$rp \u003c- try_renderPrint(\n    {\n      input$rp\n      stop(\"a\")\n    },\n    errorHandler = function(e) {\n      showNotification(\n        \"There was an error in the print\",\n        type = \"error\"\n      )\n    }\n  )\n  # This one is here to prove that it works with non failing code\n  output$rp2 \u003c- try_renderPrint({\n    input$rp\n    sample(1:100, 10)\n  })\n}\n\nshinyApp(ui, server)\n```\n\n\n+ try_renderText\n\n```{r}\nlibrary(elvis)\nlibrary(shiny)\nui \u003c- fluidPage(\n  actionButton(\"rt\", \"Try to try_renderText\"),\n  textOutput(\"rt\"),\n  textOutput(\"rt2\")\n)\n\nserver \u003c- function(input, output, session) {\n  output$rt \u003c- try_renderText(\n    {\n      input$rt\n      stop(\"a\")\n    },\n    errorHandler = function(e) {\n      showNotification(\n        \"There was an error in the text\",\n        type = \"error\"\n      )\n    }\n  )\n  # This one is here to prove that it works with non failing code\n  output$rt2 \u003c- try_renderText({\n    input$rt\n    sample(letters, 10)\n  })\n}\n\nshinyApp(ui, server)\n```\n\n+ try_renderTable\n\n```{r}\nlibrary(elvis)\nlibrary(shiny)\nui \u003c- fluidPage(\n  actionButton(\"dt\", \"Try to try_renderTable\"),\n  tableOutput(\"dt\"),\n  tableOutput(\"dt2\")\n)\n\nserver \u003c- function(input, output, session) {\n  output$dt \u003c- try_renderTable(\n    {\n      input$dt\n      stop(\"a\")\n    },\n    errorHandler = function(e) {\n      showNotification(\n        \"There was an error in the table\",\n        type = \"error\"\n      )\n    }\n  )\n  # This one is here to prove that it works with non failing code\n  output$dt2 \u003c- try_renderTable({\n    input$dt\n\n    mtcars[\n      sample(1:nrow(mtcars), 10),\n    ]\n  })\n}\n\nshinyApp(ui, server)\n```\n\n+ try_renderUI\n\n```{r}\nlibrary(elvis)\nlibrary(shiny)\nui \u003c- fluidPage(\n  actionButton(\"ui\", \"Try to try_renderUI\"),\n  uiOutput(\"ui\"),\n  uiOutput(\"ui2\")\n)\n\nserver \u003c- function(input, output, session) {\n  output$ui \u003c- try_renderUI(\n    {\n      input$ui\n      stop(\"a\")\n    },\n    errorHandler = function(e) {\n      showNotification(\n        \"There was an error in the UI\",\n        type = \"error\"\n      )\n    }\n  )\n  # This one is here to prove that it works with non failing code\n  output$ui2 \u003c- try_renderUI({\n    input$ui\n\n    sample(letters, 1)\n  })\n}\n\nshinyApp(ui, server)\n```\n\n\n## Why the name?\n\nWith `{elvis}`, you're t(rying to r)ender, t(ry)render, tender... and love me tender, love me true.\n\n## Code of Conduct\n\nPlease note that the elvis project is released with a [Contributor Code of Conduct](https://contributor-covenant.org/version/2/1/CODE_OF_CONDUCT.html). By contributing to this project, you agree to abide by its terms.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fthinkr-open%2Felvis","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fthinkr-open%2Felvis","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fthinkr-open%2Felvis/lists"}