Skip to content

Commit

Permalink
Moved the base list format global switch into saveBaseList.R.
Browse files Browse the repository at this point in the history
This also centralizes the documentation for the switch with the saving
method that it affects for easier discovery.
  • Loading branch information
LTLA committed Nov 28, 2023
1 parent 4d6adf5 commit 3bd3d67
Show file tree
Hide file tree
Showing 5 changed files with 60 additions and 33 deletions.
38 changes: 33 additions & 5 deletions R/saveBaseList.R
Original file line number Diff line number Diff line change
Expand Up @@ -3,27 +3,33 @@
#' Save a \link{list} or \linkS4class{List} to a JSON or HDF5 file, with extra files created for any of the more complex list elements (e.g., DataFrames, arrays).
#' This uses the \href{https://github.com/LTLA/uzuki2}{uzuki2} specification to ensure that appropriate types are declared.
#'
#' @param x A list or \linkS4class{List}.
#' @param x An ordinary R list, named or unnamed.
#' Alternatively, a \linkS4class{List} to be coerced into a list..
#' @inheritParams saveObject
#' @param list.format String specifying the format in which to save the list.
#' @param ... Further arguments, passed to \code{\link{altSaveObject}} for complex child objects.
#'
#' @return
#' \code{x} is saved inside \code{dir}.
#' For the \code{saveObject} method, \code{x} is saved inside \code{dir}.
#' \code{NULL} is invisibly returned.
#'
#' For \code{saveBaseListFormat}; if \code{list.format} is missing, a string containing the current format is returned.
#' If \code{list.format} is supplied, it is used to define the current format, and the \emph{previous} format is returned.
#'
#' @section File formats:
#' If \code{format="json.gz"}, the list is saved to a Gzip-compressed JSON file (the default).
#' If \code{list.format="json.gz"} (default), the list is saved to a Gzip-compressed JSON file (the default).
#' This is an easily parsed format with low storage overhead.
#'
#' If \code{format="hdf5"}, \code{x} is saved into a HDF5 file instead.
#' If \code{list.format="hdf5"}, \code{x} is saved into a HDF5 file instead.
#' This format is most useful for random access and for preserving the precision of numerical data.
#'
#' @author Aaron Lun
#'
#' @seealso
#' \url{https://github.com/LTLA/uzuki2} for the specification.
#'
#' \code{\link{readBaseList}}, to read the list back into the R session.
#'
#' @examples
#' library(S4Vectors)
#' ll <- list(A=1, B=LETTERS, C=DataFrame(X=1:5))
Expand All @@ -38,6 +44,7 @@
#' saveObject,list-method
#' stageObject,list-method
#' stageObject,List-method
#' .saveBaseListFormat
#' @importFrom jsonlite toJSON
setMethod("saveObject", "list", function(x, path, list.format=saveBaseListFormat(), ...) {
dir.create(path, showWarnings=FALSE)
Expand All @@ -48,7 +55,7 @@ setMethod("saveObject", "list", function(x, path, list.format=saveBaseListFormat
env$collected <- list()
args <- list(list.format=list.format, ...)

if (!is.null(list.format) && list.format == "hdf5") {
if (list.format == "hdf5") {
fpath <- file.path(path, "list_contents.h5")
handle <- H5Fcreate(fpath, "H5F_ACC_TRUNC")
on.exit(H5Fclose(handle), add=TRUE, after=FALSE)
Expand Down Expand Up @@ -79,6 +86,24 @@ setMethod("saveObject", "List", function(x, path, list.format=saveBaseListFormat
saveObject(as.list(x), path, list.format=list.format, ...)
})

#' @export
#' @rdname saveBaseList
saveBaseListFormat <- (function() {
mode <- "json.gz"
function(list.format) {
previous <- mode
if (missing(list.format)) {
previous
} else {
if (is.null(list.format)) {
list.format <- "json.gz"
}
assign("mode", match.arg(list.format, c("json.gz", "hdf5")), envir=parent.env(environment()))
invisible(previous)
}
}
})()

##################################
########### INTERNALS ############
##################################
Expand Down Expand Up @@ -464,3 +489,6 @@ setMethod("stageObject", "list", function(x, dir, path, child=FALSE, fname="list
setMethod("stageObject", "List", function(x, dir, path, child=FALSE, fname="list") {
stageObject(as.list(x), dir, path, child=child, fname=fname)
})

#' @export
.saveBaseListFormat <- function(...) saveBaseListFormat(...)
18 changes: 3 additions & 15 deletions R/saveFormats.R
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,10 @@ format.env$DataFrame <- NULL

#' Choose the format for certain objects
#'
#' Alter the format used to save DataFrames or base lists in their respective \code{\link{stageObject}} methods.
#' Alter the format used to save DataFrames in its \code{\link{stageObject}} methods.
#'
#' @param format String containing the format to use.
#' \itemize{
#' \item For \code{saveDataFrameFormat}, this may be \code{"csv"}, \code{"csv.gz"} (default) or \code{"hdf5"}.
#' \item For \code{saveBaseListFormat}, this may be \code{"json.gz"} (default) or \code{"hdf5"}.
#' }
#' Tbe \code{"csv"}, \code{"csv.gz"} (default) or \code{"hdf5"}.
#' Alternatively \code{NULL}, to use the default format.
#'
#' @return
Expand All @@ -35,7 +32,7 @@ format.env$DataFrame <- NULL
#' .saveDataFrameFormat(old)
#'
#' @name saveFormats
#' @aliases .saveDataFrameFormat .saveBaseListFormat
#' @aliases .saveDataFrameFormat
NULL

#' @export
Expand All @@ -44,12 +41,6 @@ saveDataFrameFormat <- function(format) {
.save_format(format, "DataFrame", c("csv", "csv.gz", "hdf5"))
}

#' @export
#' @rdname saveFormats
saveBaseListFormat <- function(format) {
.save_format(format, "BaseList", c("json.gz", "hdf5"))
}

.save_format <- function(format, mode, choices) {
previous <- format.env[[mode]]
if (missing(format)) {
Expand All @@ -67,6 +58,3 @@ saveBaseListFormat <- function(format) {

#' @export
.saveDataFrameFormat <- function(...) saveDataFrameFormat(...)

#' @export
.saveBaseListFormat <- function(...) saveBaseListFormat(...)
18 changes: 14 additions & 4 deletions man/saveBaseList.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

11 changes: 2 additions & 9 deletions man/saveFormats.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 8 additions & 0 deletions tests/testthat/test-list.R
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,14 @@ test_that("lists handle complex types correctly", {
expect_identical(readBaseList(tmp2), rvals)
})

test_that("list format switch works as expected", {
expect_identical(saveBaseListFormat(), "json.gz")
expect_identical(saveBaseListFormat("hdf5"), "json.gz")
expect_identical(saveBaseListFormat(), "hdf5")
expect_identical(saveBaseListFormat(NULL), "hdf5")
expect_identical(saveBaseListFormat(), "json.gz")
})

test_that("lists work in HDF5 mode", {
old <- saveBaseListFormat("hdf5")
on.exit(saveBaseListFormat(old))
Expand Down

0 comments on commit 3bd3d67

Please sign in to comment.