mirror of
https://github.com/rstudio/shiny.git
synced 2026-02-01 10:15:05 -05:00
187 lines
4.5 KiB
R
187 lines
4.5 KiB
R
# TESTS
|
|
# Simple set/get
|
|
# Simple remove
|
|
# Simple containsKey
|
|
# Simple keys
|
|
# Simple values
|
|
# Simple clear
|
|
# Get of unknown key returns NULL
|
|
# Remove of unknown key does nothing
|
|
# Setting a key twice always results in last-one-wins
|
|
# /TESTS
|
|
Map <- setRefClass(
|
|
'Map',
|
|
fields = list(
|
|
.env = 'environment'
|
|
),
|
|
methods = list(
|
|
initialize = function() {
|
|
.env <<- new.env(parent=emptyenv())
|
|
},
|
|
get = function(key) {
|
|
if (.self$containsKey(key))
|
|
return(base::get(key, pos=.env, inherits=F))
|
|
else
|
|
return(NULL)
|
|
},
|
|
set = function(key, value) {
|
|
assign(key, value, pos=.env, inherits=F)
|
|
return(value)
|
|
},
|
|
remove = function(key) {
|
|
if (.self$containsKey(key)) {
|
|
result <- .self$get(key)
|
|
rm(list = key, pos=.env, inherits=F)
|
|
return(result)
|
|
}
|
|
return(NULL)
|
|
},
|
|
containsKey = function(key) {
|
|
exists(key, where=.env, inherits=F)
|
|
},
|
|
keys = function() {
|
|
ls(envir=.env, all.names=T)
|
|
},
|
|
values = function() {
|
|
mget(.self$keys(), envir=.env, inherits=F)
|
|
},
|
|
clear = function() {
|
|
.env <<- new.env(parent=emptyenv())
|
|
invisible(NULL)
|
|
},
|
|
size = function() {
|
|
length(.env)
|
|
}
|
|
)
|
|
)
|
|
|
|
`[.Map` <- function(map, name) {
|
|
map$get(name)
|
|
}
|
|
|
|
`[<-.Map` <- function(map, name, value) {
|
|
map$set(name, value)
|
|
return(map)
|
|
}
|
|
|
|
as.list.Map <- function(map) {
|
|
sapply(map$keys(),
|
|
map$get,
|
|
simplify=F)
|
|
}
|
|
length.Map <- function(map) {
|
|
map$size()
|
|
}
|
|
|
|
Context <- setRefClass(
|
|
'Context',
|
|
fields = list(
|
|
id = 'character',
|
|
.invalidated = 'logical',
|
|
.callbacks = 'list'
|
|
),
|
|
methods = list(
|
|
initialize = function() {
|
|
id <<- .getReactiveEnvironment()$nextId()
|
|
.invalidated <<- F
|
|
.callbacks <<- list()
|
|
},
|
|
run = function(func) {
|
|
"Run the provided function under this context."
|
|
env <- .getReactiveEnvironment()
|
|
env$runWith(.self, func)
|
|
},
|
|
invalidate = function() {
|
|
"Schedule this context for invalidation. It will not actually be
|
|
invalidated until the next call to \\code{\\link{flushReact}}."
|
|
if (.invalidated)
|
|
return()
|
|
.invalidated <<- T
|
|
.getReactiveEnvironment()$addPendingInvalidate(.self)
|
|
NULL
|
|
},
|
|
onInvalidate = function(func) {
|
|
"Register a function to be called when this context is invalidated.
|
|
If this context is already invalidated, the function is called
|
|
immediately."
|
|
if (.invalidated)
|
|
func()
|
|
else
|
|
.callbacks <<- c(.callbacks, func)
|
|
NULL
|
|
},
|
|
executeCallbacks = function() {
|
|
"For internal use only."
|
|
lapply(.callbacks, function(func) {
|
|
tryCatch({
|
|
func()
|
|
}, warning = function(e) {
|
|
# TODO: Callbacks in app
|
|
print(e)
|
|
}, error = function(e) {
|
|
# TODO: Callbacks in app
|
|
print(e)
|
|
})
|
|
})
|
|
}
|
|
)
|
|
)
|
|
|
|
ReactiveEnvironment <- setRefClass(
|
|
'ReactiveEnvironment',
|
|
fields = c('.currentContext', '.nextId', '.pendingInvalidate'),
|
|
methods = list(
|
|
initialize = function() {
|
|
.currentContext <<- NULL
|
|
.nextId <<- 0L
|
|
.pendingInvalidate <<- list()
|
|
},
|
|
nextId = function() {
|
|
.nextId <<- .nextId + 1L
|
|
return(as.character(.nextId))
|
|
},
|
|
currentContext = function() {
|
|
if (is.null(.currentContext))
|
|
stop('No reactive context is active')
|
|
return(.currentContext)
|
|
},
|
|
runWith = function(ctx, func) {
|
|
old.ctx <- .currentContext
|
|
.currentContext <<- ctx
|
|
on.exit(.currentContext <<- old.ctx)
|
|
func()
|
|
},
|
|
addPendingInvalidate = function(ctx) {
|
|
.pendingInvalidate <<- c(.pendingInvalidate, ctx)
|
|
},
|
|
flush = function() {
|
|
while (length(.pendingInvalidate) > 0) {
|
|
contexts <- .pendingInvalidate
|
|
.pendingInvalidate <<- list()
|
|
lapply(contexts, function(ctx) {
|
|
ctx$executeCallbacks()
|
|
NULL
|
|
})
|
|
}
|
|
}
|
|
)
|
|
)
|
|
|
|
.getReactiveEnvironment <- function() {
|
|
if (!exists('.ReactiveEnvironment', envir=.GlobalEnv, inherits=F)) {
|
|
assign('.ReactiveEnvironment', ReactiveEnvironment$new(), envir=.GlobalEnv)
|
|
}
|
|
get('.ReactiveEnvironment', envir=.GlobalEnv, inherits=F)
|
|
}
|
|
|
|
#' Causes any pending invalidations to run.
|
|
flushReact <- function() {
|
|
.getReactiveEnvironment()$flush()
|
|
}
|
|
|
|
#' Retrieves the current reactive context, or errors if there is no reactive
|
|
#' context active at the moment.
|
|
getCurrentContext <- function() {
|
|
.getReactiveEnvironment()$currentContext()
|
|
}
|