[med-svn] [r-cran-fail] 06/08: New upstream version 1.3
Andreas Tille
tille at debian.org
Thu Oct 19 10:47:19 UTC 2017
This is an automated email from the git hooks/post-receive script.
tille pushed a commit to branch master
in repository r-cran-fail.
commit 737caed5e3efa8a023d070929bb58de7d772fca6
Author: Andreas Tille <tille at debian.org>
Date: Thu Oct 19 12:45:35 2017 +0200
New upstream version 1.3
---
DESCRIPTION | 17 ++++
LICENSE | 3 +
MD5 | 25 ++++++
NAMESPACE | 21 +++++
NEWS | 23 ++++++
R/backends.R | 33 ++++++++
R/cache.R | 12 +++
R/constructor.R | 56 +++++++++++++
R/fail.R | 160 +++++++++++++++++++++++++++++++++++++
R/helper.R | 82 +++++++++++++++++++
R/methods.R | 34 ++++++++
R/sail.R | 45 +++++++++++
R/worker.R | 112 ++++++++++++++++++++++++++
R/zzz.R | 16 ++++
debian/README.test | 9 ---
debian/changelog | 20 -----
debian/compat | 1 -
debian/control | 23 ------
debian/copyright | 42 ----------
debian/docs | 3 -
debian/rules | 7 --
debian/source/format | 1 -
debian/tests/control | 3 -
debian/tests/run-unit-test | 11 ---
debian/watch | 2 -
man/fail.Rd | 162 ++++++++++++++++++++++++++++++++++++++
man/sail.Rd | 46 +++++++++++
tests/test_all.R | 2 +
tests/testthat/test_apply.R | 41 ++++++++++
tests/testthat/test_as_list.R | 16 ++++
tests/testthat/test_assign.R | 15 ++++
tests/testthat/test_constructor.R | 26 ++++++
tests/testthat/test_get_put.R | 50 ++++++++++++
tests/testthat/test_mapply.R | 36 +++++++++
tests/testthat/test_remove.R | 42 ++++++++++
tests/testthat/test_sail.R | 35 ++++++++
tests/testthat/test_size.R | 16 ++++
37 files changed, 1126 insertions(+), 122 deletions(-)
diff --git a/DESCRIPTION b/DESCRIPTION
new file mode 100644
index 0000000..f6de6ba
--- /dev/null
+++ b/DESCRIPTION
@@ -0,0 +1,17 @@
+Package: fail
+Type: Package
+Title: File Abstraction Interface Layer (FAIL)
+Description: More comfortable interface to work with R data or source files
+ in a key-value fashion.
+Version: 1.3
+Author: Michel Lang <michellang at gmail.com>
+Maintainer: Michel Lang <michellang at gmail.com>
+URL: https://github.com/mllg/fail
+License: BSD_3_clause + file LICENSE
+Imports: stats, utils, BBmisc, checkmate
+Suggests: testthat
+ByteCompile: yes
+NeedsCompilation: no
+Packaged: 2015-09-30 11:01:23 UTC; lang
+Repository: CRAN
+Date/Publication: 2015-10-01 00:21:25
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..f9ed39f
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,3 @@
+YEAR: 2013
+COPYRIGHT HOLDER: Michel Lang
+ORGANIZATION: TU Dortmund University
diff --git a/MD5 b/MD5
new file mode 100644
index 0000000..43a33f1
--- /dev/null
+++ b/MD5
@@ -0,0 +1,25 @@
+969176315bdb35acf6bf596047870a1d *DESCRIPTION
+efba0fc06a435676c10b4300d35ea30d *LICENSE
+06e3be4cdd6f927ab91cd726dab4b0a7 *NAMESPACE
+2aa666d0fba1b3217c7be84ff0b100ab *NEWS
+66762b300064dc215983839f4887965a *R/backends.R
+a44c643e3af4279dd7e54bc800cec24d *R/cache.R
+93ec9d0c536a57a32be7fbe6875b8454 *R/constructor.R
+6c828a2b79de94955e22cb2ae7cebda7 *R/fail.R
+d6b11ee0756d60a73c69315f8b3605f0 *R/helper.R
+ca10178e518444cc3b0aac55c0bdc39c *R/methods.R
+6780eea1d43a369af9d6a583b17e9d2e *R/sail.R
+be6b5ed5ffb9e39e5375a45ef49a550d *R/worker.R
+3c88821a8a129662326763e752f2fb74 *R/zzz.R
+aa1cc75604c2edecefb8a5c625ac32d7 *man/fail.Rd
+217bf01b3a35435e803105e0c02dc796 *man/sail.Rd
+fed01b14cb7c5e19e8ee595aa24e4234 *tests/test_all.R
+44af3f3c31aa37644e35aac06fdcb347 *tests/testthat/test_apply.R
+71edfe2bb422057bf7a62495af0ab0dd *tests/testthat/test_as_list.R
+5e79c514e8f68dbc2ab6de3b7790583b *tests/testthat/test_assign.R
+569ed25e706189e943126b106005dca3 *tests/testthat/test_constructor.R
+e0677d5ee56f7f8ad322588a021233e0 *tests/testthat/test_get_put.R
+d4c522e256cca88d8482853245fb591a *tests/testthat/test_mapply.R
+1e311c48e2e0cf1612b4b81f776a5867 *tests/testthat/test_remove.R
+e7af3a79f6835e91ae518018889a361b *tests/testthat/test_sail.R
+21aa281c511906b38ff64763d9608603 *tests/testthat/test_size.R
diff --git a/NAMESPACE b/NAMESPACE
new file mode 100644
index 0000000..8f7aab6
--- /dev/null
+++ b/NAMESPACE
@@ -0,0 +1,21 @@
+# Generated by roxygen2 (4.1.1): do not edit by hand
+
+S3method(as.list,fail)
+S3method(as.list,sail)
+S3method(print,fail)
+S3method(print,sail)
+export(fail)
+export(sail)
+import(checkmate)
+importFrom(BBmisc,"%nin%")
+importFrom(BBmisc,argsAsNamedList)
+importFrom(BBmisc,collapse)
+importFrom(BBmisc,is.error)
+importFrom(BBmisc,names2)
+importFrom(BBmisc,setClasses)
+importFrom(BBmisc,stopf)
+importFrom(BBmisc,vlapply)
+importFrom(BBmisc,warningf)
+importFrom(stats,setNames)
+importFrom(utils,head)
+importFrom(utils,methods)
diff --git a/NEWS b/NEWS
new file mode 100644
index 0000000..e5d57c1
--- /dev/null
+++ b/NEWS
@@ -0,0 +1,23 @@
+## Version 1.3 (2015-09-30)
+* New argument "all.files" to allow working with hidden files
+* New closure "$pos" to get the n-th key
+* Added argument suppressMessages to sail
+* sail now sources files in their respective directory
+
+## Version 1.2 (2013-09-18)
+* New argument "simplify" to enforce lists to be returned
+* New object "sail" to access R source files
+* Closure "$assign" now returns keys of assigned objects
+* Closure "$clear" now returns keys of cleared objects
+
+
+## Version 1.1 (2013-02-05)
+* New closure "$assign"
+* New closure "$mapply"
+* New argument in closure "$put": keys
+* Improved error messages
+* Relaxed checks for illegal characters in keys
+
+
+## Version 1.0 (2012-12-04)
+* Initial release on CRAN
diff --git a/R/backends.R b/R/backends.R
new file mode 100644
index 0000000..e4a7e05
--- /dev/null
+++ b/R/backends.R
@@ -0,0 +1,33 @@
+loadRData = function(.self, fn) {
+ ee = new.env(parent = emptyenv(), hash = FALSE)
+ ns = load(fn, envir = ee)
+ if (.self$simplify && length(ns) == 1L)
+ return(ee[[ns]])
+ return(as.list(ee))
+}
+
+saveRData = function(.self, fn, key, value) {
+ ee = new.env(parent = emptyenv(), hash = FALSE)
+ assign(key, value, envir = ee)
+ save(list = key, envir = ee, file = fn)
+ return(invisible(key))
+}
+
+loadR = function(.self, fn) {
+ ee = new.env(parent = .GlobalEnv)
+ wrap = if (.self$suppressMessages)
+ function(expr) suppressMessages(suppressPackageStartupMessages(expr))
+ else
+ identity
+ wrap(sys.source(fn, ee, chdir = TRUE))
+ ns = ls(ee, all.names = TRUE)
+ if (.self$simplify && length(ns) == 1L)
+ return(ee[[ns]])
+ return(as.list(ee))
+}
+
+saveR = function(.self, fn, key, value) {
+ ee = new.env(parent = emptyenv(), hash = FALSE)
+ assign(key, value, envir = ee)
+ dump(key, file = fn, envir = ee)
+}
diff --git a/R/cache.R b/R/cache.R
new file mode 100644
index 0000000..1c92913
--- /dev/null
+++ b/R/cache.R
@@ -0,0 +1,12 @@
+Cache = function() {
+ ee = new.env(parent = emptyenv())
+ keys = function() ls(ee, all.names = TRUE)
+
+ list(
+ keys = keys,
+ get = function(key) get(key, envir = ee),
+ put = function(key, value) assign(key, value, envir = ee),
+ rm = function(keys) { x = intersect(keys, keys()); rm(list = x, envir = ee); x },
+ exists = function(key) exists(key, envir = ee)
+ )
+}
diff --git a/R/constructor.R b/R/constructor.R
new file mode 100644
index 0000000..0d634a9
--- /dev/null
+++ b/R/constructor.R
@@ -0,0 +1,56 @@
+makeObject = function(.self) {
+ force(.self)
+ list(
+ ls = function(pattern = NULL) {
+ Ls(.self, pattern)
+ },
+ get = function(key, simplify, use.cache) {
+ Get(.self, asKeys(.self, key, len = 1L),
+ use.cache = asFlag(use.cache, default = .self$use.cache))
+ },
+ pos = function(n = 1L, use.cache) {
+ keys = Ls(.self)
+ if (n > length(keys))
+ return(NULL)
+ Get(.self, keys[n], use.cache = asFlag(use.cache, default = .self$use.cache))
+ },
+ put = function(..., keys, li = list(), use.cache) {
+ Put(.self, ..., keys = keys, li = as.list(li),
+ use.cache = asFlag(use.cache, default = .self$use.cache))
+ },
+ remove = function(keys) {
+ Remove(.self, asKeys(.self, keys))
+ },
+ as.list = function(keys, use.cache) {
+ AsList(.self, asKeys(.self, keys, default = Ls(.self)),
+ use.cache = asFlag(use.cache, default = .self$use.cache))
+ },
+ apply = function(FUN, ..., keys, use.cache, simplify = FALSE, use.names = TRUE) {
+ Apply(.self, FUN, ..., keys = asKeys(.self, keys, default = Ls(.self)),
+ use.cache = asFlag(use.cache, default = .self$use.cache),
+ simplify = asFlag(simplify), use.names = asFlag(use.names))
+ },
+ mapply = function(FUN, ..., keys, use.cache, moreArgs = NULL, simplify = FALSE, use.names = TRUE) {
+ Mapply(.self, FUN, ..., keys = asKeys(.self, keys, default = Ls(.self)),
+ use.cache = asFlag(use.cache, default = .self$use.cache),
+ moreArgs = as.list(moreArgs), simplify = asFlag(simplify), use.names = asFlag(use.names))
+ },
+ assign = function(keys, envir = parent.frame(), use.cache) {
+ Assign(.self, keys = asKeys(.self, keys, default = Ls(.self)), envir = as.environment(envir),
+ use.cache = asFlag(use.cache, default = .self$use.cache))
+ },
+ size = function(keys, unit = "b") {
+ match.arg(unit, choices = names(UNITCONVERT))
+ Size(.self, asKeys(.self, keys, default = Ls(.self)), unit = unit)
+ },
+ clear = function(keys) {
+ Clear(.self, asKeys(.self, keys, default = Ls(.self)))
+ },
+ cached = function() {
+ Cached(.self)
+ },
+ info = function() {
+ Info(.self)
+ }
+ )
+}
diff --git a/R/fail.R b/R/fail.R
new file mode 100644
index 0000000..bceb2b3
--- /dev/null
+++ b/R/fail.R
@@ -0,0 +1,160 @@
+#' Create a file abstraction interface layer (FAIL) object.
+#'
+#' The general idea is to not bother about file path joining or file extensions.
+#' Instead, FAIL offers a key-value like interface to RData files in a specified directory.
+#' The filename (without extension) acts as the key while the stored R objects are the values.
+#' Fail provides an interface to the basic file system actions: listing, reading / loading,
+#' writing / saving, removing and applying functions on files.
+#' An implemented cache mechanism can be used to avoid repeated disk reads.
+#'
+#' @param path [\code{character(1)}]\cr
+#' Path to work in, will be created if it does not exists.
+#' @param extension [\code{character(1)}]\cr
+#' File extension to work with.
+#' Default is \dQuote{RData}.
+#' @param all.files [\code{logical(1)}]\cr
+#' Also include hidden files, i.e. files whose name start with a dot (\dQuote{.}).
+#' Default is \code{FALSE}.
+#' @param use.cache [\code{logical(1)}]\cr
+#' Use a memory cache per global default.
+#' Global option which can locally be overwritten in most functions.
+#' Default is \code{FALSE}
+#' @param simplify [\code{character(1)}]\cr
+#' If only one object is stored in a R data file,
+#' should the return value be simplified?
+#' If set to \code{TRUE},
+#' instead of a list containing one element the object itself will be returned.
+#' @return Object of class \code{fail}. See details.
+#' @details
+#' For a quick introduction on the usage, see \url{https://github.com/mllg/fail}.
+#'
+#' An object with the following functions is returned by \code{fail}:
+#' \describe{
+#' \item{\code{ls(pattern=NULL)}}{
+#' Function to list keys in directory \code{path} matching a regular expression pattern \code{pattern}.
+#' Returns a character vector of keys.
+#' }
+#' \item{\code{get(key, use.cache)}}{
+#' Function to load a file identified by \code{key} from directory \code{path}.
+#' To load many objects at once, use \code{as.list}, \code{assign} or \code{get} together with \code{\link[base]{lapply}}.
+#' Argument \code{use.cache} can be set to temporarily overwrite the global \code{use.cache} flag.
+#' }
+#' \item{\code{put(..., li, keys, use.cache)}}{
+#' Function to save objects to directory \code{path}.
+#' Names for objects provided via \code{...} will be looked up or can be provided using a \code{key = value} syntax.
+#' More objects can be passed as a named list using the argument \code{li}: Each list item will be saved to a separate file.
+#' If you provide \code{keys} as a character vector, these names will be taken for the arguments passed via \code{...}.
+#' Argument \code{use.cache} temporarily overwrites the global \code{use.cache} flag.
+#' Returns a character vector of stored keys.
+#' }
+#' \item{\code{remove(keys)}}{
+#' Function to remove files identified by \code{keys} from directory \code{path}.
+#' Returns a character vector of deleted keys.
+#' }
+#' \item{\code{apply(FUN, ..., keys, use.cache, simplify=FALSE, use.names=TRUE)}}{
+#' Apply function \code{FUN} on files identified by \code{keys}.
+#' \code{keys} defaults to all keys available and will be used to name the returned list.
+#' The loaded R objects will be past unnamed as first argument.
+#' Use \code{...} for additional function arguments.
+#' Argument \code{use.cache} can be set to temporarily overwrite the global \code{use.cache} flag.
+#' For arguments \code{simplify} and \code{use.names}, see \code{\link[base]{lapply}}.
+#' }
+#' \item{\code{mapply(FUN, ..., keys, use.cache, moreArgs = NULL, simplify=FALSE, use.names=TRUE)}}{
+#' Apply function \code{FUN} on files identified by \code{keys}.
+#' \code{keys} defaults to all keys available and will be used to name the returned list.
+#' The function \code{FUN} must have the formal arguments \dQuote{key} and \dQuote{value}.
+#' Both key and value will be passed named.
+#' Use \code{...} and/or \code{moreArgs} for additional function arguments.
+#' Argument \code{use.cache} can be set to temporarily overwrite the global \code{use.cache} flag.
+#' For arguments \code{moreArgs}, \code{simplify} and \code{use.names}, see \code{\link[base]{mapply}}.
+#' }
+#' \item{\code{as.list(keys, use.cache)}}{
+#' Return a named list of objects identified by \code{keys}. \code{keys} defaults to all keys available.
+#' Argument \code{use.cache} can be set to temporarily overwrite the global \code{use.cache} flag.
+#' }
+#' \item{\code{assign(keys, envir=parent.frame(), use.cache)}}{
+#' Assigns all objects identified by the character vector \code{keys} in the environment \code{envir}.
+#' Argument \code{use.cache} can be set to temporarily overwrite the global \code{use.cache} flag.
+#' Returns a character vector of assigned keys.
+#' }
+#' \item{\code{clear(keys)}}{
+#' Clear the cache to free memory. \code{keys} defaults to all keys available.
+#' Returns a character vector of cleared keys.
+#' }
+#' \item{\code{cached()}}{
+#' Returns a character vector of keys of cached objects.
+#' }
+#' \item{\code{size(keys, unit="b")}}{
+#' Get the file size in Bytes of the files identified by \code{keys}. \code{keys} defaults to all keys available.
+#' Argument \code{unit} accepts \dQuote{b}, \dQuote{Kb}, \dQuote{Mb} and \dQuote{Gb} and can be used to convert Bytes to KiloBytes, MegaBytes or GigaBytes, respectively.
+#' }
+#' \item{\code{info()}}{
+#' Returns a named list with \code{path}, \code{extension} and \code{use.cache}.
+#' Internally used for the \code{\link[base]{print}} method with a much nicer summary of the FAIL object.
+#' }
+#' }
+#' Furthermore, the package provides S3 methods for \code{\link[base]{print}} and \code{\link[base]{as.list}}.
+#'
+#' Be aware of the following restriction regarding file names and keys:
+#' The package performs some basic checks for illegal characters on the key names.
+#' In principle all characters matching the pattern \dQuote{[a-zA-Z0-9._-]} are allowed and should work on most or all file systems.
+#' But be careful with key names which are not compatible with R's variable naming restrictions, e.g. using the minus character or
+#' key names starting with a number: these provoke unwanted side effects and will result in errors if used with \code{assign}.
+#'
+#' If two files would collide on case-insensitive file systems like Windows' NTFS, the package will throw warnings. Best practice
+#' is to not rely on case sensitivity.
+#'
+#' @export
+#' @examples
+#' # initialize a FAIL in a temporary directory
+#' path <- tempfile("")
+#' files <- fail(path)
+#'
+#' # save x and y, vectors of random numbers
+#' x <- runif(100)
+#' files$put(x, y = runif(100))
+#'
+#' # save columns of the iris data set as separate files
+#' files$put(li = as.list(iris))
+#'
+#' # load all RData files in a named list as a one-liner
+#' as.list(fail(path))
+#'
+#' # load a single object from the file system
+#' files$get("Species")
+#' files$as.list(c("x", "y"))
+#'
+#' # remove an object (and related file)
+#' files$remove("Species")
+#'
+#' # apply a function over files
+#' files$apply(mean)
+#' files$mapply(function(key, value) sprintf("%s -> %f", key, mean(value)), simplify = TRUE)
+#'
+#' # show file size informations
+#' files$size(unit = "Mb")
+#'
+#' # get an object and cache it
+#' files$get("x", use.cache = TRUE)
+#' files$cached()
+#' files$clear()
+#' files$cached()
+#'
+#' # assign variables in the current environment
+#' files$assign("y")
+#' mean(y)
+fail = function(path = getwd(), extension = "RData", all.files = FALSE, use.cache = FALSE, simplify = TRUE) {
+ ### argument checks
+ .self = list(
+ path = checkPath(path),
+ extension = checkExtension(extension),
+ all.files = asFlag(all.files),
+ use.cache = asFlag(use.cache),
+ simplify = asFlag(simplify, na.ok = TRUE),
+ cache = Cache(),
+ loadFun = loadRData,
+ saveFun = saveRData
+ )
+ checkCollision(Ls(.self))
+ setClasses(makeObject(.self), "fail")
+}
diff --git a/R/helper.R b/R/helper.R
new file mode 100644
index 0000000..4826197
--- /dev/null
+++ b/R/helper.R
@@ -0,0 +1,82 @@
+asFlag = function(x, default, na.ok = FALSE) {
+ if (missing(x)) {
+ if (!missing(default))
+ return(default)
+ stopf("Argument %s is missing", deparse(substitute(x)))
+ }
+ assertFlag(x, na.ok = na.ok, .var.name = deparse(substitute(x)))
+ x
+}
+
+asKeys = function(.self, keys, len, default) {
+ if (missing(keys)) {
+ if (!missing(default))
+ return(default)
+ stop("Keys are missing")
+ }
+
+ if (!is.character(keys)) {
+ keys = try(as.character(keys))
+ if (is.error(keys))
+ stop("Keys must be of type character or be convertible to character")
+ }
+
+ if (!missing(len) && length(keys) != len)
+ stop("Keys must have length ", len)
+ if (anyMissing(keys))
+ stop("Keys contain NAs")
+
+ # R variable pattern: "^((\\.[[:alpha:]._]+)|([[:alpha:]]+))[[:alnum:]_.]*$"
+ pattern = "^[[:alnum:]._-]+$"
+ ok = grepl(pattern, keys)
+ if (!all(ok))
+ stopf("Key '%s' in illegal format, see help", head(keys[!ok], 1L))
+ if (!.self$all.files && any(substr(keys, 1L, 1L) == "."))
+ stop("Cannot work with hidden files (files starting with a dot) if 'all.files' is set to TRUE.")
+
+ return(keys)
+}
+
+checkPath = function(path) {
+ qassert(path, "S1")
+ if (!file.exists(path) && !dir.create(path, recursive = TRUE))
+ stopf("Could not create directory '%s'", path)
+ assertDirectory(path, access = "r")
+ path
+}
+
+checkExtension = function(extension) {
+ qassert(extension, "S1")
+ if (grepl("[^[:alnum:]]", extension))
+ stop("Extension contains illegal characters: ",
+ collapse(strsplit(gsub("[[:alnum:]]", "", extension), ""), " "))
+ return(extension)
+}
+
+checkCollision = function(keys) {
+ dups = duplicated(tolower(keys))
+ if (any(dups)) {
+ warningf("The following keys result in colliding files on case insensitive file systems: %s",
+ collapse(keys[dups]))
+ }
+ invisible(TRUE)
+}
+
+checkCollisionNew = function(new, old) {
+ dups = new %nin% old & tolower(new) %in% tolower(old)
+ if (any(dups))
+ warningf("Keys collide on case insensitive file systems: %s", collapse(new[dups]))
+ invisible(TRUE)
+}
+
+fn2key = function(.self, fn) {
+ return(sub(sprintf("\\.%s$", .self$extension), "", fn))
+}
+
+key2fn = function(.self, key) {
+ return(file.path(.self$path, sprintf("%s.%s", key, .self$extension)))
+}
+
+nkeys = function(.self) {
+ length(list.files(.self$path, pattern = sprintf("\\.%s$", .self$extension), ignore.case = TRUE, all.files = .self$all.files))
+}
diff --git a/R/methods.R b/R/methods.R
new file mode 100644
index 0000000..12b934c
--- /dev/null
+++ b/R/methods.R
@@ -0,0 +1,34 @@
+printObject = function(x, type) {
+ info = x$info()
+ cat(
+ sprintf("%s on path %s", type, info$path),
+ sprintf(" %-9s : %s", "extension", info$extension),
+ sprintf(" %-9s : %s", "use.cache", info$use.cache),
+ sprintf(" %-9s : %s", "simplify", info$simplify),
+ sprintf(" %-9s : %i", "items", length(x$ls())),
+ sprintf(" %-9s : %i", "cached", length(x$cached())),
+ sprintf(" %-9s : %s", "functions", collapse(names(x))),
+ sprintf(" %-9s : %s", "methods", collapse(sub("\\.fail$", "", methods(class = "fail")), ", ")),
+ sep = "\n"
+ )
+}
+
+#' @export
+print.fail = function(x, ...) {
+ printObject(x, "File Abstraction Interface Layer")
+}
+
+#' @export
+print.sail = function(x, ...) {
+ printObject(x, "Source Abstraction Interface Layer")
+}
+
+#' @export
+as.list.fail = function(x, ...) {
+ x$as.list(...)
+}
+
+#' @export
+as.list.sail = function(x, ...) {
+ x$as.list(...)
+}
diff --git a/R/sail.R b/R/sail.R
new file mode 100644
index 0000000..3aa00dd
--- /dev/null
+++ b/R/sail.R
@@ -0,0 +1,45 @@
+#' Create a source abstraction interface layer (SAIL) object.
+#'
+#' This function returns an object of class \code{sail} which behaves
+#' like \code{\link{fail}}, but is indented for loading and saving
+#' R source code files.
+#'
+#' @param path [\code{character(1)}]\cr
+#' Path to work in, will be created if it does not exists.
+#' @param extension [\code{character(1)}]\cr
+#' File extension to work with.
+#' Default is \dQuote{R}.
+#' @param all.files [\code{logical(1)}]\cr
+#' Also include hidden files, i.e. files whose name start with a dot (\dQuote{.}).
+#' Default is \code{FALSE}.
+#' @param use.cache [\code{logical(1)}]\cr
+#' Use a memory cache per global default.
+#' Global option which can locally be overwritten in most functions.
+#' Default is \code{FALSE}
+#' @param simplify [\code{character(1)}]\cr
+#' If only one object is defined in a sourced R file,
+#' should the return value be simplified? If set to \code{TRUE},
+#' instead of a list containing one element the object itself will be returned.
+#' @param suppressMessages [\code{logical(1)}]\cr
+#' Wrap the \code{\link[base]{sys.source}} command into \code{\link[base]{suppressMessages}}
+#' and \code{link[base]{suppressPackageStartupMessages}}?
+#' Default is \code{FALSE}, i.e. you will see regular output of sourced scripts.
+#' @return Object of class \code{sail}. See the documentation of \code{\link{fail}}
+#' for details.
+#' @export
+sail = function(path = getwd(), extension = "R", all.files = FALSE, use.cache = FALSE, simplify = TRUE,
+ suppressMessages = FALSE) {
+ .self = list(
+ path = checkPath(path),
+ extension = checkExtension(extension),
+ all.files = asFlag(all.files),
+ use.cache = asFlag(use.cache),
+ simplify = asFlag(simplify, na.ok = TRUE),
+ cache = Cache(),
+ loadFun = loadR,
+ saveFun = saveR,
+ suppressMessages = asFlag(suppressMessages)
+ )
+ checkCollision(Ls(.self))
+ setClasses(makeObject(.self), "sail")
+}
diff --git a/R/worker.R b/R/worker.R
new file mode 100644
index 0000000..8b0127a
--- /dev/null
+++ b/R/worker.R
@@ -0,0 +1,112 @@
+Ls = function(.self, pattern = NULL) {
+ keys = fn2key(.self, list.files(.self$path, pattern = sprintf("\\.%s$", .self$extension), ignore.case = TRUE, all.files = .self$all.files))
+ if (!is.null(pattern))
+ keys = keys[grepl(pattern, keys)]
+ return(keys)
+}
+
+Get = function(.self, key, use.cache) {
+ fn = key2fn(.self, key)
+ if (!file.exists(fn))
+ stopf("File for key '%s' (%s) not found", key, fn)
+
+ if (use.cache) {
+ if (!.self$cache$exists(key))
+ .self$cache$put(key, .self$loadFun(.self, fn))
+ return(.self$cache$get(key))
+ }
+ return(.self$loadFun(.self, fn))
+}
+
+Put = function(.self, ..., keys, li, use.cache) {
+ args = argsAsNamedList(...)
+ if (missing(keys))
+ keys = names2(args)
+ keys = c(asKeys(.self, keys, len = length(args)), asKeys(.self, names2(li)))
+ args = c(args, as.list(li))
+
+ if (anyMissing(keys))
+ stop("Could not determine all key names from input")
+ if (anyDuplicated(keys))
+ stop("Duplicated key names")
+
+ checkCollisionNew(keys, Ls(.self))
+
+ if (use.cache)
+ mapply(.self$cache$put, key = keys, value = args,
+ USE.NAMES = FALSE, SIMPLIFY = FALSE)
+ else
+ .self$cache$rm(keys)
+
+ mapply(.self$saveFun, fn = key2fn(.self, keys), key = keys, value = args,
+ MoreArgs = list(.self = .self), USE.NAMES = FALSE, SIMPLIFY = FALSE)
+ invisible(keys)
+}
+
+Remove = function(.self, keys) {
+ w = function(key) {
+ .self$cache$rm(key)
+ fn = key2fn(.self, key)
+ return(file.exists(fn) && file.remove(fn))
+ }
+ ok = vlapply(keys, w)
+ if (!all(ok))
+ warningf("Files not removed: %s", collapse(keys[!ok]))
+ return(invisible(ok))
+}
+
+Apply = function(.self, FUN, ..., keys, use.cache, simplify, use.names) {
+ wrapper = function(.key, ...) {
+ res = try(FUN(Get(.self, .key, use.cache = use.cache), ...), silent = TRUE)
+ if (is.error(res))
+ stopf("Error applying function on key '%s': %s", .key, as.character(res))
+ return(res)
+ }
+
+ FUN = match.fun(FUN)
+ return(sapply(keys, wrapper, ..., USE.NAMES = use.names, simplify = simplify))
+}
+
+Mapply = function(.self, FUN, ..., keys, use.cache, moreArgs, simplify, use.names) {
+ wrapper = function(.key, ...) {
+ res = try(FUN(key = .key, value = Get(.self, .key, use.cache = use.cache), ...), silent = TRUE)
+ if (is.error(res))
+ stopf("Error applying function on key '%s': %s", .key, as.character(res))
+ return(res)
+ }
+ assertFunction(FUN, args = c("key", "value"))
+ return(mapply(wrapper, .key = keys, ..., MoreArgs = moreArgs, USE.NAMES = use.names, SIMPLIFY = simplify))
+}
+
+Assign = function(.self, keys, envir, use.cache) {
+ w = function(key, envir) {
+ x = Get(.self, key, use.cache)
+ if (.self$simplify)
+ assign(key, x, envir = envir)
+ else
+ mapply(assign, names(x), x, MoreArgs = list(envir = envir), SIMPLIFY = FALSE, USE.NAMES = FALSE)
+ }
+ lapply(keys, w, envir = envir)
+ return(invisible(keys))
+}
+
+Size = function(.self, keys, unit = "b") {
+ size = as.integer(file.info(key2fn(.self, keys))$size)
+ setNames(size / UNITCONVERT[unit], keys)
+}
+
+Clear = function(.self, keys) {
+ return(invisible(.self$cache$rm(keys)))
+}
+
+Cached = function(.self) {
+ return(.self$cache$keys())
+}
+
+AsList = function(.self, keys, use.cache) {
+ setNames(lapply(keys, Get, .self = .self, use.cache = use.cache), keys)
+}
+
+Info = function(.self) {
+ return(.self[c("path", "extension", "use.cache", "simplify")])
+}
diff --git a/R/zzz.R b/R/zzz.R
new file mode 100644
index 0000000..4a3bdc2
--- /dev/null
+++ b/R/zzz.R
@@ -0,0 +1,16 @@
+#' @import checkmate
+#' @importFrom stats setNames
+#' @importFrom utils head
+#' @importFrom utils methods
+#' @importFrom BBmisc stopf
+#' @importFrom BBmisc warningf
+#' @importFrom BBmisc collapse
+#' @importFrom BBmisc %nin%
+#' @importFrom BBmisc is.error
+#' @importFrom BBmisc setClasses
+#' @importFrom BBmisc names2
+#' @importFrom BBmisc argsAsNamedList
+#' @importFrom BBmisc vlapply
+
+UNITCONVERT = c(1L, 1024L, 1048576L, 1073741824L)
+names(UNITCONVERT) = c("b", "kB", "Mb", "Gb")
diff --git a/debian/README.test b/debian/README.test
deleted file mode 100644
index c850edd..0000000
--- a/debian/README.test
+++ /dev/null
@@ -1,9 +0,0 @@
-Notes on how this package can be tested.
-────────────────────────────────────────
-
-This package can be tested by running the provided test:
-
-cd tests
-LC_ALL=C R --no-save < test_all.R
-
-in order to confirm its integrity.
diff --git a/debian/changelog b/debian/changelog
deleted file mode 100644
index f9900e6..0000000
--- a/debian/changelog
+++ /dev/null
@@ -1,20 +0,0 @@
-r-cran-fail (1.3-2) UNRELEASED; urgency=medium
-
- * cme fix dpkg-control
- * Fix Vcs-Browser
-
- -- Andreas Tille <tille at debian.org> Mon, 02 Jan 2017 15:52:50 +0100
-
-r-cran-fail (1.3-1) unstable; urgency=medium
-
- * New upstream version
- * cme fix dpkg-control
- * Fix DEP5
-
- -- Andreas Tille <tille at debian.org> Sat, 31 Oct 2015 08:24:46 +0100
-
-r-cran-fail (1.2-1) unstable; urgency=low
-
- * Initial release (Closes: #752144)
-
- -- Andreas Tille <tille at debian.org> Fri, 13 Jun 2014 22:52:06 +0200
diff --git a/debian/compat b/debian/compat
deleted file mode 100644
index ec63514..0000000
--- a/debian/compat
+++ /dev/null
@@ -1 +0,0 @@
-9
diff --git a/debian/control b/debian/control
deleted file mode 100644
index bb35a5a..0000000
--- a/debian/control
+++ /dev/null
@@ -1,23 +0,0 @@
-Source: r-cran-fail
-Maintainer: Debian Med Packaging Team <debian-med-packaging at lists.alioth.debian.org>
-Uploaders: Andreas Tille <tille at debian.org>
-Section: gnu-r
-Priority: optional
-Build-Depends: debhelper (>= 9),
- cdbs,
- r-base-dev (>= 3.0.0),
- r-cran-bbmisc
-Standards-Version: 3.9.8
-Vcs-Browser: https://anonscm.debian.org/viewvc/debian-med/trunk/packages/R/r-cran-fail/trunk/
-Vcs-Svn: svn://anonscm.debian.org/debian-med/trunk/packages/R/r-cran-fail/trunk/
-Homepage: http://cran.r-project.org/web/packages/fail/
-
-Package: r-cran-fail
-Architecture: any
-Depends: ${shlibs:Depends},
- ${R:Depends},
- r-cran-bbmisc
-Description: GNU R File Abstraction Interface Layer (FAIL) mimicking a key-value store
- This package provides a File Abstraction Interface Layer (FAIL)
- mimicking a key-value store. It is a more comfortable interface to work
- with a directory of R data or source files.
diff --git a/debian/copyright b/debian/copyright
deleted file mode 100644
index 5272d38..0000000
--- a/debian/copyright
+++ /dev/null
@@ -1,42 +0,0 @@
-Format: http://www.debian.org/doc/packaging-manuals/copyright-format/1.0/
-Upstream-Name: BatchJobs
-Upstream-Contact: Michel Lang <michellang at gmail.com>
-Source: http://cran.r-project.org/web/packages/fail/
-
-Files: *
-Copyright: 2012-2014 Michel Lang <michellang at gmail.com>
-License: BSD-3-clause
-
-Files: debian/*
-Copyright: 2014 Andreas Tille <tille at debian.org>
-License: BSD-3-clause
-
-License: BSD-3-clause
- Redistribution and use in source and binary forms, with or without
- modification, are permitted provided that the following conditions are
- met:
- .
- Redistributions of source code must retain the above copyright
- notice, this list of conditions and the following disclaimer.
- .
- Redistributions in binary form must reproduce the above copyright
- notice, this list of conditions and the following disclaimer in
- the documentation and/or other materials provided with the
- distribution.
- .
- Neither the name of the <ORGANIZATION> nor the names of its
- contributors may be used to endorse or promote products derived
- from this software without specific prior written permission.
- .
- THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
- LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
- A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
- HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
- OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-
diff --git a/debian/docs b/debian/docs
deleted file mode 100644
index 960011c..0000000
--- a/debian/docs
+++ /dev/null
@@ -1,3 +0,0 @@
-tests
-debian/README.test
-debian/tests/run-unit-test
diff --git a/debian/rules b/debian/rules
deleted file mode 100755
index 9c63da8..0000000
--- a/debian/rules
+++ /dev/null
@@ -1,7 +0,0 @@
-#!/usr/bin/make -f
-# -*- makefile -*-
-
-include /usr/share/R/debian/r-cran.mk
-
-install/$(package)::
- rm -rf debian/$(package)/usr/lib/R/site-library/$(cranName)/LICENSE
diff --git a/debian/source/format b/debian/source/format
deleted file mode 100644
index 163aaf8..0000000
--- a/debian/source/format
+++ /dev/null
@@ -1 +0,0 @@
-3.0 (quilt)
diff --git a/debian/tests/control b/debian/tests/control
deleted file mode 100644
index b044b0c..0000000
--- a/debian/tests/control
+++ /dev/null
@@ -1,3 +0,0 @@
-Tests: run-unit-test
-Depends: @, r-cran-testthat
-Restrictions: allow-stderr
diff --git a/debian/tests/run-unit-test b/debian/tests/run-unit-test
deleted file mode 100644
index 17b3dc9..0000000
--- a/debian/tests/run-unit-test
+++ /dev/null
@@ -1,11 +0,0 @@
-#!/bin/sh -e
-
-pkg=r-cran-fail
-if [ "$ADTTMP" = "" ] ; then
- ADTTMP=`mktemp -d /tmp/${pkg}-test.XXXXXX`
-fi
-cd $ADTTMP
-cp -a /usr/share/doc/${pkg}/tests/* $ADTTMP
-gunzip -r *
-LC_ALL=C R --no-save < test_all.R
-rm -fr $ADTTMP/*
diff --git a/debian/watch b/debian/watch
deleted file mode 100644
index de966ff..0000000
--- a/debian/watch
+++ /dev/null
@@ -1,2 +0,0 @@
-version=3
-http://cran.r-project.org/src/contrib/fail_([-\d.]*)\.tar\.gz
diff --git a/man/fail.Rd b/man/fail.Rd
new file mode 100644
index 0000000..6fb7ea4
--- /dev/null
+++ b/man/fail.Rd
@@ -0,0 +1,162 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/fail.R
+\name{fail}
+\alias{fail}
+\title{Create a file abstraction interface layer (FAIL) object.}
+\usage{
+fail(path = getwd(), extension = "RData", all.files = FALSE,
+ use.cache = FALSE, simplify = TRUE)
+}
+\arguments{
+\item{path}{[\code{character(1)}]\cr
+Path to work in, will be created if it does not exists.}
+
+\item{extension}{[\code{character(1)}]\cr
+File extension to work with.
+Default is \dQuote{RData}.}
+
+\item{all.files}{[\code{logical(1)}]\cr
+Also include hidden files, i.e. files whose name start with a dot (\dQuote{.}).
+Default is \code{FALSE}.}
+
+\item{use.cache}{[\code{logical(1)}]\cr
+Use a memory cache per global default.
+Global option which can locally be overwritten in most functions.
+Default is \code{FALSE}}
+
+\item{simplify}{[\code{character(1)}]\cr
+If only one object is stored in a R data file,
+should the return value be simplified?
+If set to \code{TRUE},
+instead of a list containing one element the object itself will be returned.}
+}
+\value{
+Object of class \code{fail}. See details.
+}
+\description{
+The general idea is to not bother about file path joining or file extensions.
+Instead, FAIL offers a key-value like interface to RData files in a specified directory.
+The filename (without extension) acts as the key while the stored R objects are the values.
+Fail provides an interface to the basic file system actions: listing, reading / loading,
+writing / saving, removing and applying functions on files.
+An implemented cache mechanism can be used to avoid repeated disk reads.
+}
+\details{
+For a quick introduction on the usage, see \url{https://github.com/mllg/fail}.
+
+ An object with the following functions is returned by \code{fail}:
+ \describe{
+ \item{\code{ls(pattern=NULL)}}{
+ Function to list keys in directory \code{path} matching a regular expression pattern \code{pattern}.
+ Returns a character vector of keys.
+ }
+ \item{\code{get(key, use.cache)}}{
+ Function to load a file identified by \code{key} from directory \code{path}.
+ To load many objects at once, use \code{as.list}, \code{assign} or \code{get} together with \code{\link[base]{lapply}}.
+ Argument \code{use.cache} can be set to temporarily overwrite the global \code{use.cache} flag.
+ }
+ \item{\code{put(..., li, keys, use.cache)}}{
+ Function to save objects to directory \code{path}.
+ Names for objects provided via \code{...} will be looked up or can be provided using a \code{key = value} syntax.
+ More objects can be passed as a named list using the argument \code{li}: Each list item will be saved to a separate file.
+ If you provide \code{keys} as a character vector, these names will be taken for the arguments passed via \code{...}.
+ Argument \code{use.cache} temporarily overwrites the global \code{use.cache} flag.
+ Returns a character vector of stored keys.
+ }
+ \item{\code{remove(keys)}}{
+ Function to remove files identified by \code{keys} from directory \code{path}.
+ Returns a character vector of deleted keys.
+ }
+ \item{\code{apply(FUN, ..., keys, use.cache, simplify=FALSE, use.names=TRUE)}}{
+ Apply function \code{FUN} on files identified by \code{keys}.
+ \code{keys} defaults to all keys available and will be used to name the returned list.
+ The loaded R objects will be past unnamed as first argument.
+ Use \code{...} for additional function arguments.
+ Argument \code{use.cache} can be set to temporarily overwrite the global \code{use.cache} flag.
+ For arguments \code{simplify} and \code{use.names}, see \code{\link[base]{lapply}}.
+ }
+ \item{\code{mapply(FUN, ..., keys, use.cache, moreArgs = NULL, simplify=FALSE, use.names=TRUE)}}{
+ Apply function \code{FUN} on files identified by \code{keys}.
+ \code{keys} defaults to all keys available and will be used to name the returned list.
+ The function \code{FUN} must have the formal arguments \dQuote{key} and \dQuote{value}.
+ Both key and value will be passed named.
+ Use \code{...} and/or \code{moreArgs} for additional function arguments.
+ Argument \code{use.cache} can be set to temporarily overwrite the global \code{use.cache} flag.
+ For arguments \code{moreArgs}, \code{simplify} and \code{use.names}, see \code{\link[base]{mapply}}.
+ }
+ \item{\code{as.list(keys, use.cache)}}{
+ Return a named list of objects identified by \code{keys}. \code{keys} defaults to all keys available.
+ Argument \code{use.cache} can be set to temporarily overwrite the global \code{use.cache} flag.
+ }
+ \item{\code{assign(keys, envir=parent.frame(), use.cache)}}{
+ Assigns all objects identified by the character vector \code{keys} in the environment \code{envir}.
+ Argument \code{use.cache} can be set to temporarily overwrite the global \code{use.cache} flag.
+ Returns a character vector of assigned keys.
+ }
+ \item{\code{clear(keys)}}{
+ Clear the cache to free memory. \code{keys} defaults to all keys available.
+ Returns a character vector of cleared keys.
+ }
+ \item{\code{cached()}}{
+ Returns a character vector of keys of cached objects.
+ }
+ \item{\code{size(keys, unit="b")}}{
+ Get the file size in Bytes of the files identified by \code{keys}. \code{keys} defaults to all keys available.
+ Argument \code{unit} accepts \dQuote{b}, \dQuote{Kb}, \dQuote{Mb} and \dQuote{Gb} and can be used to convert Bytes to KiloBytes, MegaBytes or GigaBytes, respectively.
+ }
+ \item{\code{info()}}{
+ Returns a named list with \code{path}, \code{extension} and \code{use.cache}.
+ Internally used for the \code{\link[base]{print}} method with a much nicer summary of the FAIL object.
+ }
+ }
+ Furthermore, the package provides S3 methods for \code{\link[base]{print}} and \code{\link[base]{as.list}}.
+
+ Be aware of the following restriction regarding file names and keys:
+ The package performs some basic checks for illegal characters on the key names.
+ In principle all characters matching the pattern \dQuote{[a-zA-Z0-9._-]} are allowed and should work on most or all file systems.
+ But be careful with key names which are not compatible with R's variable naming restrictions, e.g. using the minus character or
+ key names starting with a number: these provoke unwanted side effects and will result in errors if used with \code{assign}.
+
+ If two files would collide on case-insensitive file systems like Windows' NTFS, the package will throw warnings. Best practice
+ is to not rely on case sensitivity.
+}
+\examples{
+# initialize a FAIL in a temporary directory
+path <- tempfile("")
+files <- fail(path)
+
+# save x and y, vectors of random numbers
+x <- runif(100)
+files$put(x, y = runif(100))
+
+# save columns of the iris data set as separate files
+files$put(li = as.list(iris))
+
+# load all RData files in a named list as a one-liner
+as.list(fail(path))
+
+# load a single object from the file system
+files$get("Species")
+files$as.list(c("x", "y"))
+
+# remove an object (and related file)
+files$remove("Species")
+
+# apply a function over files
+files$apply(mean)
+files$mapply(function(key, value) sprintf("\%s -> \%f", key, mean(value)), simplify = TRUE)
+
+# show file size informations
+files$size(unit = "Mb")
+
+# get an object and cache it
+files$get("x", use.cache = TRUE)
+files$cached()
+files$clear()
+files$cached()
+
+# assign variables in the current environment
+files$assign("y")
+mean(y)
+}
+
diff --git a/man/sail.Rd b/man/sail.Rd
new file mode 100644
index 0000000..ee95339
--- /dev/null
+++ b/man/sail.Rd
@@ -0,0 +1,46 @@
+% Generated by roxygen2 (4.1.1): do not edit by hand
+% Please edit documentation in R/sail.R
+\name{sail}
+\alias{sail}
+\title{Create a source abstraction interface layer (SAIL) object.}
+\usage{
+sail(path = getwd(), extension = "R", all.files = FALSE,
+ use.cache = FALSE, simplify = TRUE, suppressMessages = FALSE)
+}
+\arguments{
+\item{path}{[\code{character(1)}]\cr
+Path to work in, will be created if it does not exists.}
+
+\item{extension}{[\code{character(1)}]\cr
+File extension to work with.
+Default is \dQuote{R}.}
+
+\item{all.files}{[\code{logical(1)}]\cr
+Also include hidden files, i.e. files whose name start with a dot (\dQuote{.}).
+Default is \code{FALSE}.}
+
+\item{use.cache}{[\code{logical(1)}]\cr
+Use a memory cache per global default.
+Global option which can locally be overwritten in most functions.
+Default is \code{FALSE}}
+
+\item{simplify}{[\code{character(1)}]\cr
+If only one object is defined in a sourced R file,
+should the return value be simplified? If set to \code{TRUE},
+instead of a list containing one element the object itself will be returned.}
+
+\item{suppressMessages}{[\code{logical(1)}]\cr
+Wrap the \code{\link[base]{sys.source}} command into \code{\link[base]{suppressMessages}}
+and \code{link[base]{suppressPackageStartupMessages}}?
+Default is \code{FALSE}, i.e. you will see regular output of sourced scripts.}
+}
+\value{
+Object of class \code{sail}. See the documentation of \code{\link{fail}}
+ for details.
+}
+\description{
+This function returns an object of class \code{sail} which behaves
+like \code{\link{fail}}, but is indented for loading and saving
+R source code files.
+}
+
diff --git a/tests/test_all.R b/tests/test_all.R
new file mode 100755
index 0000000..a691562
--- /dev/null
+++ b/tests/test_all.R
@@ -0,0 +1,2 @@
+library(testthat)
+test_check("fail")
diff --git a/tests/testthat/test_apply.R b/tests/testthat/test_apply.R
new file mode 100644
index 0000000..465ff16
--- /dev/null
+++ b/tests/testthat/test_apply.R
@@ -0,0 +1,41 @@
+context("apply")
+
+test_that("apply", {
+ path = tempfile()
+ f = fail(path)
+
+ f$put(a = 1:10, b = 1:100, c = 1:1000)
+ x = f$apply(mean)
+ expect_true(is.list(x))
+ expect_true(all(names(x) %in% letters[1:3]))
+ expect_equal(sort(unlist(x, use.names=FALSE)), c(5.5, 50.5, 500.5))
+
+ # subsetting keys works
+ x = f$apply(mean, keys=c("c", "b"))
+ expect_equal(names(x), c("c", "b"))
+
+ # simplify works
+ x = f$apply(mean, keys=letters[1:3], simplify=TRUE)
+ expect_equal(x, setNames(c(5.5, 50.5, 500.5), letters[1:3]))
+
+ # use.names works
+ x = f$apply(mean, keys=letters[1:3], use.names=FALSE)
+ expect_true(is.null(names(x)))
+
+ # passing arguments works
+ fun = function(x, y) mean(x) + y
+ x = f$apply(fun, y = -0.5, simplify=TRUE)
+ expect_equal(x, setNames(c(5, 50, 500), letters[1:3]))
+
+ # error handling
+ f$remove(f$ls())
+ f$put(a = 1, b = 2, c = "NA")
+ expect_error(f$apply(log), "key 'c'")
+
+ # invalid keys and empty sets
+ expect_equal(length(f$apply(identity, keys=NULL)), 0)
+ expect_error(f$apply(identity, keys="xxx"))
+ expect_equal(length(f$apply(identity, keys=character(0L))), 0)
+ f$remove(f$ls())
+ expect_equal(length(f$apply(identity)), 0)
+})
diff --git a/tests/testthat/test_as_list.R b/tests/testthat/test_as_list.R
new file mode 100644
index 0000000..c393f29
--- /dev/null
+++ b/tests/testthat/test_as_list.R
@@ -0,0 +1,16 @@
+context("as.list")
+
+test_that("as.list", {
+ path = tempfile()
+ f = fail(path)
+
+ f$put(a = 1, b = 2, c = 3)
+ expect_equal(f$as.list(), setNames(as.list(1:3), letters[1:3]))
+ expect_equal(f$as.list("a"), setNames(as.list(1), letters[1]))
+
+
+ # invalid keys and empty sets
+ expect_equal(length(f$as.list(NULL)), 0)
+ expect_error(f$as.list("xxx"))
+ expect_equal(length(f$as.list(character(0L))), 0L)
+})
diff --git a/tests/testthat/test_assign.R b/tests/testthat/test_assign.R
new file mode 100644
index 0000000..e0b829b
--- /dev/null
+++ b/tests/testthat/test_assign.R
@@ -0,0 +1,15 @@
+context("assign")
+
+test_that("assign", {
+ path = tempfile()
+ f = fail(path)
+
+ f$put(a = 1, b = 2)
+ f$assign("a")
+ expect_true(exists("a"))
+ expect_false(exists("b"))
+ a = 3
+ expect_true(a == 3)
+ f$assign("a")
+ expect_true(a == 1)
+})
diff --git a/tests/testthat/test_constructor.R b/tests/testthat/test_constructor.R
new file mode 100644
index 0000000..6534c2e
--- /dev/null
+++ b/tests/testthat/test_constructor.R
@@ -0,0 +1,26 @@
+context("Constructor")
+
+test_that("Creation of directories and checking of existing files", {
+ path = tempfile()
+ fail(path) # works on new dirs
+ fail(path) # works on existing dirs
+ path = tempfile()
+ file.create(path)
+ expect_error(fail(path))
+})
+
+test_that("Constructor checks input", {
+ path = tempfile()
+ expect_error(fail(path, extension="^"))
+ expect_error(fail(path, extension=".RData"))
+})
+
+test_that("Argument 'all.files' works", {
+ path = tempfile()
+ f = fail(path, all.files = FALSE)
+ expect_error(f$put(.x = 1), "hidden")
+
+ f = fail(path, all.files = TRUE)
+ f$put(.x = 1)
+ expect_equal(f$ls(), ".x")
+})
diff --git a/tests/testthat/test_get_put.R b/tests/testthat/test_get_put.R
new file mode 100644
index 0000000..86527a4
--- /dev/null
+++ b/tests/testthat/test_get_put.R
@@ -0,0 +1,50 @@
+context("list, get, put")
+
+test_that("list, get, put", {
+ path = tempfile()
+ f = fail(path)
+
+ expect_equal(f$ls(), character(0L))
+ expect_equal(f$put(a = 1, b = 2), letters[1:2])
+ expect_equal(f$ls(), letters[1:2])
+ expect_equal(f$put(li = list(c = 3)), letters[3])
+ expect_equal(f$ls(), letters[1:3])
+ f$put(d = 4, li = list(e = 5))
+ expect_equal(f$ls(), letters[1:5])
+
+ expect_equal(f$get("a"), 1)
+ x = f$as.list()
+ y = setNames(as.list(1:5), letters[1:5])
+ expect_equal(x, y)
+
+ # positional arguments
+ expect_equal(f$pos(), 1)
+ expect_equal(f$pos(2), 2)
+ expect_equal(f$pos(6), NULL)
+
+ path = tempfile()
+ f = fail(path)
+ f$put(1, 2, 3, keys = c("x", "y", "z"))
+ expect_equal(f$ls(), c("x", "y", "z"))
+ f$remove(f$ls())
+ f$put(1, 2, 3, li = list(foo = 5), keys = c("x", "y", "z"))
+ expect_equal(f$get("x"), 1)
+ expect_equal(f$get("foo"), 5)
+
+ # pattern works
+ expect_equal(f$ls("^[xy]"), c("x", "y"))
+ expect_equal(f$ls("a"), character(0L))
+
+ # invalid keys and empty sets
+ expect_error(f$get())
+ expect_error(f$get("not_existing"))
+ expect_error(f$put(li=list("a - b" = 1)))
+ expect_equal(f$put(), character(0L))
+
+ # cache
+ expect_equal(f$cached(), character(0L))
+ f$get("x", use.cache=TRUE)
+ expect_equal(f$cached(), "x")
+ f$clear()
+ expect_equal(f$cached(), character(0L))
+})
diff --git a/tests/testthat/test_mapply.R b/tests/testthat/test_mapply.R
new file mode 100644
index 0000000..5361ee4
--- /dev/null
+++ b/tests/testthat/test_mapply.R
@@ -0,0 +1,36 @@
+context("mapply")
+
+test_that("mapply", {
+ path = tempfile()
+ f = fail(path)
+
+ f$put(a = 1:10, b = 1:100)
+ x = f$mapply(function(key, value) mean(value))
+ expect_equal(x, list(a = 5.5, b = 50.5))
+ x = f$mapply(function(key, value) mean(value), keys = c("b", "a"))
+ expect_equal(x, list(b = 50.5, a = 5.5))
+ x = f$mapply(function(key, value) mean(value), use.names=FALSE)
+ expect_equal(x, list(5.5, 50.5))
+ x = f$mapply(function(key, value) mean(value), simplify=TRUE)
+ expect_equal(x, setNames(c(5.5, 50.5), letters[1:2]))
+ x = f$mapply(function(key, value, y) mean(value - y), y = 1)
+ expect_equal(x, list(a = 4.5, b = 49.5))
+ x = f$mapply(function(key, value, y) mean(value - y), moreArgs = list(y = 1))
+ expect_equal(x, list(a = 4.5, b = 49.5))
+
+ expect_error(f$mapply(function(key, value, y) mean(value - y), y = 0, moreArgs = list(y = 1)))
+
+ # error handling
+ f$remove(f$ls())
+ f$put(a = 1, b = 2, c = "NA")
+ expect_error(f$mapply(function(key, value) log(value)), "key 'c'")
+
+
+ # invalid keys and empty sets
+ fun = function(key, value) value
+ expect_equal(length(f$mapply(fun, keys=NULL)), 0)
+ expect_error(f$mapply(fun, keys="xxx"))
+ expect_equal(length(f$mapply(fun, keys=character(0L))), 0)
+ f$remove(f$ls())
+ expect_equal(length(f$mapply(fun)), 0)
+})
diff --git a/tests/testthat/test_remove.R b/tests/testthat/test_remove.R
new file mode 100644
index 0000000..82da32a
--- /dev/null
+++ b/tests/testthat/test_remove.R
@@ -0,0 +1,42 @@
+context("remove and clear")
+
+test_that("remove", {
+ path = tempfile()
+ f = fail(path)
+
+ f$put(a = 1, b = 2)
+ expect_equal(f$remove("b"), setNames(TRUE, "b"))
+ expect_equal(f$ls(), "a")
+ f$put(b = 2)
+ expect_equal(f$ls(), letters[1:2])
+ expect_equal(f$remove(letters[1:2]), setNames(c(TRUE, TRUE), letters[1:2]))
+ f$put(a = 1, b = 2)
+
+ # invalid keys and empty sets
+ expect_warning(f$remove("c"), "Files not removed")
+ expect_error(f$remove())
+ expect_equal(f$remove(character(0L)), setNames(logical(0), character(0)))
+
+ # cache
+ expect_equal(f$get("a", use.cache=TRUE), 1)
+ expect_equal(f$cached(), "a")
+ expect_equal(f$remove("a"), setNames(TRUE, "a"))
+ expect_equal(f$cached(), character(0L))
+ f$put(a = 1)
+ f$get("a", use.cache=TRUE)
+ f$get("b", use.cache=TRUE)
+ expect_equal(f$cached(), letters[1:2])
+ f$remove(letters[1:2])
+ expect_equal(f$cached(), character(0L))
+})
+
+test_that("clear", {
+ path = tempfile()
+ f = fail(path)
+ f$put(a = 1, b = 2)
+ f$get("a", use.cache=TRUE)
+ f$get("b", use.cache=TRUE)
+ expect_equal(f$cached(), letters[1:2])
+ f$clear()
+ expect_equal(f$cached(), character(0L))
+})
diff --git a/tests/testthat/test_sail.R b/tests/testthat/test_sail.R
new file mode 100644
index 0000000..76c40b6
--- /dev/null
+++ b/tests/testthat/test_sail.R
@@ -0,0 +1,35 @@
+context("sail")
+
+test_that("sail", {
+ # test basic usage here.
+ # most of the stuff is identical with fail ...
+
+ path = tempfile()
+ s = sail(path)
+
+ expect_equal(s$ls(), character(0L))
+ expect_equal(s$put(a = 1, b = 2), letters[1:2])
+ expect_equal(s$ls(), letters[1:2])
+ expect_equal(s$put(li = list(c = 3)), letters[3])
+ expect_equal(s$ls(), letters[1:3])
+ s$put(d = 4, li = list(e = 5))
+ expect_equal(s$ls(), letters[1:5])
+
+ expect_equal(s$as.list(), setNames(as.list(1:5), letters[1:5]))
+
+ s = sail(path, simplify = FALSE)
+ x = s$as.list()
+ expect_equal(x[[1]], list(a = 1))
+
+ s = sail(path, simplify = TRUE)
+ expect_equal(s$as.list(), s$apply(identity))
+
+ expect_equal(s$cached(), character(0L))
+ s$get("a", use.cache=TRUE)
+ expect_equal(s$cached(), "a")
+ expect_equal(s$get("a", use.cache = TRUE), 1)
+ expect_equal(s$clear(), "a")
+ expect_equal(s$cached(), character(0L))
+
+ expect_equal(s$remove(s$ls()), setNames(rep(TRUE, 5L), letters[1:5]))
+})
diff --git a/tests/testthat/test_size.R b/tests/testthat/test_size.R
new file mode 100644
index 0000000..aa799fa
--- /dev/null
+++ b/tests/testthat/test_size.R
@@ -0,0 +1,16 @@
+context("size")
+
+test_that("size", {
+ path = tempfile()
+ f = fail(path)
+
+ expect_equal(length(f$size()), 0)
+ f$put(a = 1, b = 2, c = 3)
+ expect_equal(length(f$size(("a"))), 1)
+ expect_equal(length(f$size()), 3)
+ expect_true(is.numeric(f$size()))
+
+ expect_true(all(f$size() > f$size(unit="Mb")))
+ expect_true(unname(is.na(f$size("d"))))
+ expect_equal(f$size(character(0L)), setNames(numeric(0L), character(0L)))
+})
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/debian-med/r-cran-fail.git
More information about the debian-med-commit
mailing list