├── .Rproj.user ├── 8B1EABEC │ ├── cpp-definition-cache │ ├── saved_source_markers │ ├── pcs │ │ ├── source-pane.pper │ │ ├── workbench-pane.pper │ │ ├── debug-breakpoints.pper │ │ ├── files-pane.pper │ │ └── windowlayoutstate.pper │ ├── sources │ │ └── prop │ │ │ ├── 55A79ACC │ │ │ ├── 87524BD3 │ │ │ ├── 9C8C892 │ │ │ ├── CB39595A │ │ │ ├── E4BB522D │ │ │ ├── F5BF7629 │ │ │ ├── 22B8063F │ │ │ ├── 6FB169F0 │ │ │ └── INDEX │ ├── rmd-outputs │ ├── console06 │ │ ├── INDEX001 │ │ ├── FE4A14.env │ │ └── FE4A14 │ └── persistent-state └── shared │ └── notebooks │ ├── patch-chunk-names │ ├── 5972E819-README │ └── 1 │ │ ├── s │ │ └── chunks.json │ │ ├── 8B1EABEC8B43C756 │ │ └── chunks.json │ │ └── 8B1EABECAD3DAB17 │ │ └── chunks.json │ └── paths ├── LICENSE ├── .gitignore ├── .RData ├── .DS_Store ├── NEWS.md ├── readme_fig ├── save_state.png └── every_second.png ├── .Rbuildignore ├── shiny_bookmarks ├── 0a12f58440b83ba8 │ └── input.rds ├── 2d70fbbce8aa7770 │ └── input.rds ├── 3fe0ae7e6bae16d0 │ └── input.rds ├── 50b5700711605123 │ └── input.rds ├── 63d9f8fcac13bf0d │ └── input.rds ├── bd3cdfa8dba957c1 │ └── input.rds └── f0de8671967d0078 │ └── input.rds ├── man ├── record.Rd ├── monitor.Rd └── Creature.Rd ├── frankenstein.Rproj ├── NAMESPACE ├── DESCRIPTION ├── inst └── testapp.R ├── LICENSE.md ├── data-raw └── devstuffs.R ├── R ├── chock.R ├── surgery.R └── frankenstein.R ├── CODE_OF_CONDUCT.md ├── README.Rmd ├── README.md └── .Rhistory /.Rproj.user/8B1EABEC/cpp-definition-cache: -------------------------------------------------------------------------------- 1 | [ 2 | ] -------------------------------------------------------------------------------- /.Rproj.user/shared/notebooks/patch-chunk-names: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | YEAR: 2018 2 | COPYRIGHT HOLDER: Colin FAY 3 | -------------------------------------------------------------------------------- /.Rproj.user/8B1EABEC/saved_source_markers: -------------------------------------------------------------------------------- 1 | {"active_set":"","sets":[]} -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .Rproj.user 2 | .Rhistory 3 | .RData 4 | .Ruserdata 5 | -------------------------------------------------------------------------------- /.RData: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ColinFay/frankenstein/HEAD/.RData -------------------------------------------------------------------------------- /.Rproj.user/8B1EABEC/pcs/source-pane.pper: -------------------------------------------------------------------------------- 1 | { 2 | "activeTab" : 0 3 | } -------------------------------------------------------------------------------- /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ColinFay/frankenstein/HEAD/.DS_Store -------------------------------------------------------------------------------- /NEWS.md: -------------------------------------------------------------------------------- 1 | # {{ Package }} 0.0.0.9000 2 | 3 | * Added a `NEWS.md` file to track changes to the package. 4 | -------------------------------------------------------------------------------- /readme_fig/save_state.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ColinFay/frankenstein/HEAD/readme_fig/save_state.png -------------------------------------------------------------------------------- /.Rproj.user/8B1EABEC/sources/prop/55A79ACC: -------------------------------------------------------------------------------- 1 | { 2 | "cursorPosition" : "18,0", 3 | "scrollLine" : "0" 4 | } -------------------------------------------------------------------------------- /.Rproj.user/8B1EABEC/sources/prop/87524BD3: -------------------------------------------------------------------------------- 1 | { 2 | "cursorPosition" : "4,0", 3 | "scrollLine" : "0" 4 | } -------------------------------------------------------------------------------- /.Rproj.user/8B1EABEC/sources/prop/9C8C892: -------------------------------------------------------------------------------- 1 | { 2 | "cursorPosition" : "12,37", 3 | "scrollLine" : "0" 4 | } -------------------------------------------------------------------------------- /.Rproj.user/8B1EABEC/sources/prop/CB39595A: -------------------------------------------------------------------------------- 1 | { 2 | "cursorPosition" : "13,1", 3 | "scrollLine" : "0" 4 | } -------------------------------------------------------------------------------- /.Rproj.user/8B1EABEC/sources/prop/E4BB522D: -------------------------------------------------------------------------------- 1 | { 2 | "cursorPosition" : "0,0", 3 | "scrollLine" : "0" 4 | } -------------------------------------------------------------------------------- /.Rproj.user/8B1EABEC/sources/prop/F5BF7629: -------------------------------------------------------------------------------- 1 | { 2 | "cursorPosition" : "25,0", 3 | "scrollLine" : "8" 4 | } -------------------------------------------------------------------------------- /.Rproj.user/shared/notebooks/5972E819-README/1/s/chunks.json: -------------------------------------------------------------------------------- 1 | {"chunk_definitions":[],"doc_write_time":1529266327} -------------------------------------------------------------------------------- /readme_fig/every_second.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ColinFay/frankenstein/HEAD/readme_fig/every_second.png -------------------------------------------------------------------------------- /.Rproj.user/shared/notebooks/5972E819-README/1/8B1EABEC8B43C756/chunks.json: -------------------------------------------------------------------------------- 1 | {"chunk_definitions":[],"doc_write_time":1529136831} -------------------------------------------------------------------------------- /.Rproj.user/shared/notebooks/5972E819-README/1/8B1EABECAD3DAB17/chunks.json: -------------------------------------------------------------------------------- 1 | {"chunk_definitions":[],"doc_write_time":1529266327} -------------------------------------------------------------------------------- /.Rproj.user/8B1EABEC/pcs/workbench-pane.pper: -------------------------------------------------------------------------------- 1 | { 2 | "TabSet1" : 3, 3 | "TabSet2" : 3, 4 | "TabZoom" : { 5 | } 6 | } -------------------------------------------------------------------------------- /.Rbuildignore: -------------------------------------------------------------------------------- 1 | ^data-raw$ 2 | ^LICENSE\.md$ 3 | ^README\.Rmd$ 4 | ^CODE_OF_CONDUCT\.md$ 5 | ^readme_fig$ 6 | ^.*\.Rproj$ 7 | ^\.Rproj\.user$ 8 | -------------------------------------------------------------------------------- /shiny_bookmarks/0a12f58440b83ba8/input.rds: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ColinFay/frankenstein/HEAD/shiny_bookmarks/0a12f58440b83ba8/input.rds -------------------------------------------------------------------------------- /shiny_bookmarks/2d70fbbce8aa7770/input.rds: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ColinFay/frankenstein/HEAD/shiny_bookmarks/2d70fbbce8aa7770/input.rds -------------------------------------------------------------------------------- /shiny_bookmarks/3fe0ae7e6bae16d0/input.rds: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ColinFay/frankenstein/HEAD/shiny_bookmarks/3fe0ae7e6bae16d0/input.rds -------------------------------------------------------------------------------- /shiny_bookmarks/50b5700711605123/input.rds: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ColinFay/frankenstein/HEAD/shiny_bookmarks/50b5700711605123/input.rds -------------------------------------------------------------------------------- /shiny_bookmarks/63d9f8fcac13bf0d/input.rds: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ColinFay/frankenstein/HEAD/shiny_bookmarks/63d9f8fcac13bf0d/input.rds -------------------------------------------------------------------------------- /shiny_bookmarks/bd3cdfa8dba957c1/input.rds: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ColinFay/frankenstein/HEAD/shiny_bookmarks/bd3cdfa8dba957c1/input.rds -------------------------------------------------------------------------------- /shiny_bookmarks/f0de8671967d0078/input.rds: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ColinFay/frankenstein/HEAD/shiny_bookmarks/f0de8671967d0078/input.rds -------------------------------------------------------------------------------- /.Rproj.user/8B1EABEC/pcs/debug-breakpoints.pper: -------------------------------------------------------------------------------- 1 | { 2 | "debugBreakpointsState" : { 3 | "breakpoints" : [ 4 | ] 5 | } 6 | } -------------------------------------------------------------------------------- /.Rproj.user/8B1EABEC/rmd-outputs: -------------------------------------------------------------------------------- 1 | /var/folders/5z/rm2h62lj45d332kfpj28c8zm0000gn/T//Rtmp2WuNJ7/preview-6e3571502b0a.html 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /.Rproj.user/8B1EABEC/sources/prop/22B8063F: -------------------------------------------------------------------------------- 1 | { 2 | "cursorPosition" : "70,47", 3 | "docOutlineVisible" : "0", 4 | "scrollLine" : "53" 5 | } -------------------------------------------------------------------------------- /.Rproj.user/8B1EABEC/sources/prop/6FB169F0: -------------------------------------------------------------------------------- 1 | { 2 | "cursorPosition" : "29,28", 3 | "docOutlineVisible" : "0", 4 | "scrollLine" : "0" 5 | } -------------------------------------------------------------------------------- /.Rproj.user/8B1EABEC/pcs/files-pane.pper: -------------------------------------------------------------------------------- 1 | { 2 | "path" : "~/Seafile/documents_colin/R/frankenstein", 3 | "sortOrder" : [ 4 | { 5 | "ascending" : true, 6 | "columnIndex" : 2 7 | } 8 | ] 9 | } -------------------------------------------------------------------------------- /man/record.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/surgery.R 3 | \name{record} 4 | \alias{record} 5 | \title{Record a session} 6 | \usage{ 7 | record(session) 8 | } 9 | \arguments{ 10 | \item{session}{the session object} 11 | } 12 | \description{ 13 | Record a session 14 | } 15 | -------------------------------------------------------------------------------- /.Rproj.user/8B1EABEC/pcs/windowlayoutstate.pper: -------------------------------------------------------------------------------- 1 | { 2 | "left" : { 3 | "panelheight" : 734, 4 | "splitterpos" : 190, 5 | "topwindowstate" : "NORMAL", 6 | "windowheight" : 772 7 | }, 8 | "right" : { 9 | "panelheight" : 734, 10 | "splitterpos" : 529, 11 | "topwindowstate" : "NORMAL", 12 | "windowheight" : 772 13 | } 14 | } -------------------------------------------------------------------------------- /frankenstein.Rproj: -------------------------------------------------------------------------------- 1 | Version: 1.0 2 | 3 | RestoreWorkspace: Default 4 | SaveWorkspace: Default 5 | AlwaysSaveHistory: Default 6 | 7 | EnableCodeIndexing: Yes 8 | UseSpacesForTab: Yes 9 | NumSpacesForTab: 2 10 | Encoding: UTF-8 11 | 12 | RnwWeave: Sweave 13 | LaTeX: pdfLaTeX 14 | 15 | BuildType: Package 16 | PackageUseDevtools: Yes 17 | PackageInstallArgs: --no-multiarch --with-keep.source 18 | -------------------------------------------------------------------------------- /.Rproj.user/8B1EABEC/console06/INDEX001: -------------------------------------------------------------------------------- 1 | [{"allow_restart":true,"alt_buffer":false,"autoclose":1,"buffered_output":"\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n","caption":"Terminal 1","channel_id":"4792","channel_mode":1,"child_procs":false,"cols":111,"cwd":"~/Seafile/documents_colin/R/frankenstein","exit_code":null,"handle":"FE4A14","interaction_mode":2,"max_output_lines":1000,"restarted":true,"rows":6,"shell_type":7,"show_on_output":false,"terminal_sequence":1,"title":"~/Seafile/documents_colin/R/frankenstein","track_env":true,"zombie":false}] -------------------------------------------------------------------------------- /NAMESPACE: -------------------------------------------------------------------------------- 1 | # Generated by roxygen2: do not edit by hand 2 | 3 | export(Creature) 4 | export(monitor) 5 | export(record) 6 | importFrom(R6,R6Class) 7 | importFrom(attempt,attempt) 8 | importFrom(attempt,stop_if_not) 9 | importFrom(crayon,green) 10 | importFrom(crayon,red) 11 | importFrom(crayon,yellow) 12 | importFrom(glue,glue) 13 | importFrom(shiny,getShinyOption) 14 | importFrom(shiny,isolate) 15 | importFrom(shiny,observe) 16 | importFrom(shiny,reactiveTimer) 17 | importFrom(shiny,shinyApp) 18 | importFrom(shiny,withLogErrors) 19 | importFrom(yesno,yesno) 20 | -------------------------------------------------------------------------------- /DESCRIPTION: -------------------------------------------------------------------------------- 1 | Package: frankenstein 2 | Title: Bring your Shiny App back from the dead 3 | Version: 0.0.0.9000 4 | Authors@R: person('Colin', 'Fay', email = 'contact@colinfay.me', role = c('cre', 'aut')) 5 | Description: Bring your Shiny App back from the dead. 6 | License: MIT + file LICENSE 7 | URL: https://github.com/Thinkr-open/frankenstein 8 | BugReports: https://github.com/Thinkr-open/frankenstein/issues 9 | Imports: 10 | attempt, 11 | crayon, 12 | glue, 13 | R6, 14 | shiny, 15 | yesno 16 | Encoding: UTF-8 17 | LazyData: true 18 | RoxygenNote: 6.0.1 19 | -------------------------------------------------------------------------------- /man/monitor.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/surgery.R 3 | \name{monitor} 4 | \alias{monitor} 5 | \title{Monitor a Shiny App} 6 | \usage{ 7 | monitor(session, intervalMs, dispose = TRUE, folder = "shiny_bookmarks") 8 | } 9 | \arguments{ 10 | \item{session}{the session object} 11 | 12 | \item{intervalMs}{interval in millisecond between each monitoring} 13 | 14 | \item{dispose}{wether or not to dispose of the non-last states} 15 | 16 | \item{folder}{the folder where the states are kept} 17 | } 18 | \description{ 19 | Monitor a Shiny App 20 | } 21 | -------------------------------------------------------------------------------- /.Rproj.user/shared/notebooks/paths: -------------------------------------------------------------------------------- 1 | /Users/colin/Seafile/documents_colin/R/frankenstein/DESCRIPTION="C195600F" 2 | /Users/colin/Seafile/documents_colin/R/frankenstein/NEWS.md="776F28EF" 3 | /Users/colin/Seafile/documents_colin/R/frankenstein/R/chock.R="4BED2EC5" 4 | /Users/colin/Seafile/documents_colin/R/frankenstein/R/frankenstein.R="DCAEFD7F" 5 | /Users/colin/Seafile/documents_colin/R/frankenstein/R/surgery.R="86536FDE" 6 | /Users/colin/Seafile/documents_colin/R/frankenstein/README.Rmd="5972E819" 7 | /Users/colin/Seafile/documents_colin/R/frankenstein/data-raw/devstuffs.R="8D858209" 8 | /Users/colin/Seafile/documents_colin/R/frankenstein/testapp.R="F2351D" 9 | -------------------------------------------------------------------------------- /inst/testapp.R: -------------------------------------------------------------------------------- 1 | library(shiny) 2 | 3 | 4 | ui_req <- function(request) { 5 | fluidPage( 6 | textInput("txt", "Enter text"), 7 | checkboxInput("caps", "Capitalize"), 8 | verbatimTextOutput("out"), 9 | actionButton("fo","fo") 10 | ) 11 | } 12 | 13 | server <- function(input, output, session) { 14 | observeEvent(input$fo, { 15 | record(session) 16 | }) 17 | 18 | output$out <- renderText({ 19 | if (input$caps) 20 | toupper(input$txt) 21 | else 22 | input$txt 23 | }) 24 | } 25 | 26 | library(frankenstein) 27 | johndoe <- Creature$new(ui_req, server) 28 | johndoe$as_fresh() 29 | johndoe$revive() 30 | 31 | -------------------------------------------------------------------------------- /.Rproj.user/8B1EABEC/sources/prop/INDEX: -------------------------------------------------------------------------------- 1 | ~%2FSeafile%2Fdocuments_colin%2FR%2Ffrankenstein%2FDESCRIPTION="55A79ACC" 2 | ~%2FSeafile%2Fdocuments_colin%2FR%2Ffrankenstein%2FR%2Fchock.R="6FB169F0" 3 | ~%2FSeafile%2Fdocuments_colin%2FR%2Ffrankenstein%2FR%2Ffrankenstein.R="22B8063F" 4 | ~%2FSeafile%2Fdocuments_colin%2FR%2Ffrankenstein%2FR%2Fsurgery.R="87524BD3" 5 | ~%2FSeafile%2Fdocuments_colin%2FR%2Ffrankenstein%2FR%2Futils.R="E4BB522D" 6 | ~%2FSeafile%2Fdocuments_colin%2FR%2Ffrankenstein%2FREADME.Rmd="CB39595A" 7 | ~%2FSeafile%2Fdocuments_colin%2FR%2Ffrankenstein%2FREADME.md="7C472F" 8 | ~%2FSeafile%2Fdocuments_colin%2FR%2Ffrankenstein%2Fdata-raw%2Fdevstuffs.R="F5BF7629" 9 | ~%2FSeafile%2Fdocuments_colin%2FR%2Ffrankenstein%2Ftestapp.R="9C8C892" 10 | -------------------------------------------------------------------------------- /man/Creature.Rd: -------------------------------------------------------------------------------- 1 | % Generated by roxygen2: do not edit by hand 2 | % Please edit documentation in R/frankenstein.R 3 | \docType{data} 4 | \name{Creature} 5 | \alias{Creature} 6 | \title{A Shiny Creature} 7 | \format{An object of class \code{R6ClassGenerator} of length 24.} 8 | \usage{ 9 | Creature 10 | } 11 | \value{ 12 | An R6 object 13 | } 14 | \description{ 15 | A Shiny Creature 16 | } 17 | \section{Methods}{ 18 | 19 | \describe{ 20 | \item{\code{as_fresh}}{run the app as fresh} 21 | \item{\code{dispose}}{remove old saved states} 22 | \item{\code{list_states}}{list all saved states} 23 | \item{\code{options}}{shiny options} 24 | \item{\code{revive}}{revive an old app from last states or specific one} 25 | \item{\code{server}}{server object} 26 | \item{\code{ui}}{ui object} 27 | } 28 | } 29 | 30 | \keyword{datasets} 31 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | # MIT License 2 | 3 | Copyright (c) 2018 Colin FAY 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /data-raw/devstuffs.R: -------------------------------------------------------------------------------- 1 | library(desc) 2 | unlink("DESCRIPTION") 3 | my_desc <- description$new("!new") 4 | my_desc$set("Package", "frankenstein") 5 | my_desc$set("Authors@R", "person('Colin', 'Fay', email = 'contact@colinfay.me', role = c('cre', 'aut'))") 6 | my_desc$del("Maintainer") 7 | my_desc$set_version("0.0.0.9000") 8 | my_desc$set(Title = "Bring your Shiny App back from the dead") 9 | my_desc$set(Description = "Bring your Shiny App back from the dead.") 10 | my_desc$set("URL", "https://github.com/Thinkr-open/frankenstein") 11 | my_desc$set("BugReports", "https://github.com/Thinkr-open/frankenstein/issues") 12 | my_desc$write(file = "DESCRIPTION") 13 | 14 | colin::init_docs() 15 | usethis::use_code_of_conduct() 16 | usethis::use_package("attempt") 17 | usethis::use_package("shiny") 18 | usethis::use_package("glue") 19 | usethis::use_package("crayon") 20 | usethis::use_package("yesno") 21 | usethis::use_package("R6") 22 | usethis::use_build_ignore("readme_fig/") 23 | usethis::use_build_ignore("shiny_bookmarks/") 24 | dir.create("readme_fig") 25 | usethis::use_build_ignore("readme_fig/") 26 | usethis::use_lifecycle_badge("Experimental") 27 | usethis::use_tidy_description() 28 | 29 | library(attempt) 30 | library(shiny) 31 | library(glue) 32 | library(crayon) 33 | library(yesno) 34 | -------------------------------------------------------------------------------- /R/chock.R: -------------------------------------------------------------------------------- 1 | #' @importFrom crayon green red 2 | #' @importFrom glue glue 3 | #' @importFrom shiny withLogErrors isolate getShinyOption 4 | 5 | chock <- function(scenario = NULL){ 6 | function () 7 | { 8 | tryCatch(withLogErrors({ 9 | saveState <- ShinySaveState$new(input = self$input, exclude = self$getBookmarkExclude(), 10 | onSave = function(state) { 11 | private$bookmarkCallbacks$invoke(state) 12 | }) 13 | 14 | url <- saveShinySaveState(saveState) 15 | id <- gsub("_state_id_=(.*)", "\\1", url) 16 | 17 | clientData <- self$clientData 18 | url <- paste0(clientData$url_protocol, "//", clientData$url_hostname, 19 | if (nzchar(clientData$url_port)) 20 | paste0(":", clientData$url_port), clientData$url_pathname, 21 | "?", url) 22 | 23 | if (private$bookmarkedCallbacks$count() > 0) { 24 | private$bookmarkedCallbacks$invoke(url) 25 | } 26 | else { 27 | cat(crayon::green(glue::glue("Saving state {id} at {Sys.time()}")), sep = "\n") 28 | } 29 | }), error = function(e) { 30 | cat(crayon::red(glue::glue("Unabled to save the state")), sep = "\n") 31 | }) 32 | } 33 | } -------------------------------------------------------------------------------- /.Rproj.user/8B1EABEC/persistent-state: -------------------------------------------------------------------------------- 1 | build-last-errors="[]" 2 | build-last-errors-base-dir="~/Seafile/documents_colin/R/frankenstein/" 3 | build-last-outputs="[{\"output\":\"==> R CMD INSTALL --no-multiarch --with-keep.source frankenstein\\n\\n\",\"type\":0},{\"output\":\"* installing to library ‘/Library/Frameworks/R.framework/Versions/3.4/Resources/library’\\n\",\"type\":1},{\"output\":\"* installing *source* package ‘frankenstein’ ...\\n\",\"type\":1},{\"output\":\"\",\"type\":1},{\"output\":\"** R\\n\",\"type\":1},{\"output\":\"\",\"type\":1},{\"output\":\"** preparing package for lazy loading\\n\",\"type\":1},{\"output\":\"\",\"type\":1},{\"output\":\"** help\\n\",\"type\":1},{\"output\":\"\",\"type\":1},{\"output\":\"*** installing help indices\\n\",\"type\":1},{\"output\":\"** building package indices\\n\",\"type\":1},{\"output\":\"** testing if installed package can be loaded\\n\",\"type\":1},{\"output\":\"\",\"type\":1},{\"output\":\"* DONE (frankenstein)\\n\",\"type\":1},{\"output\":\"\",\"type\":1}]" 4 | compile_pdf_state="{\"errors\":[],\"output\":\"\",\"running\":false,\"tab_visible\":false,\"target_file\":\"\"}" 5 | files.monitored-path="" 6 | find-in-files-state="{\"handle\":\"\",\"input\":\"\",\"path\":\"\",\"regex\":true,\"results\":{\"file\":[],\"line\":[],\"lineValue\":[],\"matchOff\":[],\"matchOn\":[]},\"running\":false}" 7 | imageDirtyState="1" 8 | saveActionState="-1" 9 | -------------------------------------------------------------------------------- /CODE_OF_CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Code of Conduct 2 | 3 | As contributors and maintainers of this project, we pledge to respect all people who 4 | contribute through reporting issues, posting feature requests, updating documentation, 5 | submitting pull requests or patches, and other activities. 6 | 7 | We are committed to making participation in this project a harassment-free experience for 8 | everyone, regardless of level of experience, gender, gender identity and expression, 9 | sexual orientation, disability, personal appearance, body size, race, ethnicity, age, or religion. 10 | 11 | Examples of unacceptable behavior by participants include the use of sexual language or 12 | imagery, derogatory comments or personal attacks, trolling, public or private harassment, 13 | insults, or other unprofessional conduct. 14 | 15 | Project maintainers have the right and responsibility to remove, edit, or reject comments, 16 | commits, code, wiki edits, issues, and other contributions that are not aligned to this 17 | Code of Conduct. Project maintainers who do not follow the Code of Conduct may be removed 18 | from the project team. 19 | 20 | Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by 21 | opening an issue or contacting one or more of the project maintainers. 22 | 23 | This Code of Conduct is adapted from the Contributor Covenant 24 | (http://contributor-covenant.org), version 1.0.0, available at 25 | http://contributor-covenant.org/version/1/0/0/ 26 | -------------------------------------------------------------------------------- /R/surgery.R: -------------------------------------------------------------------------------- 1 | #' Record a session 2 | #' 3 | #' @param session the session object 4 | #' 5 | #' @importFrom attempt attempt 6 | #' @export 7 | 8 | record <- function(session){ 9 | attempt(session$chock(), 10 | "Unable to save the state.\nDid you call `record` from outside a Frankenstein instance?") 11 | } 12 | 13 | #' Monitor a Shiny App 14 | #' 15 | #' @param session the session object 16 | #' @param intervalMs interval in millisecond between each monitoring 17 | #' @param dispose wether or not to dispose of the non-last states 18 | #' @param folder the folder where the states are kept 19 | #' 20 | #' @importFrom shiny reactiveTimer observe 21 | #' @importFrom attempt attempt 22 | #' @importFrom shiny reactiveTimer observe 23 | #' 24 | #' @export 25 | monitor <- function(session, intervalMs, dispose = TRUE, folder = "shiny_bookmarks"){ 26 | autoInvalidate <- reactiveTimer(intervalMs) 27 | observe({ 28 | autoInvalidate() 29 | attempt(session$chock(), 30 | "Unable to save the state.\nDid you call `record` from outside a Frankenstein instance?") 31 | if (dispose){ 32 | last_state <- get_last_state(folder) 33 | a <- list.files(folder, full.names = TRUE) 34 | a <- a[!grepl(last_state, a)] 35 | x <- lapply(a, unlink, recursive = TRUE) 36 | invisible(x) 37 | } 38 | }) 39 | } 40 | 41 | #' @importFrom crayon green 42 | #' 43 | get_last_state <- function(folder = "shiny_bookmarks"){ 44 | a <- list.files(folder, full.names = TRUE) 45 | if (length(a) == 0){ 46 | cat(green("No previous state found"), "\n") 47 | Sys.sleep(1) 48 | return(0) 49 | } else { 50 | last_state <- do.call(rbind, lapply(a, file.info)) 51 | last_state$name <- basename(a) 52 | last_state <- last_state[rev(order(last_state$mtime)), ] 53 | last_state <- last_state$name[1] 54 | return(last_state) 55 | } 56 | 57 | } 58 | 59 | -------------------------------------------------------------------------------- /.Rproj.user/8B1EABEC/console06/FE4A14.env: -------------------------------------------------------------------------------- 1 | { 2 | "Apple_PubSub_Socket_Render" : "/private/tmp/com.apple.launchd.uIrvC98I5b/Render", 3 | "CLICOLOR_FORCE" : "1", 4 | "DISPLAY" : "/private/tmp/com.apple.launchd.pboCEGhubh/org.macosforge.xquartz:0", 5 | "EDITOR" : "vi", 6 | "GIT_ASKPASS" : "rpostback-askpass", 7 | "HISTCONTROL" : "ignoreboth", 8 | "HOME" : "/Users/colin", 9 | "JAVA_PATH" : "/Users/colin/neo4j/bin/neo4j", 10 | "LANG" : "fr_FR.UTF-8", 11 | "LC_CTYPE" : "fr_FR.UTF-8", 12 | "LN_S" : "ln -s", 13 | "LOGNAME" : "colin", 14 | "MAKE" : "make", 15 | "PAGER" : "/usr/bin/less", 16 | "PATH" : "~/neo4j/bin/neo4j/anaconda3/bin:/Library/Frameworks/Python.framework/Versions/3.6/bin:/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/opt/X11/bin:bin/msys-ssh-1000-18 ", 17 | "PROMPT_COMMAND" : "echo -ne \"\\033]0;${PWD/#${HOME}/~}\\007\"", 18 | "PWD" : "/Users/colin/Seafile/documents_colin/R/frankenstein", 19 | "RMARKDOWN_MATHJAX_PATH" : "/Applications/RStudio.app/Contents/Resources/resources/mathjax-26", 20 | "RSTUDIO" : "1", 21 | "RSTUDIO_CONSOLE_COLOR" : "256", 22 | "RSTUDIO_CONSOLE_WIDTH" : "108", 23 | "RSTUDIO_PANDOC" : "/Applications/RStudio.app/Contents/MacOS/pandoc", 24 | "RSTUDIO_PROJ_NAME" : "frankenstein", 25 | "RSTUDIO_SESSION_ID" : "AD3DAB17", 26 | "RSTUDIO_SESSION_PORT" : "44413", 27 | "RSTUDIO_TERM" : "FE4A14", 28 | "RSTUDIO_USER_IDENTITY" : "colin", 29 | "RSTUDIO_WINUTILS" : "bin/winutils", 30 | "RS_RPOSTBACK_PATH" : "/Applications/RStudio.app/Contents/MacOS/rpostback", 31 | "RS_SHARED_SECRET" : "18b0b86f-8928-440b-b894-2ddb7199ffd3", 32 | "R_BROWSER" : "/usr/bin/open", 33 | "R_BZIPCMD" : "/usr/bin/bzip2", 34 | "R_DOC_DIR" : "/Library/Frameworks/R.framework/Resources/doc", 35 | "R_GZIPCMD" : "/usr/bin/gzip", 36 | "R_HOME" : "/Library/Frameworks/R.framework/Resources", 37 | "R_INCLUDE_DIR" : "/Library/Frameworks/R.framework/Resources/include", 38 | "R_LIBS_SITE" : "", 39 | "R_LIBS_USER" : "~/Library/R/3.4/library", 40 | "R_PAPERSIZE" : "a4", 41 | "R_PDFVIEWER" : "/usr/bin/open", 42 | "R_PLATFORM" : "x86_64-apple-darwin15.6.0", 43 | "R_PRINTCMD" : "lpr", 44 | "R_QPDF" : "/Library/Frameworks/R.framework/Resources/bin/qpdf", 45 | "R_RD4PDF" : "times,inconsolata,hyper", 46 | "R_SESSION_TMPDIR" : "/var/folders/5z/rm2h62lj45d332kfpj28c8zm0000gn/T//Rtmpt1PcuJ", 47 | "R_SHARE_DIR" : "/Library/Frameworks/R.framework/Resources/share", 48 | "R_SYSTEM_ABI" : "osx,gcc,gxx,gfortran,?", 49 | "R_TEXI2DVICMD" : "/usr/local/bin/texi2dvi", 50 | "R_UNZIPCMD" : "/usr/bin/unzip", 51 | "R_ZIPCMD" : "/usr/bin/zip", 52 | "SED" : "/usr/bin/sed", 53 | "SHELL" : "/bin/bash", 54 | "SHLVL" : "1", 55 | "SSH_ASKPASS" : "rpostback-askpass", 56 | "SSH_AUTH_SOCK" : "/private/tmp/com.apple.launchd.nfnfkukO4Y/Listeners", 57 | "TAR" : "/usr/bin/tar", 58 | "TERM" : "xterm-256color", 59 | "TMPDIR" : "/var/folders/5z/rm2h62lj45d332kfpj28c8zm0000gn/T/", 60 | "TWITTER_PAT" : "/Users/colin/.rtweet_token54.rds", 61 | "USER" : "colin", 62 | "XPC_FLAGS" : "0x0", 63 | "XPC_SERVICE_NAME" : "0", 64 | "__CF_USER_TEXT_ENCODING" : "0x1F5:0x0:0x1", 65 | "__KMP_REGISTERED_LIB_22315" : "0x1018ae7e8-cafebf2b-libomp.dylib" 66 | } -------------------------------------------------------------------------------- /README.Rmd: -------------------------------------------------------------------------------- 1 | --- 2 | output: github_document 3 | --- 4 | 5 | 6 | 7 | ```{r setup, include = FALSE} 8 | knitr::opts_chunk$set( 9 | collapse = TRUE, 10 | eval = FALSE, 11 | comment = "#>", 12 | fig.path = "man/figures/README-", 13 | out.width = "100%" 14 | ) 15 | ``` 16 | 17 | [![lifecycle](https://img.shields.io/badge/lifecycle-experimental-orange.svg)](https://www.tidyverse.org/lifecycle/#experimental) 18 | 19 | # frankenstein 20 | 21 | > Disclaimer: this is still highly experimental 22 | 23 | {frankenstein} allows you to bring your shiny app back from the dead. 24 | 25 |
26 | 27 | ## Installation 28 | 29 | You can install the released version of frankenstein from Github with: 30 | 31 | ``` r 32 | remotes::install_github("Thinkr-open/frankenstein") 33 | ``` 34 | 35 | ## Why frankenstein? 36 | 37 | As a shiny developper, you sometime lose time re-navigating through your app when it crashes. The goal of {frankenstein} is to allow you to bring back you shiny app from the dead (i.e, to the last registered state). All this, with minimal deviation from your usual shiny dev workflow. 38 | 39 | ### How is it different from shiny bookmark? 40 | 41 | Shiny bookmark are useful from an interactive point of view: your user has a pop up with the url of the restorable state. This is not what you would want as a developer: you want the bookmark to be silent (no pop up), and also to automatically restore the app from the last known state (no copy and paste of the url). 42 | 43 | ### How can I make this work? 44 | 45 | {frankenstein} relies on shiny bookmark, which need ui to be a function. So if your app looks like this: 46 | 47 | ```{r} 48 | library(shiny) 49 | 50 | ui <- fluidPage( 51 | textInput("txt", "Enter text"), 52 | checkboxInput("caps", "Capitalize"), 53 | verbatimTextOutput("out"), 54 | actionButton("fo","fo") 55 | ) 56 | 57 | server <- function(input, output, session) { 58 | observeEvent(input$fo, { 59 | session$doBookmark() 60 | }) 61 | 62 | output$out <- renderText({ 63 | if (input$caps) 64 | toupper(input$txt) 65 | else 66 | input$txt 67 | }) 68 | } 69 | 70 | shinyApp(ui, server) 71 | ``` 72 | 73 | You'll have to turn it to: 74 | 75 | ```{r eval = TRUE} 76 | 77 | ui_req <- function(request) { 78 | fluidPage( 79 | textInput("txt", "Enter text"), 80 | checkboxInput("caps", "Capitalize"), 81 | verbatimTextOutput("out"), 82 | actionButton("fo","fo") 83 | ) 84 | } 85 | 86 | server <- function(input, output, session) { 87 | observeEvent(input$fo, { 88 | session$doBookmark() 89 | }) 90 | 91 | output$out <- renderText({ 92 | if (input$caps) 93 | toupper(input$txt) 94 | else 95 | input$txt 96 | }) 97 | } 98 | 99 | ``` 100 | 101 | Note that the ui as function also works when calling shinyApp (but the `session$chock` won't). 102 | 103 | ```{r} 104 | shinyApp(ui_req, server) 105 | ``` 106 | 107 | ### The Creature Object: 108 | 109 | This object creates a new Frankenstein Creature from your ui and server: 110 | 111 | ```{r eval = TRUE} 112 | library(frankenstein) 113 | johndoe <- Creature$new(ui_req, server) 114 | ``` 115 | 116 | ### About `record` 117 | 118 | `record()` works as would ``session$doBookmark()`, with the little difference that it doesn't show a modal pop up, but instead print the id of the bookmark to the console. 119 | 120 | It takes the session as the only argument: 121 | 122 | ```{r eval = TRUE} 123 | ui_req <- function(request) { 124 | fluidPage( 125 | textInput("txt", "Enter text"), 126 | checkboxInput("caps", "Capitalize"), 127 | verbatimTextOutput("out"), 128 | actionButton("fo","fo") 129 | ) 130 | } 131 | 132 | server <- function(input, output, session) { 133 | observeEvent(input$fo, { 134 | record(session) 135 | }) 136 | 137 | output$out <- renderText({ 138 | if (input$caps) 139 | toupper(input$txt) 140 | else 141 | input$txt 142 | }) 143 | } 144 | 145 | johndoe <- Creature$new(ui_req, server) 146 | ``` 147 | 148 | A use case example would be to put this `record` in a "next" button on a shiny Dashboard, so that every time you move to another tab, the current state is saved. 149 | 150 | You can then run your app as fresh with: 151 | 152 | ```{r} 153 | johndoe$as_fresh() 154 | ``` 155 | 156 | 157 | ![](readme_fig/save_state.png) 158 | 159 | You now have a list of states in your console, which you can get back with: 160 | 161 | ```{r eval = TRUE} 162 | johndoe$list_states() 163 | ``` 164 | 165 | ### Revive old shiny states 166 | 167 | You can either revive from the last known state: 168 | 169 | ```{r} 170 | johndoe$revive() 171 | ``` 172 | 173 | Or from a specific state: 174 | 175 | ```{r} 176 | johndoe$revive(id = "3fe0ae7e6bae16d0") 177 | ``` 178 | 179 | ### Running `record()` periodically 180 | 181 | `monitor()` takes the session object, and an `intervalMs` argument, which is the interval in milliseconds you want your session to be saved: 182 | 183 | ```{r} 184 | ui_record <- function(request) { 185 | fluidPage( 186 | textInput("txt", "Enter text"), 187 | checkboxInput("caps", "Capitalize"), 188 | verbatimTextOutput("out") 189 | ) 190 | } 191 | 192 | server_record <- function(input, output, session) { 193 | 194 | monitor(session, 1000) 195 | 196 | output$out <- renderText({ 197 | if (input$caps) 198 | toupper(input$txt) 199 | else 200 | input$txt 201 | }) 202 | } 203 | ``` 204 | 205 | To be more efficient memory-wise, `monitor()` only keeps the last states by default, and flush all the others. You can prevent this behavior by turning `dispose` to FALSE. 206 | 207 | Note that this example will save a state each second. 208 | 209 | ### With new ui / server 210 | 211 | When you call as_fresh or revive without any argument, you'll get the ui and server used when the Creature object was created. If you pass a ui and/or server to these methods, you'll use these new elements. The `overwrite` argument specifies wether or not the ui / server element from self should be overwritten (default is TRUE) 212 | 213 | ```{r} 214 | johndoe$as_fresh(ui = ui_record, server = server_record) 215 | ``` 216 | 217 | ![](readme_fig/every_second.png) 218 | 219 | ### Flush states 220 | 221 | If for example you're saving every second, you can get a lot of states in your folder. 222 | 223 | You can dispose of your old bookmark with the `dispose` function. It can either remove all states, or just keep the last known state. 224 | 225 | __This function will remove all object from the folder, be cautious when using it__. 226 | 227 | ```{r} 228 | johndoe$dispose(folder ="shiny_bookmarks", save_last = TRUE) 229 | ``` 230 | 231 | ### Working with modules 232 | 233 | As long as the main ui is a function, you can work with module. 234 | 235 | ```{r} 236 | frankUI <- function(id){ 237 | ns <- NS(id) 238 | fluidPage( 239 | textInput(ns("txt"), "Enter text"), 240 | checkboxInput(ns("caps"), "Capitalize"), 241 | verbatimTextOutput(ns("out")), 242 | actionButton(ns("fo"), "fo") 243 | ) 244 | } 245 | 246 | frank <- function(input, output, session){ 247 | observeEvent(input$fo, { 248 | session$chock() 249 | }) 250 | 251 | output$out <- renderText({ 252 | if (input$caps) 253 | toupper(input$txt) 254 | else 255 | input$txt 256 | }) 257 | } 258 | 259 | 260 | ui <- function(request){ 261 | fluidPage( 262 | frankUI("test") 263 | ) 264 | } 265 | 266 | server <- function(input, output, session){ 267 | callModule(frank, "test") 268 | } 269 | 270 | johndoe$as_fresh(ui, server) 271 | ``` 272 | 273 | ## CoC 274 | 275 | Please note that this project is released with a [Contributor Code of Conduct](CODE_OF_CONDUCT.md). 276 | By participating in this project you agree to abide by its terms. 277 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | [![lifecycle](https://img.shields.io/badge/lifecycle-experimental-orange.svg)](https://www.tidyverse.org/lifecycle/#experimental) 5 | 6 | # frankenstein 7 | 8 | > Disclaimer: this is still highly experimental 9 | 10 | {frankenstein} allows you to bring your shiny app back from the 11 | dead. 12 | 13 |
14 | 15 | 16 | 17 |
18 | 19 | ## Installation 20 | 21 | You can install the released version of frankenstein from Github with: 22 | 23 | ``` r 24 | remotes::install_github("Thinkr-open/frankenstein") 25 | ``` 26 | 27 | ## Why frankenstein? 28 | 29 | As a shiny developper, you sometime lose time re-navigating through your 30 | app when it crashes. The goal of {frankenstein} is to allow you to bring 31 | back you shiny app from the dead (i.e, to the last registered state). 32 | All this, with minimal deviation from your usual shiny dev workflow. 33 | 34 | ### How is it different from shiny bookmark? 35 | 36 | Shiny bookmark are useful from an interactive point of view: your user 37 | has a pop up with the url of the restorable state. This is not what you 38 | would want as a developer: you want the bookmark to be silent (no pop 39 | up), and also to automatically restore the app from the last known state 40 | (no copy and paste of the url). 41 | 42 | ### How can I make this work? 43 | 44 | {frankenstein} relies on shiny bookmark, which need ui to be a function. 45 | So if your app looks like this: 46 | 47 | ``` r 48 | library(shiny) 49 | 50 | ui <- fluidPage( 51 | textInput("txt", "Enter text"), 52 | checkboxInput("caps", "Capitalize"), 53 | verbatimTextOutput("out"), 54 | actionButton("fo","fo") 55 | ) 56 | 57 | server <- function(input, output, session) { 58 | observeEvent(input$fo, { 59 | session$doBookmark() 60 | }) 61 | 62 | output$out <- renderText({ 63 | if (input$caps) 64 | toupper(input$txt) 65 | else 66 | input$txt 67 | }) 68 | } 69 | 70 | shinyApp(ui, server) 71 | ``` 72 | 73 | You’ll have to turn it to : 74 | 75 | ``` r 76 | 77 | ui_req <- function(request) { 78 | fluidPage( 79 | textInput("txt", "Enter text"), 80 | checkboxInput("caps", "Capitalize"), 81 | verbatimTextOutput("out"), 82 | actionButton("fo","fo") 83 | ) 84 | } 85 | 86 | server <- function(input, output, session) { 87 | observeEvent(input$fo, { 88 | session$doBookmark() 89 | }) 90 | 91 | output$out <- renderText({ 92 | if (input$caps) 93 | toupper(input$txt) 94 | else 95 | input$txt 96 | }) 97 | } 98 | ``` 99 | 100 | Note that the ui as function also works when calling shinyApp (but the 101 | `session$chock` won’t). 102 | 103 | ``` r 104 | shinyApp(ui_req, server) 105 | ``` 106 | 107 | ### The Creature Object : 108 | 109 | This object creates a new Frankenstein Creature from your ui and server: 110 | 111 | ``` r 112 | library(frankenstein) 113 | johndoe <- Creature$new(ui_req, server) 114 | ``` 115 | 116 | ### About `record` 117 | 118 | `record()` works as would \``session$doBookmark()`, with the little 119 | difference that it doesn’t show a modal pop up, but instead print the id 120 | of the bookmark to the console. 121 | 122 | It takes the session as the only argument: 123 | 124 | ``` r 125 | ui_req <- function(request) { 126 | fluidPage( 127 | textInput("txt", "Enter text"), 128 | checkboxInput("caps", "Capitalize"), 129 | verbatimTextOutput("out"), 130 | actionButton("fo","fo") 131 | ) 132 | } 133 | 134 | server <- function(input, output, session) { 135 | observeEvent(input$fo, { 136 | record(session) 137 | }) 138 | 139 | output$out <- renderText({ 140 | if (input$caps) 141 | toupper(input$txt) 142 | else 143 | input$txt 144 | }) 145 | } 146 | 147 | johndoe <- Creature$new(ui_req, server) 148 | ``` 149 | 150 | A use case example would be to put this `record` in a “next” button on a 151 | shiny Dashboard, so that every time you move to another tab, the current 152 | state is saved. 153 | 154 | You can then run your app as fresh with : 155 | 156 | ``` r 157 | johndoe$as_fresh() 158 | ``` 159 | 160 | ![](readme_fig/save_state.png) 161 | 162 | You now have a list of states in your console, which you can get back 163 | with : 164 | 165 | ``` r 166 | johndoe$list_states() 167 | #> id last_modified_time 168 | #> 1 63d9f8fcac13bf0d 2018-06-17 22:52:40 169 | #> 2 bd3cdfa8dba957c1 2018-06-17 22:51:49 170 | #> 3 50b5700711605123 2018-06-17 22:50:57 171 | #> 4 3fe0ae7e6bae16d0 2018-06-17 22:19:36 172 | #> 5 2d70fbbce8aa7770 2018-06-17 22:19:35 173 | #> 6 0a12f58440b83ba8 2018-06-17 22:19:34 174 | #> 7 f0de8671967d0078 2018-06-17 22:19:33 175 | ``` 176 | 177 | ### Revive old shiny states 178 | 179 | You can either revive from the last known state: 180 | 181 | ``` r 182 | johndoe$revive() 183 | ``` 184 | 185 | Or from a specific state: 186 | 187 | ``` r 188 | johndoe$revive(id = "3fe0ae7e6bae16d0") 189 | ``` 190 | 191 | ### Running `record()` periodically 192 | 193 | `monitor()` takes the session object, and an `intervalMs` argument, 194 | which is the interval in milliseconds you want your session to be saved: 195 | 196 | ``` r 197 | ui_record <- function(request) { 198 | fluidPage( 199 | textInput("txt", "Enter text"), 200 | checkboxInput("caps", "Capitalize"), 201 | verbatimTextOutput("out") 202 | ) 203 | } 204 | 205 | server_record <- function(input, output, session) { 206 | 207 | monitor(session, 1000) 208 | 209 | output$out <- renderText({ 210 | if (input$caps) 211 | toupper(input$txt) 212 | else 213 | input$txt 214 | }) 215 | } 216 | ``` 217 | 218 | To be more efficient memory-wise, `monitor()` only keeps the last states 219 | by default, and flush all the others. You can prevent this behavior by 220 | turning `dispose` to FALSE. 221 | 222 | Note that this example will save a state each second. 223 | 224 | ### With new ui / server 225 | 226 | When you call as\_fresh or revive without any argument, you’ll get the 227 | ui and server used when the Creature object was created. If you pass a 228 | ui and/or server to these methods, you’ll use these new elements. The 229 | `overwrite` argument specifies wether or not the ui / server element 230 | from self should be overwritten (default is TRUE) 231 | 232 | ``` r 233 | johndoe$as_fresh(ui = ui_record, server = server_record) 234 | ``` 235 | 236 | ![](readme_fig/every_second.png) 237 | 238 | ### Flush states 239 | 240 | If for example you’re saving every second, you can get a lot of states 241 | in your folder. 242 | 243 | You can dispose of your old bookmark with the `dispose` function. It can 244 | either remove all states, or just keep the last known state. 245 | 246 | **This function will remove all object from the folder, be cautious when 247 | using it**. 248 | 249 | ``` r 250 | johndoe$dispose(folder ="shiny_bookmarks", save_last = TRUE) 251 | ``` 252 | 253 | ### Working with modules 254 | 255 | As long as the main ui is a function, you can work with module. 256 | 257 | ``` r 258 | frankUI <- function(id){ 259 | ns <- NS(id) 260 | fluidPage( 261 | textInput(ns("txt"), "Enter text"), 262 | checkboxInput(ns("caps"), "Capitalize"), 263 | verbatimTextOutput(ns("out")), 264 | actionButton(ns("fo"), "fo") 265 | ) 266 | } 267 | 268 | frank <- function(input, output, session){ 269 | observeEvent(input$fo, { 270 | session$chock() 271 | }) 272 | 273 | output$out <- renderText({ 274 | if (input$caps) 275 | toupper(input$txt) 276 | else 277 | input$txt 278 | }) 279 | } 280 | 281 | 282 | ui <- function(request){ 283 | fluidPage( 284 | frankUI("test") 285 | ) 286 | } 287 | 288 | server <- function(input, output, session){ 289 | callModule(frank, "test") 290 | } 291 | 292 | johndoe$as_fresh(ui, server) 293 | ``` 294 | 295 | ## CoC 296 | 297 | Please note that this project is released with a [Contributor Code of 298 | Conduct](CODE_OF_CONDUCT.md). By participating in this project you agree 299 | to abide by its terms. 300 | -------------------------------------------------------------------------------- /R/frankenstein.R: -------------------------------------------------------------------------------- 1 | #' A Shiny Creature 2 | #' 3 | #' @return An R6 object 4 | #' 5 | #' @section Methods: 6 | #' \describe{ 7 | #' \item{\code{as_fresh}}{run the app as fresh} 8 | #' \item{\code{dispose}}{remove old saved states} 9 | #' \item{\code{list_states}}{list all saved states} 10 | #' \item{\code{options}}{shiny options} 11 | #' \item{\code{revive}}{revive an old app from last states or specific one} 12 | #' \item{\code{server}}{server object} 13 | #' \item{\code{ui}}{ui object} 14 | #' } 15 | #' 16 | #' @importFrom R6 R6Class 17 | #' @importFrom yesno yesno 18 | #' @importFrom attempt stop_if_not 19 | #' @importFrom shiny shinyApp 20 | #' @importFrom glue glue 21 | #' @importFrom crayon yellow green 22 | #' @export 23 | #' 24 | 25 | Creature <- R6::R6Class("Creature", 26 | public = list( 27 | ui = NULL, 28 | server = NULL, 29 | onStart = NULL, 30 | options = list(), 31 | uiPattern = "/", 32 | enableBookmarking = "server", 33 | scenario = "shiny_bookmarks", 34 | initialize = function(ui = NULL, 35 | server = NULL, 36 | options = list() 37 | ){ 38 | stop_if_not(ui, is.function, 39 | "ui should be a function with `request` as argument") 40 | self$ui <- ui 41 | self$server <- server 42 | self$options <- options 43 | }, 44 | 45 | as_fresh = function(ui = NULL, 46 | server = NULL, 47 | overwrite = TRUE){ 48 | if (!dir.exists(self$scenario)){ 49 | dir.create(self$scenario) 50 | } 51 | if (!is.null(ui)){ 52 | if (overwrite){ 53 | self$ui <- ui 54 | } 55 | } else { 56 | ui <- self$ui 57 | } 58 | 59 | if (!is.null(server)){ 60 | if (overwrite){ 61 | self$server <- server 62 | } 63 | } else { 64 | server <- self$server 65 | } 66 | 67 | self$options$launch.browser <- function(appUrl){ 68 | invisible(.Call("rs_shinyviewer", appUrl, getwd(), 3)) 69 | } 70 | 71 | shiny:::ShinySession$set( 72 | which = "public", 73 | name = "chock", 74 | value = chock(), 75 | overwrite = TRUE) 76 | 77 | shinyApp(ui, server, 78 | self$onStart, self$options, 79 | self$uiPattern, self$enableBookmarking) 80 | 81 | }, 82 | 83 | revive = function(ui = NULL, 84 | server = NULL, 85 | overwrite = TRUE, 86 | id = NULL){ 87 | 88 | if (!dir.exists(self$scenario)){ 89 | dir.create(self$scenario) 90 | } 91 | 92 | if (!is.null(ui)){ 93 | if (overwrite){ 94 | self$ui <- ui 95 | } 96 | } else { 97 | ui <- self$ui 98 | } 99 | 100 | if (!is.null(server)){ 101 | if (overwrite){ 102 | self$server <- server 103 | } 104 | } else { 105 | server <- self$server 106 | } 107 | 108 | if (!is.null(id)){ 109 | a <- list.files(self$scenario) 110 | stop_if_not(id, ~ .x %in% a, "Id not found") 111 | cat( green( glue::glue( "Launching from id : {id}" ) ), "\n") 112 | Sys.sleep(1) 113 | 114 | self$options$launch.browser <- function(appUrl){ 115 | 116 | url <- glue('{appUrl}/?_state_id_={id}') 117 | invisible(.Call("rs_shinyviewer", url, getwd(), 3)) 118 | } 119 | } else { 120 | last_state <- get_last_state(self$scenario) 121 | if (last_state == 0){ 122 | cat(green("No previous state found"), "\n") 123 | Sys.sleep(1) 124 | cat(yellow("Launching the App"), "\n") 125 | } else { 126 | cat( green( glue( "Last id found : {last_state}" ) ), "\n") 127 | Sys.sleep(1) 128 | cat(yellow("Launching the App"), "\n") 129 | 130 | self$options$launch.browser <- function(appUrl){ 131 | url <- glue('{appUrl}/?_state_id_={last_state}') 132 | invisible(.Call("rs_shinyviewer", url, getwd(), 3)) 133 | } 134 | } 135 | } 136 | 137 | shiny:::ShinySession$set( 138 | which = "public", 139 | name = "chock", 140 | value = chock(), 141 | overwrite = TRUE) 142 | 143 | shinyApp(ui, server, 144 | self$onStart, self$options, 145 | self$uiPattern, self$enableBookmarking) 146 | 147 | }, 148 | 149 | list_states = function(folder = "shiny_bookmarks"){ 150 | a <- list.files(folder, full.names = TRUE) 151 | if (length(a) == 0){ 152 | cat(crayon::green("No previous state found"), "\n") 153 | Sys.sleep(1) 154 | return(0) 155 | } else { 156 | last_state <- do.call(rbind, lapply(a, file.info)) 157 | last_state$name <- basename(a) 158 | last_state <- last_state[rev(order(last_state$mtime)), ] 159 | row.names(last_state) <- NULL 160 | last <- last_state[, c("name", "mtime")] 161 | names(last) <- c("id","last_modified_time") 162 | return(last) 163 | } 164 | }, 165 | 166 | dispose = function(folder = "shiny_bookmarks", save_last = TRUE){ 167 | if (yesno("This function will recursively remove all files from ", folder, ". Are you sure?")) { 168 | if(save_last){ 169 | last_state <- get_last_state(folder) 170 | a <- list.files(folder, full.names = TRUE) 171 | a <- a[!grepl(last_state, a)] 172 | } else { 173 | a <- list.files(folder, all.files = TRUE, full.names = TRUE) 174 | } 175 | x <- lapply(a, unlink, recursive = TRUE) 176 | invisible(x) 177 | } 178 | } 179 | ) 180 | ) 181 | 182 | -------------------------------------------------------------------------------- /.Rhistory: -------------------------------------------------------------------------------- 1 | attempt::stop_if_not(ui, is.function, 2 | "ui should be a function with `request` as argument") 3 | self$ui <- ui 4 | self$server <- server 5 | self$options <- options 6 | }, 7 | as_fresh = function(ui = NULL, 8 | server = NULL, 9 | overwrite = TRUE){ 10 | if (!dir.exists(self$scenario)){ 11 | dir.create(self$scenario) 12 | } 13 | if (!is.null(ui)){ 14 | if (overwrite){ 15 | self$ui <- ui 16 | } 17 | } else { 18 | ui <- self$ui 19 | } 20 | if (!is.null(server)){ 21 | if (overwrite){ 22 | self$server <- server 23 | } 24 | } else { 25 | server <- self$server 26 | } 27 | ShinySession <- utils::getFromNamespace("ShinySession", "shiny") 28 | self$options$launch.browser <- function(appUrl){ 29 | invisible(.Call("rs_shinyviewer", url, getwd(), 3)) 30 | } 31 | ShinySession$set( 32 | which = "public", 33 | name = "chock", 34 | value = chock(), 35 | overwrite = TRUE) 36 | shiny::shinyApp(ui, server, 37 | self$onStart, self$options, 38 | self$uiPattern, self$enableBookmarking) 39 | }, 40 | revive = function(ui = NULL, 41 | server = NULL, 42 | overwrite = TRUE, 43 | id = NULL){ 44 | if (!dir.exists(self$scenario)){ 45 | dir.create(self$scenario) 46 | } 47 | if (!is.null(ui)){ 48 | if (overwrite){ 49 | self$ui <- ui 50 | } 51 | } else { 52 | ui <- self$ui 53 | } 54 | if (!is.null(server)){ 55 | if (overwrite){ 56 | self$server <- server 57 | } 58 | } else { 59 | server <- self$server 60 | } 61 | if (!is.null(id)){ 62 | a <- list.files(self$scenario) 63 | stop_if_not(a, ~ .x %in% a, "Id not found") 64 | cat( crayon::green( glue::glue( "Launching from id : {id}" ) ), "\n") 65 | Sys.sleep(1) 66 | self$options$launch.browser <- function(appUrl){ 67 | url <- glue::glue('{appUrl}/?_state_id_={id}') 68 | invisible(.Call("rs_shinyviewer", url, getwd(), 3)) 69 | } 70 | } else { 71 | last_state <- get_last_state(self$scenario) 72 | if (last_state == 0){ 73 | cat(crayon::green("No previous state found"), "\n") 74 | Sys.sleep(1) 75 | cat(crayon::yellow("Launching the App"), "\n") 76 | } else { 77 | cat( crayon::green( glue::glue( "Last id found : {last_state}" ) ), "\n") 78 | Sys.sleep(1) 79 | cat(crayon::yellow("Launching the App"), "\n") 80 | self$options$launch.browser <- function(appUrl){ 81 | url <- glue::glue('{appUrl}/?_state_id_={last_state}') 82 | utils::browseURL(url) 83 | } 84 | } 85 | } 86 | ShinySession <- utils::getFromNamespace("ShinySession", "shiny") 87 | ShinySession$set( 88 | which = "public", 89 | name = "chock", 90 | value = chock(), 91 | overwrite = TRUE) 92 | shiny::shinyApp(ui, server, 93 | self$onStart, self$options, 94 | self$uiPattern, self$enableBookmarking) 95 | }, 96 | list_states = function(folder = "shiny_bookmarks"){ 97 | a <- list.files(folder, full.names = TRUE) 98 | if (length(a) == 0){ 99 | cat(crayon::green("No previous state found"), "\n") 100 | Sys.sleep(1) 101 | return(0) 102 | } else { 103 | last_state <- do.call(rbind, lapply(a, file.info)) 104 | last_state$name <- basename(a) 105 | last_state <- last_state[rev(order(last_state$mtime)), ] 106 | row.names(last_state) <- NULL 107 | last <- last_state[, c("name", "mtime")] 108 | names(last) <- c("id","last_modified_time") 109 | return(last) 110 | } 111 | }, 112 | dispose = function(folder = "shiny_bookmarks", save_last = TRUE){ 113 | if (yesno::yesno("This function will recursively remove all files from ", folder, ". Are you sure?")) { 114 | if(save_last){ 115 | last_state <- get_last_state(folder) 116 | a <- list.files(folder, full.names = TRUE) 117 | a <- a[!grepl(last_state, a)] 118 | } else { 119 | a <- list.files(folder, all.files = TRUE, full.names = TRUE) 120 | } 121 | x <- lapply(a, unlink, recursive = TRUE) 122 | invisible(x) 123 | } 124 | } 125 | ) 126 | ) 127 | ui_req <- function(request) { 128 | fluidPage( 129 | textInput("txt", "Enter text"), 130 | checkboxInput("caps", "Capitalize"), 131 | verbatimTextOutput("out"), 132 | actionButton("fo","fo") 133 | ) 134 | } 135 | server <- function(input, output, session) { 136 | observeEvent(input$fo, { 137 | record(session) 138 | }) 139 | output$out <- renderText({ 140 | if (input$caps) 141 | toupper(input$txt) 142 | else 143 | input$txt 144 | }) 145 | } 146 | johndoe <- Creature$new(ui_req, server) 147 | johndoe$as_fresh() 148 | johndoe$list_states() 149 | johndoe$revive(id = "AZ") 150 | #' A Shiny Creature 151 | #' 152 | #' @return An R6 object 153 | #' 154 | #' @section Methods: 155 | #' \describe{ 156 | #' \item{\code{as_fresh}}{run the app as fresh} 157 | #' \item{\code{dispose}}{remove old saved states} 158 | #' \item{\code{list_states}}{list all saved states} 159 | #' \item{\code{options}}{shiny options} 160 | #' \item{\code{revive}}{revive an old app from last states or specific one} 161 | #' \item{\code{server}}{server object} 162 | #' \item{\code{ui}}{ui object} 163 | #' } 164 | #' 165 | #' @importFrom R6 R6Class 166 | #' @export 167 | #' 168 | Creature <- R6::R6Class("Creature", 169 | public = list( 170 | ui = NULL, 171 | server = NULL, 172 | onStart = NULL, 173 | options = list(), 174 | uiPattern = "/", 175 | enableBookmarking = "server", 176 | scenario = "shiny_bookmarks", 177 | initialize = function(ui = NULL, 178 | server = NULL, 179 | options = list() 180 | ){ 181 | attempt::stop_if_not(ui, is.function, 182 | "ui should be a function with `request` as argument") 183 | self$ui <- ui 184 | self$server <- server 185 | self$options <- options 186 | }, 187 | as_fresh = function(ui = NULL, 188 | server = NULL, 189 | overwrite = TRUE){ 190 | if (!dir.exists(self$scenario)){ 191 | dir.create(self$scenario) 192 | } 193 | if (!is.null(ui)){ 194 | if (overwrite){ 195 | self$ui <- ui 196 | } 197 | } else { 198 | ui <- self$ui 199 | } 200 | if (!is.null(server)){ 201 | if (overwrite){ 202 | self$server <- server 203 | } 204 | } else { 205 | server <- self$server 206 | } 207 | ShinySession <- utils::getFromNamespace("ShinySession", "shiny") 208 | self$options$launch.browser <- function(appUrl){ 209 | invisible(.Call("rs_shinyviewer", url, getwd(), 3)) 210 | } 211 | ShinySession$set( 212 | which = "public", 213 | name = "chock", 214 | value = chock(), 215 | overwrite = TRUE) 216 | shiny::shinyApp(ui, server, 217 | self$onStart, self$options, 218 | self$uiPattern, self$enableBookmarking) 219 | }, 220 | revive = function(ui = NULL, 221 | server = NULL, 222 | overwrite = TRUE, 223 | id = NULL){ 224 | if (!dir.exists(self$scenario)){ 225 | dir.create(self$scenario) 226 | } 227 | if (!is.null(ui)){ 228 | if (overwrite){ 229 | self$ui <- ui 230 | } 231 | } else { 232 | ui <- self$ui 233 | } 234 | if (!is.null(server)){ 235 | if (overwrite){ 236 | self$server <- server 237 | } 238 | } else { 239 | server <- self$server 240 | } 241 | if (!is.null(id)){ 242 | browser() 243 | a <- list.files(self$scenario) 244 | stop_if_not(a, ~ .x %in% a, "Id not found") 245 | cat( crayon::green( glue::glue( "Launching from id : {id}" ) ), "\n") 246 | Sys.sleep(1) 247 | self$options$launch.browser <- function(appUrl){ 248 | url <- glue::glue('{appUrl}/?_state_id_={id}') 249 | invisible(.Call("rs_shinyviewer", url, getwd(), 3)) 250 | } 251 | } else { 252 | last_state <- get_last_state(self$scenario) 253 | if (last_state == 0){ 254 | cat(crayon::green("No previous state found"), "\n") 255 | Sys.sleep(1) 256 | cat(crayon::yellow("Launching the App"), "\n") 257 | } else { 258 | cat( crayon::green( glue::glue( "Last id found : {last_state}" ) ), "\n") 259 | Sys.sleep(1) 260 | cat(crayon::yellow("Launching the App"), "\n") 261 | self$options$launch.browser <- function(appUrl){ 262 | url <- glue::glue('{appUrl}/?_state_id_={last_state}') 263 | utils::browseURL(url) 264 | } 265 | } 266 | } 267 | ShinySession <- utils::getFromNamespace("ShinySession", "shiny") 268 | ShinySession$set( 269 | which = "public", 270 | name = "chock", 271 | value = chock(), 272 | overwrite = TRUE) 273 | shiny::shinyApp(ui, server, 274 | self$onStart, self$options, 275 | self$uiPattern, self$enableBookmarking) 276 | }, 277 | list_states = function(folder = "shiny_bookmarks"){ 278 | a <- list.files(folder, full.names = TRUE) 279 | if (length(a) == 0){ 280 | cat(crayon::green("No previous state found"), "\n") 281 | Sys.sleep(1) 282 | return(0) 283 | } else { 284 | last_state <- do.call(rbind, lapply(a, file.info)) 285 | last_state$name <- basename(a) 286 | last_state <- last_state[rev(order(last_state$mtime)), ] 287 | row.names(last_state) <- NULL 288 | last <- last_state[, c("name", "mtime")] 289 | names(last) <- c("id","last_modified_time") 290 | return(last) 291 | } 292 | }, 293 | dispose = function(folder = "shiny_bookmarks", save_last = TRUE){ 294 | if (yesno::yesno("This function will recursively remove all files from ", folder, ". Are you sure?")) { 295 | if(save_last){ 296 | last_state <- get_last_state(folder) 297 | a <- list.files(folder, full.names = TRUE) 298 | a <- a[!grepl(last_state, a)] 299 | } else { 300 | a <- list.files(folder, all.files = TRUE, full.names = TRUE) 301 | } 302 | x <- lapply(a, unlink, recursive = TRUE) 303 | invisible(x) 304 | } 305 | } 306 | ) 307 | ) 308 | johndoe <- Creature$new(ui_req, server) 309 | johndoe$revive(id = "AZ") 310 | a <- list.files(self$scenario) 311 | a 312 | id 313 | id %in% a 314 | library(shiny) 315 | ui_req <- function(request) { 316 | fluidPage( 317 | textInput("txt", "Enter text"), 318 | checkboxInput("caps", "Capitalize"), 319 | verbatimTextOutput("out"), 320 | actionButton("fo","fo") 321 | ) 322 | } 323 | server <- function(input, output, session) { 324 | observeEvent(input$fo, { 325 | session$doBookmark() 326 | }) 327 | output$out <- renderText({ 328 | if (input$caps) 329 | toupper(input$txt) 330 | else 331 | input$txt 332 | }) 333 | } 334 | shinyApp(ui_req, server) 335 | johndoe <- Creature$new(ui_req, server) 336 | ui_record <- function(request) { 337 | fluidPage( 338 | textInput("txt", "Enter text"), 339 | checkboxInput("caps", "Capitalize"), 340 | verbatimTextOutput("out") 341 | ) 342 | } 343 | server_record <- function(input, output, session) { 344 | monitor(session, 1000) 345 | output$out <- renderText({ 346 | if (input$caps) 347 | toupper(input$txt) 348 | else 349 | input$txt 350 | }) 351 | } 352 | johndoe$as_fresh(ui = ui_record, server = server_record) 353 | johndoe$list_states() 354 | library(frankenstein) 355 | roxygen2::roxygenise() 356 | library(frankenstein) 357 | library(frankenstein) 358 | library(frankenstein) 359 | shiny:::ShinySession 360 | shiny:::ShinySession$set 361 | library(frankenstein) 362 | library(shiny) 363 | ui_req <- function(request) { 364 | fluidPage( 365 | textInput("txt", "Enter text"), 366 | checkboxInput("caps", "Capitalize"), 367 | verbatimTextOutput("out"), 368 | actionButton("fo","fo") 369 | ) 370 | } 371 | server <- function(input, output, session) { 372 | observeEvent(input$fo, { 373 | session$doBookmark() 374 | }) 375 | output$out <- renderText({ 376 | if (input$caps) 377 | toupper(input$txt) 378 | else 379 | input$txt 380 | }) 381 | } 382 | library(frankenstein) 383 | johndoe <- Creature$new(ui_req, server) 384 | ui_req <- function(request) { 385 | fluidPage( 386 | textInput("txt", "Enter text"), 387 | checkboxInput("caps", "Capitalize"), 388 | verbatimTextOutput("out"), 389 | actionButton("fo","fo") 390 | ) 391 | } 392 | server <- function(input, output, session) { 393 | observeEvent(input$fo, { 394 | record(session) 395 | }) 396 | output$out <- renderText({ 397 | if (input$caps) 398 | toupper(input$txt) 399 | else 400 | input$txt 401 | }) 402 | } 403 | johndoe <- Creature$new(ui_req, server) 404 | johndoe$as_fresh() 405 | library(frankenstein) 406 | library(shiny) 407 | ui_req <- function(request) { 408 | fluidPage( 409 | textInput("txt", "Enter text"), 410 | checkboxInput("caps", "Capitalize"), 411 | verbatimTextOutput("out"), 412 | actionButton("fo","fo") 413 | ) 414 | } 415 | server <- function(input, output, session) { 416 | observeEvent(input$fo, { 417 | record(session) 418 | }) 419 | output$out <- renderText({ 420 | if (input$caps) 421 | toupper(input$txt) 422 | else 423 | input$txt 424 | }) 425 | } 426 | library(frankenstein) 427 | johndoe <- Creature$new(ui_req, server) 428 | johndoe$as_fresh() 429 | record <- function(session){ 430 | browser() 431 | attempt(session$chock(), 432 | "Unable to save the state.\nDid you call `record` from outside a Frankenstein instance?") 433 | } 434 | library(frankenstein) 435 | library(shiny) 436 | ui_req <- function(request) { 437 | fluidPage( 438 | textInput("txt", "Enter text"), 439 | checkboxInput("caps", "Capitalize"), 440 | verbatimTextOutput("out"), 441 | actionButton("fo","fo") 442 | ) 443 | } 444 | server <- function(input, output, session) { 445 | observeEvent(input$fo, { 446 | record(session) 447 | }) 448 | output$out <- renderText({ 449 | if (input$caps) 450 | toupper(input$txt) 451 | else 452 | input$txt 453 | }) 454 | } 455 | library(frankenstein) 456 | johndoe <- Creature$new(ui_req, server) 457 | johndoe$as_fresh() 458 | johndoe$revive() 459 | session 460 | session$chock 461 | session$chock() 462 | library(frankenstein) 463 | library(shiny) 464 | ui_req <- function(request) { 465 | fluidPage( 466 | textInput("txt", "Enter text"), 467 | checkboxInput("caps", "Capitalize"), 468 | verbatimTextOutput("out"), 469 | actionButton("fo","fo") 470 | ) 471 | } 472 | server <- function(input, output, session) { 473 | observeEvent(input$fo, { 474 | record(session) 475 | }) 476 | output$out <- renderText({ 477 | if (input$caps) 478 | toupper(input$txt) 479 | else 480 | input$txt 481 | }) 482 | } 483 | library(frankenstein) 484 | johndoe <- Creature$new(ui_req, server) 485 | johndoe$as_fresh() 486 | session$chock() 487 | library(frankenstein) 488 | library(frankenstein) 489 | library(shiny) 490 | ui_req <- function(request) { 491 | fluidPage( 492 | textInput("txt", "Enter text"), 493 | checkboxInput("caps", "Capitalize"), 494 | verbatimTextOutput("out"), 495 | actionButton("fo","fo") 496 | ) 497 | } 498 | server <- function(input, output, session) { 499 | observeEvent(input$fo, { 500 | record(session) 501 | }) 502 | output$out <- renderText({ 503 | if (input$caps) 504 | toupper(input$txt) 505 | else 506 | input$txt 507 | }) 508 | } 509 | library(frankenstein) 510 | johndoe <- Creature$new(ui_req, server) 511 | johndoe$as_fresh() 512 | library(frankenstein) 513 | -------------------------------------------------------------------------------- /.Rproj.user/8B1EABEC/console06/FE4A14: -------------------------------------------------------------------------------- 1 | ]0;~/Seafile/documents_colin/R/frankenstein[?1034hMacBook-Pro-de-colin:frankenstein colin$ usethis::use_package("crayon") 2 | bash: syntax error near unexpected token `"crayon"' 3 | ]0;~/Seafile/documents_colin/R/frankenstein[?1034hMacBook-Pro-de-colin:frankenstein colin$ MacBook-Pro-de-colin:frankenstein colin$ git init 4 | Initialized empty Git repository in /Users/colin/Seafile/documents_colin/R/frankenstein/.git/ 5 | ]0;~/Seafile/documents_colin/R/frankensteinMacBook-Pro-de-colin:frankenstein colin$ git commit -m "first commit"👶" 👶" 6 | On branch master 7 | 8 | Initial commit 9 | 10 | Untracked files: 11 | .DS_Store 12 | .RData 13 | .Rbuildignore 14 | .Rhistory 15 | .Rproj.user/ 16 | CODE_OF_CONDUCT.md 17 | DESCRIPTION 18 | LICENSE 19 | LICENSE.md 20 | NAMESPACE 21 | NEWS.md 22 | R/ 23 | README.Rmd 24 | README.md 25 | data-raw/ 26 | frankenstein.Rproj 27 | man/ 28 | readme_fig/ 29 | shiny_bookmarks/ 30 | testapp.R 31 | tests/ 32 | 33 | nothing added to commit but untracked files present 34 | ]0;~/Seafile/documents_colin/R/frankensteinMacBook-Pro-de-colin:frankenstein colin$ git commit -m "first commit 👶"initadd / 35 | fatal: /: '/' is outside repository 36 | ]0;~/Seafile/documents_colin/R/frankensteinMacBook-Pro-de-colin:frankenstein colin$ git add /. 37 | ]0;~/Seafile/documents_colin/R/frankensteinMacBook-Pro-de-colin:frankenstein colin$ git add ./commit -m "first commit 👶" 38 | [master (root-commit) 68f52af] first commit 👶 39 | 82 files changed, 2988 insertions(+) 40 | create mode 100644 .DS_Store 41 | create mode 100644 .RData 42 | create mode 100644 .Rbuildignore 43 | create mode 100644 .Rhistory 44 | create mode 100644 .Rproj.user/8B1EABEC/console06/FE4A14 45 | create mode 100644 .Rproj.user/8B1EABEC/console06/FE4A14.env 46 | create mode 100644 .Rproj.user/8B1EABEC/console06/INDEX001 47 | create mode 100644 .Rproj.user/8B1EABEC/cpp-definition-cache 48 | create mode 100644 .Rproj.user/8B1EABEC/pcs/debug-breakpoints.pper 49 | create mode 100644 .Rproj.user/8B1EABEC/pcs/files-pane.pper 50 | create mode 100644 .Rproj.user/8B1EABEC/pcs/source-pane.pper 51 | create mode 100644 .Rproj.user/8B1EABEC/pcs/windowlayoutstate.pper 52 | create mode 100644 .Rproj.user/8B1EABEC/pcs/workbench-pane.pper 53 | create mode 100644 .Rproj.user/8B1EABEC/persistent-state 54 | create mode 100644 .Rproj.user/8B1EABEC/rmd-outputs 55 | create mode 100644 .Rproj.user/8B1EABEC/saved_source_markers 56 | create mode 100644 .Rproj.user/8B1EABEC/sources/prop/22B8063F 57 | create mode 100644 .Rproj.user/8B1EABEC/sources/prop/55A79ACC 58 | create mode 100644 .Rproj.user/8B1EABEC/sources/prop/6FB169F0 59 | create mode 100644 .Rproj.user/8B1EABEC/sources/prop/87524BD3 60 | create mode 100644 .Rproj.user/8B1EABEC/sources/prop/9C8C892 61 | create mode 100644 .Rproj.user/8B1EABEC/sources/prop/CB39595A 62 | create mode 100644 .Rproj.user/8B1EABEC/sources/prop/E4BB522D 63 | create mode 100644 .Rproj.user/8B1EABEC/sources/prop/F5BF7629 64 | create mode 100644 .Rproj.user/8B1EABEC/sources/prop/INDEX 65 | create mode 100644 .Rproj.user/8B1EABEC/sources/s-AD3DAB17/15109F6C-contents 66 | create mode 100644 .Rproj.user/8B1EABEC/sources/s-AD3DAB17/1AF21B3F-contents 67 | create mode 100644 .Rproj.user/8B1EABEC/sources/s-AD3DAB17/237EF341-contents 68 | create mode 100644 .Rproj.user/8B1EABEC/sources/s-AD3DAB17/57D9BD66-contents 69 | create mode 100644 .Rproj.user/8B1EABEC/sources/s-AD3DAB17/5E5EE3EF-contents 70 | create mode 100644 .Rproj.user/8B1EABEC/sources/s-AD3DAB17/631D40F3 71 | create mode 100644 .Rproj.user/8B1EABEC/sources/s-AD3DAB17/631D40F3-contents 72 | create mode 100644 .Rproj.user/8B1EABEC/sources/s-AD3DAB17/6ABDBD64-contents 73 | create mode 100644 .Rproj.user/8B1EABEC/sources/s-AD3DAB17/76433F1 74 | create mode 100644 .Rproj.user/8B1EABEC/sources/s-AD3DAB17/76433F1-contents 75 | create mode 100644 .Rproj.user/8B1EABEC/sources/s-AD3DAB17/78539925-contents 76 | create mode 100644 .Rproj.user/8B1EABEC/sources/s-AD3DAB17/84023832 77 | create mode 100644 .Rproj.user/8B1EABEC/sources/s-AD3DAB17/84023832-contents 78 | create mode 100644 .Rproj.user/8B1EABEC/sources/s-AD3DAB17/852BA706-contents 79 | create mode 100644 .Rproj.user/8B1EABEC/sources/s-AD3DAB17/8DF95D8F-contents 80 | create mode 100644 .Rproj.user/8B1EABEC/sources/s-AD3DAB17/8F5595C4 81 | create mode 100644 .Rproj.user/8B1EABEC/sources/s-AD3DAB17/8F5595C4-contents 82 | create mode 100644 .Rproj.user/8B1EABEC/sources/s-AD3DAB17/91C19260-contents 83 | create mode 100644 .Rproj.user/8B1EABEC/sources/s-AD3DAB17/A083DB13-contents 84 | create mode 100644 .Rproj.user/8B1EABEC/sources/s-AD3DAB17/ABBB0D2C-contents 85 | create mode 100644 .Rproj.user/8B1EABEC/sources/s-AD3DAB17/AF4D74C1-contents 86 | create mode 100644 .Rproj.user/8B1EABEC/sources/s-AD3DAB17/B7FA937E-contents 87 | create mode 100644 .Rproj.user/8B1EABEC/sources/s-AD3DAB17/C5CDBF7A-contents 88 | create mode 100644 .Rproj.user/8B1EABEC/sources/s-AD3DAB17/CCFE315F-contents 89 | create mode 100644 .Rproj.user/8B1EABEC/sources/s-AD3DAB17/D1254EEF-contents 90 | create mode 100644 .Rproj.user/8B1EABEC/sources/s-AD3DAB17/EA18C4C2-contents 91 | create mode 100644 .Rproj.user/8B1EABEC/sources/s-AD3DAB17/F365E3DF-contents 92 | create mode 100644 .Rproj.user/8B1EABEC/sources/s-AD3DAB17/FAC923D8 93 | create mode 100644 .Rproj.user/8B1EABEC/sources/s-AD3DAB17/FAC923D8-contents 94 | create mode 100644 .Rproj.user/8B1EABEC/sources/s-AD3DAB17/lock_file 95 | create mode 100644 .Rproj.user/shared/notebooks/5972E819-README/1/8B1EABEC8B43C756/chunks.json 96 | create mode 100644 .Rproj.user/shared/notebooks/5972E819-README/1/8B1EABECAD3DAB17/chunks.json 97 | create mode 100644 .Rproj.user/shared/notebooks/5972E819-README/1/s/chunks.json 98 | create mode 100644 .Rproj.user/shared/notebooks/patch-chunk-names 99 | create mode 100644 .Rproj.user/shared/notebooks/paths 100 | create mode 100644 CODE_OF_CONDUCT.md 101 | create mode 100644 DESCRIPTION 102 | create mode 100644 LICENSE 103 | create mode 100644 LICENSE.md 104 | create mode 100644 NAMESPACE 105 | create mode 100644 NEWS.md 106 | create mode 100644 R/chock.R 107 | create mode 100644 R/frankenstein.R 108 | create mode 100644 R/surgery.R 109 | create mode 100644 README.Rmd 110 | create mode 100644 README.md 111 | create mode 100644 data-raw/devstuffs.R 112 | create mode 100644 frankenstein.Rproj 113 | create mode 100644 man/Creature.Rd 114 | create mode 100644 readme_fig/every_second.png 115 | create mode 100644 readme_fig/save_state.png 116 | create mode 100644 shiny_bookmarks/0a12f58440b83ba8/input.rds 117 | create mode 100644 shiny_bookmarks/2d70fbbce8aa7770/input.rds 118 | create mode 100644 shiny_bookmarks/3fe0ae7e6bae16d0/input.rds 119 | create mode 100644 shiny_bookmarks/f0de8671967d0078/input.rds 120 | create mode 100644 testapp.R 121 | create mode 100644 tests/testthat.R 122 | ]0;~/Seafile/documents_colin/R/frankensteinMacBook-Pro-de-colin:frankenstein colin$ git remote add origin https://github.com/ThinkR-open/frankenstein.git 123 | ]0;~/Seafile/documents_colin/R/frankensteinMacBook-Pro-de-colin:frankenstein colin$ git push -u origin master 124 | Counting objects: 81, done. 125 | Delta compression using up to 4 threads. 126 | Compressing objects: 1% (1/67) Compressing objects: 2% (2/67) Compressing objects: 4% (3/67) Compressing objects: 5% (4/67) Compressing objects: 7% (5/67) Compressing objects: 8% (6/67) Compressing objects: 10% (7/67) Compressing objects: 11% (8/67) Compressing objects: 13% (9/67) Compressing objects: 14% (10/67) Compressing objects: 16% (11/67) Compressing objects: 17% (12/67) Compressing objects: 19% (13/67) Compressing objects: 20% (14/67) Compressing objects: 22% (15/67) Compressing objects: 23% (16/67) Compressing objects: 25% (17/67) Compressing objects: 26% (18/67) Compressing objects: 28% (19/67) Compressing objects: 29% (20/67) Compressing objects: 31% (21/67) Compressing objects: 32% (22/67) Compressing objects: 34% (23/67) Compressing objects: 35% (24/67) Compressing objects: 37% (25/67) Compressing objects: 38% (26/67) Compressing objects: 40% (27/67) Compressing objects: 41% (28/67) Compressing objects: 43% (29/67) Compressing objects: 44% (30/67) Compressing objects: 46% (31/67) Compressing objects: 47% (32/67) Compressing objects: 49% (33/67) Compressing objects: 50% (34/67) Compressing objects: 52% (35/67) Compressing objects: 53% (36/67) Compressing objects: 55% (37/67) Compressing objects: 56% (38/67) Compressing objects: 58% (39/67) Compressing objects: 59% (40/67) Compressing objects: 61% (41/67) Compressing objects: 62% (42/67) Compressing objects: 64% (43/67) Compressing objects: 65% (44/67) Compressing objects: 67% (45/67) Compressing objects: 68% (46/67) Compressing objects: 70% (47/67) Compressing objects: 71% (48/67) Compressing objects: 73% (49/67) Compressing objects: 74% (50/67) Compressing objects: 76% (51/67) Compressing objects: 77% (52/67) Compressing objects: 79% (53/67) Compressing objects: 80% (54/67) Compressing objects: 82% (55/67) Compressing objects: 83% (56/67) Compressing objects: 85% (57/67) Compressing objects: 86% (58/67) Compressing objects: 88% (59/67) Compressing objects: 89% (60/67) Compressing objects: 91% (61/67) Compressing objects: 92% (62/67) Compressing objects: 94% (63/67) Compressing objects: 95% (64/67) Compressing objects: 97% (65/67) Compressing objects: 98% (66/67) Compressing objects: 100% (67/67) Compressing objects: 100% (67/67), done. 127 | Writing objects: 1% (1/81) Writing objects: 2% (2/81) Writing objects: 3% (3/81) Writing objects: 4% (4/81) Writing objects: 6% (5/81) Writing objects: 7% (6/81) Writing objects: 8% (7/81) Writing objects: 9% (8/81) Writing objects: 11% (9/81) Writing objects: 12% (10/81) Writing objects: 13% (11/81) Writing objects: 14% (12/81) Writing objects: 16% (13/81) Writing objects: 17% (14/81) Writing objects: 18% (15/81) Writing objects: 19% (16/81) Writing objects: 20% (17/81) Writing objects: 22% (18/81) Writing objects: 23% (19/81) Writing objects: 24% (20/81) Writing objects: 25% (21/81) Writing objects: 27% (22/81) Writing objects: 28% (23/81) Writing objects: 29% (24/81) Writing objects: 30% (25/81) Writing objects: 32% (26/81) Writing objects: 33% (27/81) Writing objects: 34% (28/81) Writing objects: 35% (29/81) Writing objects: 37% (30/81) Writing objects: 38% (31/81) Writing objects: 39% (32/81) Writing objects: 40% (33/81) Writing objects: 41% (34/81) Writing objects: 43% (35/81) Writing objects: 44% (36/81) Writing objects: 45% (37/81) Writing objects: 48% (39/81) Writing objects: 49% (40/81) Writing objects: 50% (41/81) Writing objects: 51% (42/81) Writing objects: 53% (43/81) Writing objects: 54% (44/81) Writing objects: 56% (46/81) Writing objects: 58% (47/81) Writing objects: 59% (48/81) Writing objects: 60% (49/81) Writing objects: 61% (50/81) Writing objects: 62% (51/81) Writing objects: 64% (52/81) Writing objects: 65% (53/81) Writing objects: 66% (54/81) Writing objects: 67% (55/81) Writing objects: 69% (56/81) Writing objects: 70% (57/81) Writing objects: 71% (58/81) Writing objects: 72% (59/81) Writing objects: 74% (60/81) Writing objects: 75% (61/81) Writing objects: 76% (62/81) Writing objects: 77% (63/81) Writing objects: 79% (64/81) Writing objects: 80% (65/81) Writing objects: 81% (66/81) Writing objects: 82% (67/81) Writing objects: 83% (68/81) Writing objects: 85% (69/81) Writing objects: 86% (70/81) Writing objects: 87% (71/81) Writing objects: 88% (72/81) Writing objects: 90% (73/81) Writing objects: 91% (74/81) Writing objects: 91% (74/81), 1.07 MiB | 533.00 KiB/s Writing objects: 91% (74/81), 1.19 MiB | 402.00 KiB/s Writing objects: 92% (75/81), 1.19 MiB | 402.00 KiB/s Writing objects: 93% (76/81), 1.19 MiB | 402.00 KiB/s Writing objects: 95% (77/81), 1.19 MiB | 402.00 KiB/s Writing objects: 96% (78/81), 1.19 MiB | 402.00 KiB/s Writing objects: 97% (79/81), 1.19 MiB | 402.00 KiB/s Writing objects: 98% (80/81), 1.19 MiB | 402.00 KiB/s Writing objects: 100% (81/81), 1.19 MiB | 402.00 KiB/s Writing objects: 100% (81/81), 1.22 MiB | 408.00 KiB/s, done. 128 | Total 81 (delta 10), reused 0 (delta 0) 129 | remote: Resolving deltas: 0% (0/10)  remote: Resolving deltas: 10% (1/10)  remote: Resolving deltas: 20% (2/10)  remote: Resolving deltas: 30% (3/10)  remote: Resolving deltas: 60% (6/10)  remote: Resolving deltas: 70% (7/10)  remote: Resolving deltas: 80% (8/10)  remote: Resolving deltas: 90% (9/10)  remote: Resolving deltas: 100% (10/10)  remote: Resolving deltas: 100% (10/10), done. 130 | To https://github.com/ThinkR-open/frankenstein.git 131 | * [new branch] master -> master 132 | Branch master set up to track remote branch master from origin. 133 | MacBook-Pro-de-colin:frankenstein colin$ git push -u origin masterremote add origin https://github.com/ThinkR-open/frankenstein.git commit -m "first commit 👶"add .commit -m "first commit 👶"add . --------------------------------------------------------------------------------