alabaster.base 1.0.0
Developers can also create “alabaster applications”, which customize the machinery of the alabaster framework for specific needs. Customizations typically involve:
We provide a number of hooks inside alabaster.base to enable applications to apply these customizations over the defaults.
The acquireMetadata()
and acquireFile()
generic, which describe how the metadata and file artifacts should be acquired.
For example, applications can write new methods that query APIs for this content rather than reading it from the filesystem.
library(alabaster.base)
setClass("RemoteDownloadHandler", slots=c(host="character", id="character"))
setMethod("acquireFile", "RemoteDownloadHandler", function(project, path) {
# Download a file here, possibly with some application-specific caching.
demo.url <- paste0(project@host, "/projects/", project@id, "/file", path)
target <- tempfile()
download.file(demo.url, target)
target
})
setMethod("acquireMetadata", "RemoteDownloadHandler", function(project, path) {
# Pull down JSON metadata, possibly with some application-specific caching.
demo.url <- paste0(project@host, "/projects/", project@id, "/file", path)
target <- tempfile()
download.file(demo.url, target)
jsonlite::fromJSON(target, simplifyVector=FALSE)
})
We can then construct an instance of a RemoteDownloadHandler
;
proj <- new("RemoteDownloadHandler", host="https://my.institute.org/downloads", id="PROJECT_ID")
And use it in loadObject()
, which will use the new methods for all internal acquireMetadata()
and acquireFile()
calls.
This will instruct loadObject()
to download remote content on demand.
# Demonstration only.
meta <- acquireMetadata(proj, "some/file/path.csv")
obj <- loadObject(meta, proj)
Applications can define their own schemas with custom metadata requirements or data structures.
See here for more details.
Once created, the application-specific schemas should be stored in the inst/schemas
directory of the application’s R package.
The .altStageObject()
setter allows applications to replace stageObject()
with an alternative staging generic.
This can be used to perform additional tasks during staging of some or all classes, e.g., add more metadata.
For example, we could force all saving operations to include the author in the metadata for non-child objects:
setGeneric("appStageObject", function(x, dir, path, child=FALSE, ...)
standardGeneric("appStageObject"))
## [1] "appStageObject"
setMethod("appStageObject", "ANY", function(x, dir, path, child=FALSE, ...) {
meta <- stageObject(x, dir, path, child=child, ...)
# Creating a fallback that adds authorship to all non-child objects.
if (!child) {
meta$authors <- I(Sys.info()[["user"]])
}
# Pointing .writeMetadata to the application package storing the schemas.
attr(meta[["$schema"]], "package") <- "APPLICATION_NAME_HERE"
meta
})
Application developers will typically create another wrapper function that runs the setter before attempting to stage an object. This is more convenient for the end-users of that application, who do not have to remember what to set:
appSave <- function(x, dir, path, child=FALSE) {
olds <- .altStageObject(appStageObject)
on.exit(.altStageObject(olds))
meta <- appStageObject(x, dir, path, child=child)
written <- .writeMetadata(meta, dir)
written$path
}
Of course, it is possible to customize the staging of specific classes by simply defining a new method for the new generic:
setMethod("appStageObject", "DFrame", function(x, dir, path, child=FALSE, ...) {
# Extracting details from the metadata.
clinical.trial.id <- metadata(x)$trial_id
treatment <- metadata(x)$treatment
study.design <- metadata(x)$study
# Calling the ANY method, which eventually just calls stageObject...
meta <- callNextMethod()
# Adding some metadata for data frames, assuming these properties are
# listed in the schema.
meta[["clinical_trail_details"]] <- list(
trial_id = trail.id,
treatment = treatment,
design = study.design
)
meta
})
Similarly, the .altLoadObject()
setter allows applications to set an alternative loading function to replace loadObject()
.
This is necessary if .altStageObject()
is used to define a staging override that points to a different set of schemas;
in which case, the loading method must also be overridden to look at those schemas to obtain appropriate restoration method (in the _attributes.restore.R
property).
The loading method may also attach various bits and pieces of global metadata that we might have stored, e.g. authorship.
# Memorize schema look-up in the R session, to avoid having to repeatedly query
# the R package directory on the file system at every loadObject request.
memory <- new.env()
memory$cache <- list()
appLoadObject <- function(info, project, ...) {
# .loadObjectInternal is a helper function that handles loading
# with different schema location and memory store.
output <- .loadObjectInternal(info, project, ...,
.locations="APPLCATION_NAME_HERE",
.memory=memory
)
if ("authors" %in% names(info) && is(output, "Annotated")) {
metadata(output)$authors <- info$authors
}
output
}
Application developers will typically create another wrapper function that runs the setter before attempting to load an object.
This wrapper may also create the application-specific *Handler
class that will be used to override acquireFile
and acquireMetadata
.
appLoad <- function(project, path) {
oldl <- .altLoadObject(appLoadObject)
on.exit(.altLoadObject(oldl))
info <- acquireMetadata(project, path)
appLoadObject(info, project, child=child)
}
Note that .altLoadObject()
will override the loading for all objects.
For overrides of specific objects, application developers can simply modify the _attributes.restore.R
in the corresponding schema to point to a different function.
sessionInfo()
## R version 4.3.0 RC (2023-04-13 r84269)
## Platform: x86_64-pc-linux-gnu (64-bit)
## Running under: Ubuntu 22.04.2 LTS
##
## Matrix products: default
## BLAS: /home/biocbuild/bbs-3.17-bioc/R/lib/libRblas.so
## LAPACK: /usr/lib/x86_64-linux-gnu/lapack/liblapack.so.3.10.0
##
## locale:
## [1] LC_CTYPE=en_US.UTF-8 LC_NUMERIC=C
## [3] LC_TIME=en_GB LC_COLLATE=C
## [5] LC_MONETARY=en_US.UTF-8 LC_MESSAGES=en_US.UTF-8
## [7] LC_PAPER=en_US.UTF-8 LC_NAME=C
## [9] LC_ADDRESS=C LC_TELEPHONE=C
## [11] LC_MEASUREMENT=en_US.UTF-8 LC_IDENTIFICATION=C
##
## time zone: America/New_York
## tzcode source: system (glibc)
##
## attached base packages:
## [1] stats graphics grDevices utils datasets methods base
##
## other attached packages:
## [1] alabaster.base_1.0.0 BiocStyle_2.28.0
##
## loaded via a namespace (and not attached):
## [1] cli_3.6.1 knitr_1.42 rlang_1.1.0
## [4] xfun_0.39 jsonlite_1.8.4 S4Vectors_0.38.0
## [7] htmltools_0.5.5 sass_0.4.5 stats4_4.3.0
## [10] rmarkdown_2.21 evaluate_0.20 jquerylib_0.1.4
## [13] fastmap_1.1.1 yaml_2.3.7 alabaster.schemas_1.0.0
## [16] Rhdf5lib_1.22.0 bookdown_0.33 BiocManager_1.30.20
## [19] compiler_4.3.0 Rcpp_1.0.10 rhdf5filters_1.12.0
## [22] rhdf5_2.44.0 digest_0.6.31 R6_2.5.1
## [25] bslib_0.4.2 tools_4.3.0 BiocGenerics_0.46.0
## [28] cachem_1.0.7