[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