diff --git a/.Rbuildignore b/.Rbuildignore index 0e754c0..e8fbf40 100644 --- a/.Rbuildignore +++ b/.Rbuildignore @@ -3,4 +3,5 @@ ^examples ^\.travis\.yml$ ^appveyor\.yml$ +R/TODO.txt ^.RData diff --git a/DESCRIPTION b/DESCRIPTION index 0a2e7b0..96c1e62 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -16,7 +16,9 @@ LazyData: true Imports: V8 (>= 0.6), jsonlite, - utils + utils, + R6 +Enhances: lumberjack URL: http://github.com/edwindj/daff Suggests: testthat diff --git a/NAMESPACE b/NAMESPACE index eab5b03..20994b2 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -6,12 +6,14 @@ S3method(print,data_diff_summary) S3method(summary,data_diff) export(diff_data) export(differs_from) +export(lbj_daff) export(merge_data) export(patch_data) export(read_diff) export(render_diff) export(which_conflicts) export(write_diff) +import(R6) importFrom(V8,JS) importFrom(V8,new_context) importFrom(jsonlite,toJSON) diff --git a/R/lumberjack.R b/R/lumberjack.R new file mode 100644 index 0000000..0944e22 --- /dev/null +++ b/R/lumberjack.R @@ -0,0 +1,114 @@ +# A logger for the 'lumberjack' package. + + + +#' Automatically derive daffs with the lumberjack package +#' +#' The lbj_daff logger creates a \code{daff} and writes it to \code{daff.csv} +#' in a directory of choice. +#' +#' @import R6 +#' +#' @section Creating a logger: +#' +#' \code{filedump$new(dir=file.path(tempdir(),"daff") +#' , prefix="step\%03d.csv", verbose=TRUE, ...)} +#' \tabular{ll}{ +#' \code{dir}\tab Where to write the daff files.\cr +#' \code{filename}\tab filename template, used with \code{\link{sprintf}} +#' to create a file name.\cr +#' \code{verbose}\tab toggle verbosity\cr +#' \code{...}\tab Extra arguments, passed to \code{diff_data} each time. +#' } +#' +#' @section Dump options: +#' +#' \code{$dump(...)} +#' \tabular{ll}{ +#' \code{...}\tab Currently unused.\cr +#' } +#' +#' @section Retrieve log data: +#' +#' \code{$logdata(simplify=TRUE)} returns a list of data frames, sorted in the +#' order returned by \code{base::dir()} +#' \code{$diffs(simplify=TRUE)} returns a list of \code{daff} objects, sorted +#' in the order returned by \code{base::dir()} +#' +#' \tabular{ll}{ +#' \code{simplify}\tab Simplify lists of length 1 to data.frame? +#' } +#' +#' @section Details: +#' +#' If \code{dir} does not exist it is created. If +#' +#' +#' @docType class +#' @format An \code{R6} class object. +#' +#' @examples +#' \dontrun{ +#' library(lumberjack) +#' logger <- lbj_daff$new() +#' women %>>% +#' start_log(logger) %>>% +#' head() %>>% +#' {. * 2} %>>% +#' dump_log() +#' L <- logger$logdata() +#' L[[2]] +#' L <- logger$diffs() +#' L[[1]] +#' } +#' +#' @family loggers +#' @export +lbj_daff <- R6Class("lpj_daff" + , public=list( + n = NULL + , dir = NULL + , verbose = NULL + , filename = NULL + , daff_args = NULL + , initialize = function(dir = file.path(tempdir(), "daff") + , filename="daff%03d.csv", verbose = TRUE,...){ + self$n <- 0 + self$dir <- dir + if (!dir.exists(dir)){ + dir.create(dir,recursive = TRUE) + if (verbose){ + msgf("Created %s", normalizePath(dir)) + } + } + self$verbose <- verbose + self$filename <- filename + self$daff_args <- list(...) + } + , add = function(meta, input, output){ + outname <- file.path(self$dir,sprintf(self$filename,self$n)) + self$n <- self$n + 1 + outname <- file.path(self$dir, sprintf(self$filename,self$n)) + arglist <- c(list(data_ref=input, data=output), self$daff_args) + output <- do.call("diff_data", arglist) + write_diff(output, file=outname) + } + , dump = function(...){ + if ( self$verbose ){ + msgf("daffs were written to %s", normalizePath(self$dir)) + } + } + , logdata = function(simplify=TRUE){ + fl <- dir(self$dir,full.names = TRUE) + L <- lapply(fl, function(x) read_diff(x)$get_data()) + if (simplify && length(L) == 1L) L[[1]] else L + } + , diffs = function(simplify=TRUE){ + fl <- dir(self$dir, full.names=TRUE) + L <- lapply(fl, read_diff) + if (simplify && length(L) == 1L) L[[1]] else L + } +)) + +# msgf: the reasonable messenger :^) +msgf <- function(fmt,...) message(sprintf(fmt,...)) diff --git a/man/lbj_daff.Rd b/man/lbj_daff.Rd new file mode 100644 index 0000000..386e7c4 --- /dev/null +++ b/man/lbj_daff.Rd @@ -0,0 +1,73 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/lumberjack.R +\docType{class} +\name{lbj_daff} +\alias{lbj_daff} +\title{Automatically derive daffs with the lumberjack package} +\format{An \code{R6} class object.} +\usage{ +lbj_daff +} +\description{ +The lbj_daff logger creates a \code{daff} and writes it to \code{daff.csv} +in a directory of choice. +} +\section{Creating a logger}{ + + +\code{filedump$new(dir=file.path(tempdir(),"daff") + , prefix="step\%03d.csv", verbose=TRUE, ...)} +\tabular{ll}{ + \code{dir}\tab Where to write the daff files.\cr + \code{filename}\tab filename template, used with \code{\link{sprintf}} + to create a file name.\cr + \code{verbose}\tab toggle verbosity\cr + \code{...}\tab Extra arguments, passed to \code{diff_data} each time. +} +} + +\section{Dump options}{ + + +\code{$dump(...)} +\tabular{ll}{ + \code{...}\tab Currently unused.\cr +} +} + +\section{Retrieve log data}{ + + +\code{$logdata(simplify=TRUE)} returns a list of data frames, sorted in the + order returned by \code{base::dir()} +\code{$diffs(simplify=TRUE)} returns a list of \code{daff} objects, sorted + in the order returned by \code{base::dir()} + +\tabular{ll}{ +\code{simplify}\tab Simplify lists of length 1 to data.frame? +} +} + +\section{Details}{ + + +If \code{dir} does not exist it is created. If +} + +\examples{ +\dontrun{ + library(lumberjack) + logger <- lbj_daff$new() + women \%>>\% + start_log(logger) \%>>\% + head() \%>>\% + {. * 2} \%>>\% + dump_log() + L <- logger$logdata() + L[[2]] + L <- logger$diffs() + L[[1]] +} + +} +\keyword{datasets} diff --git a/tests/testthat/test_lumberjack.R b/tests/testthat/test_lumberjack.R new file mode 100644 index 0000000..ee74341 --- /dev/null +++ b/tests/testthat/test_lumberjack.R @@ -0,0 +1,14 @@ + +context("lumberjack logger") + +test_that("lumberjack logger",{ + logger <- lbj_daff$new() + meta=list(expr=expression({.*2}), src="{\n .*2\n}") + logger$add(meta, women, 2*women) + expect_equal(logger$n,1L) + fl <- dir(logger$dir, full.names = TRUE) + expect_equal(length(fl),1L) + d <- read.csv(fl) + expect_equal(nrow(d), nrow(women)*ncol(women)) + expect_equal(nrow(logger$logdata()), nrow(women)*ncol(women)) +})