From 864260da1a9619686f961a3cbac0ddbdf8475f50 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kirill=20M=C3=BCller?= Date: Tue, 15 Jan 2019 14:24:55 +0100 Subject: [PATCH 01/28] - Use _vctrs_. Only the user-facing `blob()` constructor checks the contents of the vector, `new_blob()` only checks if the input is a list (#10). --- DESCRIPTION | 3 ++- NAMESPACE | 3 +-- R/accessors.R | 5 ----- R/blob.R | 20 +++++++++++--------- tests/testthat/test-construction.R | 6 +++--- 5 files changed, 17 insertions(+), 20 deletions(-) diff --git a/DESCRIPTION b/DESCRIPTION index acce1ab..434b6f1 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -21,7 +21,8 @@ URL: https://github.com/tidyverse/blob BugReports: https://github.com/tidyverse/blob/issues Imports: methods, - prettyunits + prettyunits, + vctrs Suggests: covr, pillar (>= 1.2.1), diff --git a/NAMESPACE b/NAMESPACE index 2836670..088786c 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -1,6 +1,5 @@ # Generated by roxygen2: do not edit by hand -S3method("[",blob) S3method("[<-",blob) S3method("[[<-",blob) S3method("is.na<-",blob) @@ -9,7 +8,6 @@ S3method(as.blob,character) S3method(as.blob,integer) S3method(as.blob,list) S3method(as.blob,raw) -S3method(as.data.frame,blob) S3method(c,blob) S3method(format,blob) S3method(is.na,blob) @@ -17,4 +15,5 @@ S3method(print,blob) export(as.blob) export(blob) export(new_blob) +import(vctrs) importFrom(methods,setOldClass) diff --git a/R/accessors.R b/R/accessors.R index de859d6..bd5caf6 100644 --- a/R/accessors.R +++ b/R/accessors.R @@ -1,8 +1,3 @@ -#' @export -`[.blob` <- function(x, i, ...) { - new_blob(NextMethod()) -} - #' @export `[<-.blob` <- function(x, i, ..., value) { if (!is_raw_list(value)) { diff --git a/R/blob.R b/R/blob.R index 5544113..15dee6e 100644 --- a/R/blob.R +++ b/R/blob.R @@ -1,5 +1,8 @@ +#' @import vctrs +NULL + #' @importFrom methods setOldClass -setOldClass("blob") +setOldClass(c("blob", "vctrs_blob", "vctrs_vctr")) #' Construct a blob object #' @@ -19,16 +22,18 @@ setOldClass("blob") #' #' as.blob(c("Good morning", "Good evening")) blob <- function(...) { - new_blob(list(...)) + x <- list(...) + if (!is_raw_list(x)) { + stop("`x` must be a list of raw vectors", call. = FALSE) + } + new_blob(x) } #' @export #' @rdname blob new_blob <- function(x) { - if (!is_raw_list(x)) { - stop("`x` must be a list of raw vectors", call. = FALSE) - } - structure(x, class = "blob") + vec_assert(x, list()) + new_vctr(x, class = c("blob", "vctrs_blob")) } #' @export @@ -61,6 +66,3 @@ as.blob.character <- function(x, ...) { as.blob.integer <- function(x, ...) { new_blob(lapply(x, as.raw)) } - -#' @export -as.data.frame.blob <- as.data.frame.difftime diff --git a/tests/testthat/test-construction.R b/tests/testthat/test-construction.R index 407c21a..560d2d8 100644 --- a/tests/testthat/test-construction.R +++ b/tests/testthat/test-construction.R @@ -1,7 +1,7 @@ context("construction") test_that("input must be list of raw blobs", { - expect_error(new_blob(1), "must be a list of raw vectors") - expect_error(new_blob(list(1)), "must be a list of raw vectors") - expect_error(new_blob(list(1, as.raw(1))), "must be a list of raw vectors") + expect_error(new_blob(1), "`x` must be , not .") + expect_error(blob(1), "must be a list of raw vectors") + expect_error(blob(1, as.raw(1)), "must be a list of raw vectors") }) From 28856a1c0927d45376951a09cae82ad7ee0f2b89 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kirill=20M=C3=BCller?= Date: Tue, 15 Jan 2019 15:23:53 +0100 Subject: [PATCH 02/28] Get rid of print() method --- NAMESPACE | 1 - R/format.R | 9 --------- 2 files changed, 10 deletions(-) diff --git a/NAMESPACE b/NAMESPACE index 088786c..8a8fce9 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -11,7 +11,6 @@ S3method(as.blob,raw) S3method(c,blob) S3method(format,blob) S3method(is.na,blob) -S3method(print,blob) export(as.blob) export(blob) export(new_blob) diff --git a/R/format.R b/R/format.R index 5ad4f21..cda8898 100644 --- a/R/format.R +++ b/R/format.R @@ -6,15 +6,6 @@ format.blob <- function(x, ...) { ifelse(is.na(x), "", paste0("blob[", blob_size(x, ...), "]")) } -#' @export -print.blob <- function(x, ...) { - if (length(x) == 0) { - cat("blob()\n") - } else { - print(format(x, ...), quote = FALSE) - } -} - # Dynamically exported, see zzz.R type_sum.blob <- function(x) { "blob" From d111652ccd9bd359260718078561325e326c2691 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kirill=20M=C3=BCller?= Date: Tue, 15 Jan 2019 15:47:13 +0100 Subject: [PATCH 03/28] Implement vec_ptype_abbr() instead of type_sum() --- NAMESPACE | 1 + R/format.R | 4 ++-- R/zzz.R | 1 - 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/NAMESPACE b/NAMESPACE index 8a8fce9..1e39c84 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -11,6 +11,7 @@ S3method(as.blob,raw) S3method(c,blob) S3method(format,blob) S3method(is.na,blob) +S3method(vec_ptype_abbr,vctrs_percent) export(as.blob) export(blob) export(new_blob) diff --git a/R/format.R b/R/format.R index cda8898..fa45e3b 100644 --- a/R/format.R +++ b/R/format.R @@ -6,8 +6,8 @@ format.blob <- function(x, ...) { ifelse(is.na(x), "", paste0("blob[", blob_size(x, ...), "]")) } -# Dynamically exported, see zzz.R -type_sum.blob <- function(x) { +#' @export +vec_ptype_abbr.vctrs_percent <- function(x) { "blob" } diff --git a/R/zzz.R b/R/zzz.R index 9e41dc2..6d65e79 100644 --- a/R/zzz.R +++ b/R/zzz.R @@ -2,7 +2,6 @@ .onLoad <- function(...) { register_s3_method("pillar", "pillar_shaft", "blob") register_s3_method("pillar", "is_vector_s3", "blob") - register_s3_method("pillar", "type_sum", "blob") invisible() } From ec2b752e4949d696467c91b9977aade12aebced9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kirill=20M=C3=BCller?= Date: Tue, 15 Jan 2019 16:26:14 +0100 Subject: [PATCH 04/28] Extract check_raw_list() --- DESCRIPTION | 1 + NAMESPACE | 1 + R/blob.R | 10 ++++++++-- 3 files changed, 10 insertions(+), 2 deletions(-) diff --git a/DESCRIPTION b/DESCRIPTION index 434b6f1..42e724f 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -22,6 +22,7 @@ BugReports: https://github.com/tidyverse/blob/issues Imports: methods, prettyunits, + rlang, vctrs Suggests: covr, diff --git a/NAMESPACE b/NAMESPACE index 1e39c84..0ce9534 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -15,5 +15,6 @@ S3method(vec_ptype_abbr,vctrs_percent) export(as.blob) export(blob) export(new_blob) +import(rlang) import(vctrs) importFrom(methods,setOldClass) diff --git a/R/blob.R b/R/blob.R index 15dee6e..b4ef95c 100644 --- a/R/blob.R +++ b/R/blob.R @@ -1,4 +1,5 @@ #' @import vctrs +#' @import rlang NULL #' @importFrom methods setOldClass @@ -23,10 +24,15 @@ setOldClass(c("blob", "vctrs_blob", "vctrs_vctr")) #' as.blob(c("Good morning", "Good evening")) blob <- function(...) { x <- list(...) + check_raw_list(x) + new_blob(x) +} + +check_raw_list <- function(x) { + quo <- enquo(x) if (!is_raw_list(x)) { - stop("`x` must be a list of raw vectors", call. = FALSE) + stop("`", as_label(quo), "` must be a list of raw vectors", call. = FALSE) } - new_blob(x) } #' @export From 16cc4aff7288fc3ccbf1830f6479fe8dce706662 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kirill=20M=C3=BCller?= Date: Tue, 15 Jan 2019 17:00:59 +0100 Subject: [PATCH 05/28] Comment reasons for existing behavior --- R/accessors.R | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/R/accessors.R b/R/accessors.R index bd5caf6..241ce32 100644 --- a/R/accessors.R +++ b/R/accessors.R @@ -7,6 +7,8 @@ NextMethod() } +# Required, because blob wraps a list, and the default implementation +# doesn't cast if the underlying type is a list. #' @export `[[<-.blob` <- function(x, i, ..., value) { if (!is.raw(value) && !is.null(value)) { @@ -14,6 +16,8 @@ } if (is.null(value)) { + # Setting to NULL via [[ shortens the list! Example: + # `[[<-`(list(1), 1, NULL) x[i] <- list(NULL) x } else { From b57ab6f29d8210cfbc8b8013753792abb9ec2aa4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kirill=20M=C3=BCller?= Date: Tue, 15 Jan 2019 17:02:16 +0100 Subject: [PATCH 06/28] - blob() uses tidy evaluation. --- R/blob.R | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/R/blob.R b/R/blob.R index b4ef95c..b968a56 100644 --- a/R/blob.R +++ b/R/blob.R @@ -23,7 +23,7 @@ setOldClass(c("blob", "vctrs_blob", "vctrs_vctr")) #' #' as.blob(c("Good morning", "Good evening")) blob <- function(...) { - x <- list(...) + x <- list2(...) check_raw_list(x) new_blob(x) } From 4cfc28b454fab951df4733e854a27bcca7f828f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kirill=20M=C3=BCller?= Date: Tue, 15 Jan 2019 17:02:59 +0100 Subject: [PATCH 07/28] - new_blob() gains default argument for convenience. --- R/blob.R | 2 +- man/blob.Rd | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/R/blob.R b/R/blob.R index b968a56..d963bd6 100644 --- a/R/blob.R +++ b/R/blob.R @@ -37,7 +37,7 @@ check_raw_list <- function(x) { #' @export #' @rdname blob -new_blob <- function(x) { +new_blob <- function(x = list()) { vec_assert(x, list()) new_vctr(x, class = c("blob", "vctrs_blob")) } diff --git a/man/blob.Rd b/man/blob.Rd index a5eb4ae..a986a95 100644 --- a/man/blob.Rd +++ b/man/blob.Rd @@ -8,7 +8,7 @@ \usage{ blob(...) -new_blob(x) +new_blob(x = list()) as.blob(x, ...) } From 3d63f6375d3041509e1cfbe2040a399af5d10da9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kirill=20M=C3=BCller?= Date: Tue, 15 Jan 2019 17:10:58 +0100 Subject: [PATCH 08/28] Casting and coercion, [<- and c methods now gone. --- NAMESPACE | 16 ++++++++++++-- R/accessors.R | 12 ----------- R/cast.R | 30 ++++++++++++++++++++++++++ R/coerce.R | 38 +++++++++++++++++++++++++++++++++ man/vec_cast.vctrs_blob.Rd | 16 ++++++++++++++ man/vec_type2.vctrs_blob.Rd | 16 ++++++++++++++ tests/testthat/test-accessors.R | 4 ++-- 7 files changed, 116 insertions(+), 16 deletions(-) create mode 100644 R/cast.R create mode 100644 R/coerce.R create mode 100644 man/vec_cast.vctrs_blob.Rd create mode 100644 man/vec_type2.vctrs_blob.Rd diff --git a/NAMESPACE b/NAMESPACE index 0ce9534..91730e4 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -1,6 +1,5 @@ # Generated by roxygen2: do not edit by hand -S3method("[<-",blob) S3method("[[<-",blob) S3method("is.na<-",blob) S3method(as.blob,blob) @@ -8,13 +7,26 @@ S3method(as.blob,character) S3method(as.blob,integer) S3method(as.blob,list) S3method(as.blob,raw) -S3method(c,blob) S3method(format,blob) S3method(is.na,blob) +S3method(vec_cast,vctrs_blob) +S3method(vec_cast.list,vctrs_blob) +S3method(vec_cast.vctrs_blob,default) +S3method(vec_cast.vctrs_blob,list) +S3method(vec_cast.vctrs_blob,logical) +S3method(vec_cast.vctrs_blob,vctrs_blob) S3method(vec_ptype_abbr,vctrs_percent) +S3method(vec_type2,vctrs_blob) +S3method(vec_type2.list,vctrs_blob) +S3method(vec_type2.vctrs_blob,default) +S3method(vec_type2.vctrs_blob,list) +S3method(vec_type2.vctrs_blob,vctrs_blob) +S3method(vec_type2.vctrs_blob,vctrs_unspecified) export(as.blob) export(blob) export(new_blob) +export(vec_cast.vctrs_blob) +export(vec_type2.vctrs_blob) import(rlang) import(vctrs) importFrom(methods,setOldClass) diff --git a/R/accessors.R b/R/accessors.R index 241ce32..eb6f48f 100644 --- a/R/accessors.R +++ b/R/accessors.R @@ -1,12 +1,3 @@ -#' @export -`[<-.blob` <- function(x, i, ..., value) { - if (!is_raw_list(value)) { - stop("RHS must be list of raw vectors", call. = FALSE) - } - - NextMethod() -} - # Required, because blob wraps a list, and the default implementation # doesn't cast if the underlying type is a list. #' @export @@ -24,6 +15,3 @@ NextMethod() } } - -#' @export -c.blob <- function(x, ...) as.blob(NextMethod()) diff --git a/R/cast.R b/R/cast.R new file mode 100644 index 0000000..d807959 --- /dev/null +++ b/R/cast.R @@ -0,0 +1,30 @@ +#' Casting +#' +#' Double dispatch methods to support [vctrs::vec_cast()]. +#' +#' @inheritParams vctrs::vec_cast +#' +#' @method vec_cast vctrs_blob +#' @export +#' @export vec_cast.vctrs_blob +vec_cast.vctrs_blob <- function(x, to) UseMethod("vec_cast.vctrs_blob") + +#' @method vec_cast.vctrs_blob default +#' @export +vec_cast.vctrs_blob.default <- function(x, to) stop_incompatible_cast(x, to) + +#' @method vec_cast.vctrs_blob logical +#' @export +vec_cast.vctrs_blob.logical <- function(x, to) vec_unspecified_cast(x, to) + +#' @method vec_cast.vctrs_blob vctrs_blob +#' @export +vec_cast.vctrs_blob.vctrs_blob <- function(x, to) x + +#' @method vec_cast.vctrs_blob list +#' @export +vec_cast.vctrs_blob.list <- function(x, to) blob(!!!x) + +#' @method vec_cast.list vctrs_blob +#' @export +vec_cast.list.vctrs_blob <- function(x, to) vec_data(x) diff --git a/R/coerce.R b/R/coerce.R new file mode 100644 index 0000000..de3e97b --- /dev/null +++ b/R/coerce.R @@ -0,0 +1,38 @@ +#' Coercion +#' +#' Double dispatch methods to support [vctrs::vec_type2()]. +#' +#' @inheritParams vctrs::vec_type2 +#' +#' @method vec_type2 vctrs_blob +#' @export +#' @export vec_type2.vctrs_blob +vec_type2.vctrs_blob <- function(x, y) UseMethod("vec_type2.vctrs_blob", y) + +#' @method vec_type2.vctrs_blob default +#' @export +vec_type2.vctrs_blob.default <- function(x, y) stop_incompatible_type(x, y) + +#' @method vec_type2.vctrs_blob vctrs_blob +#' @export +vec_type2.vctrs_blob.vctrs_blob <- function(x, y) { + new_blob(list()) +} + +#' @method vec_type2.vctrs_blob vctrs_unspecified +#' @export +vec_type2.vctrs_blob.vctrs_unspecified <- function(x, y) x + +#' @method vec_type2.vctrs_blob list +#' @export +vec_type2.vctrs_blob.list <- function(x, y) { + check_raw_list(y) + new_blob(list()) +} + +#' @method vec_type2.list vctrs_blob +#' @export +vec_type2.list.vctrs_blob <- function(x, y) { + check_raw_list(x) + new_blob(list()) +} diff --git a/man/vec_cast.vctrs_blob.Rd b/man/vec_cast.vctrs_blob.Rd new file mode 100644 index 0000000..c9b7cdb --- /dev/null +++ b/man/vec_cast.vctrs_blob.Rd @@ -0,0 +1,16 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/cast.R +\name{vec_cast.vctrs_blob} +\alias{vec_cast.vctrs_blob} +\title{Casting} +\usage{ +\method{vec_cast}{vctrs_blob}(x, to) +} +\arguments{ +\item{x}{Vectors to cast.} + +\item{to}{Type to cast to. If \code{NULL}, \code{x} will be returned as is.} +} +\description{ +Double dispatch methods to support \code{\link[vctrs:vec_cast]{vctrs::vec_cast()}}. +} diff --git a/man/vec_type2.vctrs_blob.Rd b/man/vec_type2.vctrs_blob.Rd new file mode 100644 index 0000000..76ee737 --- /dev/null +++ b/man/vec_type2.vctrs_blob.Rd @@ -0,0 +1,16 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/coerce.R +\name{vec_type2.vctrs_blob} +\alias{vec_type2.vctrs_blob} +\title{Coercion} +\usage{ +\method{vec_type2}{vctrs_blob}(x, y) +} +\arguments{ +\item{x}{Either vector types; i.e.} + +\item{y}{Either vector types; i.e.} +} +\description{ +Double dispatch methods to support \code{\link[vctrs:vec_type2]{vctrs::vec_type2()}}. +} diff --git a/tests/testthat/test-accessors.R b/tests/testthat/test-accessors.R index 40b1d3d..92770ad 100644 --- a/tests/testthat/test-accessors.R +++ b/tests/testthat/test-accessors.R @@ -8,8 +8,8 @@ test_that("subsetting blob returns blob", { test_that("can't insert objects of incorrect type", { x <- as.blob(1:5) - expect_error(x[[1]] <- 1, "must be raw vector") - expect_error(x[1] <- 1, "must be list of raw vectors") + expect_error(x[[1]] <- 1, "RHS must be raw vector or NULL", fixed = TRUE) + expect_error(x[1] <- 1, "Can't cast to ", fixed = TRUE) }) test_that("can insert raw or NULL", { From 1ff83a95c61014d907c9777cafac2abde1f3378a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kirill=20M=C3=BCller?= Date: Tue, 15 Jan 2019 17:12:40 +0100 Subject: [PATCH 09/28] is.na() works out of the box, is.na<-() needs to be kept for now --- NAMESPACE | 1 - R/missing.R | 5 ----- 2 files changed, 6 deletions(-) diff --git a/NAMESPACE b/NAMESPACE index 91730e4..0fb0bdf 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -8,7 +8,6 @@ S3method(as.blob,integer) S3method(as.blob,list) S3method(as.blob,raw) S3method(format,blob) -S3method(is.na,blob) S3method(vec_cast,vctrs_blob) S3method(vec_cast.list,vctrs_blob) S3method(vec_cast.vctrs_blob,default) diff --git a/R/missing.R b/R/missing.R index c36fcbb..ba655f1 100644 --- a/R/missing.R +++ b/R/missing.R @@ -1,8 +1,3 @@ -#' @export -is.na.blob <- function(x) { - vapply(x, is.null, logical(1)) -} - #' @export `is.na<-.blob` <- function(x, value) { if (!is.logical(value) || length(x) != length(value)) { From 6700523c5ec9d81ca5d591537b03fefd04a8cc4c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kirill=20M=C3=BCller?= Date: Tue, 15 Jan 2019 17:13:44 +0100 Subject: [PATCH 10/28] - Simplify . --- R/missing.R | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/R/missing.R b/R/missing.R index ba655f1..63b59af 100644 --- a/R/missing.R +++ b/R/missing.R @@ -1,9 +1,10 @@ +# No implementation in vctrs 0.1.0 #' @export `is.na<-.blob` <- function(x, value) { if (!is.logical(value) || length(x) != length(value)) { stop("RHS must be a logical the same length as `x`", call. = FALSE) } - x[value] <- rep(list(NULL), sum(value)) + x[value] <- list(NULL) x } From 8a4acf9879351286ec05b2b3db40ac09f80df7a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kirill=20M=C3=BCller?= Date: Tue, 15 Jan 2019 18:57:09 +0100 Subject: [PATCH 11/28] Add tests --- tests/testthat/test-accessors.R | 23 +++++++++++++++++++++++ tests/testthat/test-cast.R | 9 +++++++++ tests/testthat/test-format.R | 9 +++++++++ tests/testthat/test-missing.R | 6 ++++++ 4 files changed, 47 insertions(+) create mode 100644 tests/testthat/test-cast.R diff --git a/tests/testthat/test-accessors.R b/tests/testthat/test-accessors.R index 92770ad..377cf59 100644 --- a/tests/testthat/test-accessors.R +++ b/tests/testthat/test-accessors.R @@ -28,4 +28,27 @@ test_that("can combine", { c(blob(raw(4), raw(5)), blob(raw(7))), blob(raw(4), raw(5), raw(7)) ) + expect_identical( + # Doesn't work with c() + vec_c(list(raw(4), raw(5)), blob(raw(7))), + blob(raw(4), raw(5), raw(7)) + ) + expect_identical( + vec_c(list(raw(7)), blob(raw(4), raw(5)), list(raw(7))), + blob(raw(7), raw(4), raw(5), raw(7)) + ) + expect_identical( + vec_c(NA, blob()), + blob(NULL) + ) + expect_identical( + c(blob(), NA), + blob(NULL) + ) + expect_error( + c(blob(raw(4), raw(5)), raw(7)) + ) + expect_error( + c(blob(raw(4), raw(5)), 7) + ) }) diff --git a/tests/testthat/test-cast.R b/tests/testthat/test-cast.R new file mode 100644 index 0000000..1e7ffb1 --- /dev/null +++ b/tests/testthat/test-cast.R @@ -0,0 +1,9 @@ +context("test-cast") + +test_that("casting with as.blob()", { + expect_identical(as.blob(blob(raw(1))), blob(raw(1))) + expect_identical(as.blob(list(raw(1))), blob(raw(1))) + expect_identical(as.blob(raw(1)), blob(raw(1))) + expect_identical(as.blob(1:3), blob(as.raw(1), as.raw(2), as.raw(3))) + expect_identical(as.blob(c("abc", "def")), blob(charToRaw("abc"), charToRaw("def"))) +}) diff --git a/tests/testthat/test-format.R b/tests/testthat/test-format.R index 16c9a69..57b05cd 100644 --- a/tests/testthat/test-format.R +++ b/tests/testthat/test-format.R @@ -45,3 +45,12 @@ test_that("similar sizes", { ) ) }) + +test_that("empty", { + x <- blob() + + expect_format_equal( + format(x), + character() + ) +}) diff --git a/tests/testthat/test-missing.R b/tests/testthat/test-missing.R index 97cde21..9af242f 100644 --- a/tests/testthat/test-missing.R +++ b/tests/testthat/test-missing.R @@ -11,3 +11,9 @@ test_that("is.na<- sets missing values", { expect_equal(x, blob(as.raw(1), NULL, as.raw(3), NULL)) }) + +test_that("is.na<- error", { + x <- as.blob(1:4) + expect_error(is.na(x) <- rep(TRUE, 26)) + expect_error(is.na(x) <- letters[1:4]) +}) From 2df1350488e21f5cc5c6916d3dadaf83a079f779 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kirill=20M=C3=BCller?= Date: Tue, 15 Jan 2019 19:06:41 +0100 Subject: [PATCH 12/28] - Use vec_cast() to implement as.blob(). --- NAMESPACE | 9 ++++----- R/blob.R | 24 ++---------------------- R/cast.R | 12 ++++++++++++ 3 files changed, 18 insertions(+), 27 deletions(-) diff --git a/NAMESPACE b/NAMESPACE index 0fb0bdf..1248351 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -2,17 +2,16 @@ S3method("[[<-",blob) S3method("is.na<-",blob) -S3method(as.blob,blob) -S3method(as.blob,character) -S3method(as.blob,integer) -S3method(as.blob,list) -S3method(as.blob,raw) +S3method(as.blob,default) S3method(format,blob) S3method(vec_cast,vctrs_blob) S3method(vec_cast.list,vctrs_blob) +S3method(vec_cast.vctrs_blob,character) S3method(vec_cast.vctrs_blob,default) +S3method(vec_cast.vctrs_blob,integer) S3method(vec_cast.vctrs_blob,list) S3method(vec_cast.vctrs_blob,logical) +S3method(vec_cast.vctrs_blob,raw) S3method(vec_cast.vctrs_blob,vctrs_blob) S3method(vec_ptype_abbr,vctrs_percent) S3method(vec_type2,vctrs_blob) diff --git a/R/blob.R b/R/blob.R index d963bd6..c7938f7 100644 --- a/R/blob.R +++ b/R/blob.R @@ -49,26 +49,6 @@ as.blob <- function(x, ...) { } #' @export -as.blob.blob <- function(x, ...) { - x -} - -#' @export -as.blob.list <- function(x, ...) { - new_blob(x) -} - -#' @export -as.blob.raw <- function(x, ...) { - new_blob(list(x)) -} - -#' @export -as.blob.character <- function(x, ...) { - new_blob(lapply(x, charToRaw)) -} - -#' @export -as.blob.integer <- function(x, ...) { - new_blob(lapply(x, as.raw)) +as.blob.default <- function(x, ...) { + vec_cast(x, new_blob()) } diff --git a/R/cast.R b/R/cast.R index d807959..06b0dba 100644 --- a/R/cast.R +++ b/R/cast.R @@ -25,6 +25,18 @@ vec_cast.vctrs_blob.vctrs_blob <- function(x, to) x #' @export vec_cast.vctrs_blob.list <- function(x, to) blob(!!!x) +#' @method vec_cast.vctrs_blob integer +#' @export +vec_cast.vctrs_blob.integer <- function(x, to) blob(!!!lapply(x, as.raw)) + +#' @method vec_cast.vctrs_blob raw +#' @export +vec_cast.vctrs_blob.raw <- function(x, to) blob(x) + +#' @method vec_cast.vctrs_blob character +#' @export +vec_cast.vctrs_blob.character <- function(x, to) blob(!!!lapply(x, charToRaw)) + #' @method vec_cast.list vctrs_blob #' @export vec_cast.list.vctrs_blob <- function(x, to) vec_data(x) From 270a163302384a0230fb3f47897f234820cd410a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kirill=20M=C3=BCller?= Date: Tue, 15 Jan 2019 15:10:40 +0100 Subject: [PATCH 13/28] Add lifecycle compat code --- R/compat-lifecycle.R | 229 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 229 insertions(+) create mode 100644 R/compat-lifecycle.R diff --git a/R/compat-lifecycle.R b/R/compat-lifecycle.R new file mode 100644 index 0000000..68bb5ab --- /dev/null +++ b/R/compat-lifecycle.R @@ -0,0 +1,229 @@ +# nocov start - compat-lifecycle (last updated: rlang 0.3.0.9000) + +# This file serves as a reference for currently unexported rlang +# lifecycle functions. Please find the most recent version in rlang's +# repository. These functions require rlang in your `Imports` +# DESCRIPTION field but you don't need to import rlang in your +# namespace. + + +#' Signal deprecation +#' +#' @description +#' +#' These functions provide two levels of verbosity for deprecation +#' warnings. +#' +#' * `signal_soft_deprecated()` warns only if called from the global +#' environment (so the user can change their script) or from the +#' package currently being tested (so the package developer can fix +#' the package). +#' +#' * `warn_deprecated()` warns unconditionally. +#' +#' * `stop_defunct()` fails unconditionally. +#' +#' Both functions warn only once per session by default to avoid +#' overwhelming the user with repeated warnings. +#' +#' @param msg The deprecation message. +#' @param id The id of the deprecation. A warning is issued only once +#' for each `id`. Defaults to `msg`, but you should give a unique ID +#' when the message is built programmatically and depends on inputs. +#' @param env The environment in which the soft-deprecated function +#' was called. A warning is issued if called from the global +#' environment. If testthat is running, a warning is also called if +#' the retired function was called from the package being tested. +#' +#' @section Controlling verbosity: +#' +#' The verbosity of retirement warnings can be controlled with global +#' options. You'll generally want to set these options locally with +#' one of these helpers: +#' +#' * `with_lifecycle_silence()` disables all soft-deprecation and +#' deprecation warnings. +#' +#' * `with_lifecycle_warnings()` enforces warnings for both +#' soft-deprecated and deprecated functions. The warnings are +#' repeated rather than signalled once per session. +#' +#' * `with_lifecycle_errors()` enforces errors for both +#' soft-deprecated and deprecated functions. +#' +#' All the `with_` helpers have `scoped_` variants that are +#' particularly useful in testthat blocks. +#' +#' @noRd +#' @seealso [lifecycle()] +NULL + +signal_soft_deprecated <- function(msg, id = msg, env = caller_env(2)) { + if (rlang::is_true(rlang::peek_option("lifecycle_disable_warnings"))) { + return(invisible(NULL)) + } + + if (rlang::is_true(rlang::peek_option("lifecycle_verbose_soft_deprecation")) || + rlang::is_reference(topenv(env), rlang::global_env())) { + warn_deprecated(msg, id) + return(invisible(NULL)) + } + + # Test for environment names rather than reference/contents because + # testthat clones the namespace + tested_package <- Sys.getenv("TESTTHAT_PKG") + if (nzchar(tested_package) && + identical(Sys.getenv("NOT_CRAN"), "true") && + rlang::env_name(topenv(env)) == rlang::env_name(ns_env(tested_package))) { + warn_deprecated(msg, id) + return(invisible(NULL)) + } + + rlang::signal(msg, "lifecycle_soft_deprecated") +} + +warn_deprecated <- function(msg, id = msg) { + if (rlang::is_true(rlang::peek_option("lifecycle_disable_warnings"))) { + return(invisible(NULL)) + } + + if (!rlang::is_true(rlang::peek_option("lifecycle_repeat_warnings"))) { + if (rlang::env_has(deprecation_env, id)) { + return(invisible(NULL)) + } + + has_colour <- function() rlang::is_installed("crayon") && crayon::has_color() + silver <- function(x) if (has_colour()) crayon::silver(x) else x + + msg <- paste0( + msg, + "\n", + silver("This warning is displayed once per session.") + ) + } + + rlang::env_poke(deprecation_env, id, TRUE) + + if (rlang::is_true(rlang::peek_option("lifecycle_warnings_as_errors"))) { + signal <- .Defunct + } else { + signal <- .Deprecated + } + + signal(msg = msg) +} +deprecation_env <- new.env(parent = emptyenv()) + +stop_defunct <- function(msg) { + .Defunct(msg = msg) +} + +scoped_lifecycle_silence <- function(frame = rlang::caller_env()) { + rlang::scoped_options(.frame = frame, + lifecycle_disable_warnings = TRUE + ) +} +with_lifecycle_silence <- function(expr) { + scoped_lifecycle_silence() + expr +} + +scoped_lifecycle_warnings <- function(frame = rlang::caller_env()) { + rlang::scoped_options(.frame = frame, + lifecycle_disable_warnings = FALSE, + lifecycle_verbose_soft_deprecation = TRUE, + lifecycle_repeat_warnings = TRUE + ) +} +with_lifecycle_warnings <- function(expr) { + scoped_lifecycle_warnings() + expr +} + +scoped_lifecycle_errors <- function(frame = rlang::caller_env()) { + scoped_lifecycle_warnings(frame = frame) + rlang::scoped_options(.frame = frame, + lifecycle_warnings_as_errors = TRUE + ) +} +with_lifecycle_errors <- function(expr) { + scoped_lifecycle_errors() + expr +} + + +#' Embed a lifecycle badge in documentation +#' +#' @description +#' +#' Use `lifecycle()` within a `Sexpr` macro to embed a +#' [lifecycle](https://www.tidyverse.org/lifecycle/) badge in your +#' documentation. The badge should appear first in the description: +#' +#' ``` +#' \Sexpr[results=rd, stage=render]{mypkg:::lifecycle("questioning")} +#' ``` +#' +#' The badge appears as an image in the HTML version of the +#' documentation. To make them available in your package, visit +#' and copy +#' all the files starting with `lifecycle-` in your `man/figures/` +#' folder. +#' +#' @param stage A lifecycle stage as a string, one of: +#' `"experimental"`, `"maturing"`, `"stable"`, `"questioning"`, +#' `"archived"`, `"soft-deprecated"`, `"deprecated"`, `"defunct"`. +#' +#' @noRd +NULL + +lifecycle <- function(stage) { + url <- paste0("https://www.tidyverse.org/lifecycle/#", stage) + img <- lifecycle_img(stage, url) + + sprintf( + "\\ifelse{html}{%s}{\\strong{%s}}", + img, + upcase1(stage) + ) +} + +lifecycle_img <- function(stage, url) { + file <- sprintf("lifecycle-%s.svg", stage) + stage_alt <- upcase1(stage) + + switch(stage, + + experimental = , + maturing = , + stable = , + questioning = , + archived = + sprintf( + "\\out{%s lifecycle}", + url, + file.path("figures", file), + stage_alt + ) + , + + `soft-deprecated` = , + deprecated = , + defunct = + sprintf( + "\\figure{%s}{options: alt='%s lifecycle'}", + file, + stage_alt + ), + + rlang::abort(sprintf("Unknown lifecycle stage `%s`", stage)) + + ) +} +upcase1 <- function(x) { + substr(x, 1, 1) <- toupper(substr(x, 1, 1)) + x +} + + +# nocov end From 581212a47a2526a3da247ae8b25d3e547194abdc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kirill=20M=C3=BCller?= Date: Tue, 15 Jan 2019 19:14:42 +0100 Subject: [PATCH 14/28] as_blob() and is_blob() - `as.blob()` is deprecatd in favor of the new `as_blob()` function. - New `is_blob()`. --- NAMESPACE | 2 ++ R/blob.R | 30 +++++++++++++++++++++++++--- README.Rmd | 6 +++--- README.md | 35 +++++++++++++++++++++------------ man/as.blob.Rd | 15 ++++++++++++++ man/blob.Rd | 16 +++++++++++---- tests/testthat/test-accessors.R | 6 +++--- tests/testthat/test-cast.R | 11 +++++++++++ tests/testthat/test-missing.R | 4 ++-- 9 files changed, 97 insertions(+), 28 deletions(-) create mode 100644 man/as.blob.Rd diff --git a/NAMESPACE b/NAMESPACE index 1248351..67952d2 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -21,7 +21,9 @@ S3method(vec_type2.vctrs_blob,list) S3method(vec_type2.vctrs_blob,vctrs_blob) S3method(vec_type2.vctrs_blob,vctrs_unspecified) export(as.blob) +export(as_blob) export(blob) +export(is_blob) export(new_blob) export(vec_cast.vctrs_blob) export(vec_type2.vctrs_blob) diff --git a/R/blob.R b/R/blob.R index c7938f7..57ef234 100644 --- a/R/blob.R +++ b/R/blob.R @@ -8,8 +8,12 @@ setOldClass(c("blob", "vctrs_blob", "vctrs_vctr")) #' Construct a blob object #' #' `new_blob()` is a low-level constructor that takes a list of -#' raw vectors. `blob()` constructs a blob from individual raw vectors, -#' and `as.blob()` is a S3 generic that converts existing objects. +#' raw vectors. +#' `blob()` constructs a blob from individual raw vectors. +#' `as_blob()` and `is_blob()` are simple forwarders to [vctrs::vec_cast()] +#' and [inherits()], respectively. +#' +#' @seealso [as.blob()] for the legacy interface for specifying casts. #' #' @param ... Individual raw vectors #' @param x A list of raw vectors, or other object to coerce @@ -44,11 +48,31 @@ new_blob <- function(x = list()) { #' @export #' @rdname blob +as_blob <- function(x) { + vec_cast(x, new_blob()) +} + +#' @export +#' @rdname blob +is_blob <- function(x) { + inherits(x, "blob") +} + +#' Deprecated generic +#' +#' The `as.blob()` generic has been deprecated in favor of +#' [vec_cast.vctrs_blob()]. +#' Implement a `vec_cast.vctrs_blob.myclass()` method to support +#' coercing objects of your class to blobs. +#' See [vctrs::vec_cast()] for more detail. +#' +#' @export as.blob <- function(x, ...) { + signal_soft_deprecated("as.blob() is deprecated, use as_blob().") UseMethod("as.blob") } #' @export as.blob.default <- function(x, ...) { - vec_cast(x, new_blob()) + as_blob(x) } diff --git a/README.Rmd b/README.Rmd index e8b866e..952b75a 100644 --- a/README.Rmd +++ b/README.Rmd @@ -16,7 +16,7 @@ knitr::opts_chunk$set( comment = "#>", fig.path = "README-" ) -library(blob) +pkgload::load_all(".") ``` # blob @@ -38,7 +38,7 @@ devtools::install_github("tidyverse/blob") ## Example -To create a blob, use `blob()`, `new_blob()` or `as.blob()`: +To create a blob, use `blob()`, `new_blob()` or `as_blob()`: ```{r example} x1 <- charToRaw("Good morning") @@ -47,5 +47,5 @@ x2 <- as.raw(c(0x48, 0x65, 0x6c, 0x6c, 0x6f)) new_blob(list(x1, x2)) blob(x1, x2) -as.blob(c("Good morning", "Good evening")) +as_blob(c("Good morning", "Good evening")) ``` diff --git a/README.md b/README.md index 05c8763..7c20804 100644 --- a/README.md +++ b/README.md @@ -1,16 +1,23 @@ -[![Travis-CI Build Status](https://travis-ci.org/tidyverse/blob.svg?branch=master)](https://travis-ci.org/tidyverse/blob) [![CRAN\_Status\_Badge](http://www.r-pkg.org/badges/version/blob)](https://cran.r-project.org/package=blob) [![Coverage Status](https://codecov.io/gh/tidyverse/blob/branch/master/graph/badge.svg)](https://codecov.io/github/tidyverse/blob?branch=master) +[![Travis-CI Build +Status](https://travis-ci.org/tidyverse/blob.svg?branch=master)](https://travis-ci.org/tidyverse/blob) +[![CRAN\_Status\_Badge](http://www.r-pkg.org/badges/version/blob)](https://cran.r-project.org/package=blob) +[![Coverage +Status](https://codecov.io/gh/tidyverse/blob/branch/master/graph/badge.svg)](https://codecov.io/github/tidyverse/blob?branch=master) -blob -==== -The goal of blob is to provide a simple S3 class to represent a vector of binary objects, aka blobs. The `blob` class is a lightweight wrapper around a list of raw vectors, suitable for inclusion in a data frame. +# blob -In most cases you will not need to use this package explicitly: it will be used transparently by packages that need to load BLOB columns from databases or binary file formats. +The goal of blob is to provide a simple S3 class to represent a vector +of binary objects, aka blobs. The `blob` class is a lightweight wrapper +around a list of raw vectors, suitable for inclusion in a data frame. -Installation ------------- +In most cases you will not need to use this package explicitly: it will +be used transparently by packages that need to load BLOB columns from +databases or binary file formats. + +## Installation You can install blob from github with: @@ -19,20 +26,22 @@ You can install blob from github with: devtools::install_github("tidyverse/blob") ``` -Example -------- +## Example -To create a blob, use `blob()`, `new_blob()` or `as.blob()`: +To create a blob, use `blob()`, `new_blob()` or `as_blob()`: ``` r x1 <- charToRaw("Good morning") x2 <- as.raw(c(0x48, 0x65, 0x6c, 0x6c, 0x6f)) new_blob(list(x1, x2)) -#> [1] blob[12 B] blob[5 B] +#> +#> [1] blob[12 B] blob[ 5 B] blob(x1, x2) -#> [1] blob[12 B] blob[5 B] +#> +#> [1] blob[12 B] blob[ 5 B] -as.blob(c("Good morning", "Good evening")) +as_blob(c("Good morning", "Good evening")) +#> #> [1] blob[12 B] blob[12 B] ``` diff --git a/man/as.blob.Rd b/man/as.blob.Rd new file mode 100644 index 0000000..4d9ecbb --- /dev/null +++ b/man/as.blob.Rd @@ -0,0 +1,15 @@ +% Generated by roxygen2: do not edit by hand +% Please edit documentation in R/blob.R +\name{as.blob} +\alias{as.blob} +\title{Deprecated generic} +\usage{ +as.blob(x, ...) +} +\description{ +The \code{as.blob()} generic has been deprecated in favor of +\code{\link[=vec_cast.vctrs_blob]{vec_cast.vctrs_blob()}}. +Implement a \code{vec_cast.vctrs_blob.myclass()} method to support +coercing objects of your class to blobs. +See \code{\link[vctrs:vec_cast]{vctrs::vec_cast()}} for more detail. +} diff --git a/man/blob.Rd b/man/blob.Rd index a986a95..db76d8f 100644 --- a/man/blob.Rd +++ b/man/blob.Rd @@ -3,14 +3,17 @@ \name{blob} \alias{blob} \alias{new_blob} -\alias{as.blob} +\alias{as_blob} +\alias{is_blob} \title{Construct a blob object} \usage{ blob(...) new_blob(x = list()) -as.blob(x, ...) +as_blob(x) + +is_blob(x) } \arguments{ \item{...}{Individual raw vectors} @@ -19,8 +22,10 @@ as.blob(x, ...) } \description{ \code{new_blob()} is a low-level constructor that takes a list of -raw vectors. \code{blob()} constructs a blob from individual raw vectors, -and \code{as.blob()} is a S3 generic that converts existing objects. +raw vectors. +\code{blob()} constructs a blob from individual raw vectors. +\code{as_blob()} and \code{is_blob()} are simple forwarders to \code{\link[vctrs:vec_cast]{vctrs::vec_cast()}} +and \code{\link[=inherits]{inherits()}}, respectively. } \examples{ x1 <- charToRaw("Good morning") @@ -31,3 +36,6 @@ blob(x1, x2) as.blob(c("Good morning", "Good evening")) } +\seealso{ +\code{\link[=as.blob]{as.blob()}} for the legacy interface for specifying casts. +} diff --git a/tests/testthat/test-accessors.R b/tests/testthat/test-accessors.R index 377cf59..d7fc608 100644 --- a/tests/testthat/test-accessors.R +++ b/tests/testthat/test-accessors.R @@ -1,19 +1,19 @@ context("accessors") test_that("subsetting blob returns blob", { - x <- as.blob(1:5) + x <- as_blob(1:5) expect_s3_class(x[1], "blob") }) test_that("can't insert objects of incorrect type", { - x <- as.blob(1:5) + x <- as_blob(1:5) expect_error(x[[1]] <- 1, "RHS must be raw vector or NULL", fixed = TRUE) expect_error(x[1] <- 1, "Can't cast to ", fixed = TRUE) }) test_that("can insert raw or NULL", { - x <- as.blob(1:4) + x <- as_blob(1:4) x[[1]] <- as.raw(0) x[2] <- list(as.raw(0)) diff --git a/tests/testthat/test-cast.R b/tests/testthat/test-cast.R index 1e7ffb1..84b7437 100644 --- a/tests/testthat/test-cast.R +++ b/tests/testthat/test-cast.R @@ -1,9 +1,20 @@ context("test-cast") test_that("casting with as.blob()", { + # Deprecated in v1.2.0 + scoped_lifecycle_silence() + expect_identical(as.blob(blob(raw(1))), blob(raw(1))) expect_identical(as.blob(list(raw(1))), blob(raw(1))) expect_identical(as.blob(raw(1)), blob(raw(1))) expect_identical(as.blob(1:3), blob(as.raw(1), as.raw(2), as.raw(3))) expect_identical(as.blob(c("abc", "def")), blob(charToRaw("abc"), charToRaw("def"))) }) + +test_that("casting with as_blob()", { + expect_identical(as_blob(blob(raw(1))), blob(raw(1))) + expect_identical(as_blob(list(raw(1))), blob(raw(1))) + expect_identical(as_blob(raw(1)), blob(raw(1))) + expect_identical(as_blob(1:3), blob(as.raw(1), as.raw(2), as.raw(3))) + expect_identical(as_blob(c("abc", "def")), blob(charToRaw("abc"), charToRaw("def"))) +}) diff --git a/tests/testthat/test-missing.R b/tests/testthat/test-missing.R index 9af242f..a0e02ad 100644 --- a/tests/testthat/test-missing.R +++ b/tests/testthat/test-missing.R @@ -6,14 +6,14 @@ test_that("is.na detects nulls", { }) test_that("is.na<- sets missing values", { - x <- as.blob(1:4) + x <- as_blob(1:4) is.na(x) <- (1:4 %% 2 == 0) expect_equal(x, blob(as.raw(1), NULL, as.raw(3), NULL)) }) test_that("is.na<- error", { - x <- as.blob(1:4) + x <- as_blob(1:4) expect_error(is.na(x) <- rep(TRUE, 26)) expect_error(is.na(x) <- letters[1:4]) }) From 4fbfa5129db1a8a082f80267f13322eaf30adfa6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kirill=20M=C3=BCller?= Date: Wed, 16 Jan 2019 15:35:39 +0100 Subject: [PATCH 15/28] Proper abbreviations --- NAMESPACE | 3 ++- R/format.R | 7 ++++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/NAMESPACE b/NAMESPACE index 67952d2..8b2b115 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -13,7 +13,8 @@ S3method(vec_cast.vctrs_blob,list) S3method(vec_cast.vctrs_blob,logical) S3method(vec_cast.vctrs_blob,raw) S3method(vec_cast.vctrs_blob,vctrs_blob) -S3method(vec_ptype_abbr,vctrs_percent) +S3method(vec_ptype_abbr,vctrs_blob) +S3method(vec_ptype_full,vctrs_blob) S3method(vec_type2,vctrs_blob) S3method(vec_type2.list,vctrs_blob) S3method(vec_type2.vctrs_blob,default) diff --git a/R/format.R b/R/format.R index fa45e3b..675d474 100644 --- a/R/format.R +++ b/R/format.R @@ -7,7 +7,12 @@ format.blob <- function(x, ...) { } #' @export -vec_ptype_abbr.vctrs_percent <- function(x) { +vec_ptype_abbr.vctrs_blob <- function(x) { + "blob" +} + +#' @export +vec_ptype_full.vctrs_blob <- function(x) { "blob" } From a9e4ece9bf1c00f56c5e4cc4f908954209d8fe71 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kirill=20M=C3=BCller?= Date: Wed, 16 Jan 2019 15:35:48 +0100 Subject: [PATCH 16/28] Use s3_register() --- R/zzz.R | 28 ++-------------------------- 1 file changed, 2 insertions(+), 26 deletions(-) diff --git a/R/zzz.R b/R/zzz.R index 6d65e79..ca5eca6 100644 --- a/R/zzz.R +++ b/R/zzz.R @@ -1,32 +1,8 @@ # nocov start .onLoad <- function(...) { - register_s3_method("pillar", "pillar_shaft", "blob") - register_s3_method("pillar", "is_vector_s3", "blob") + s3_register("pillar::pillar_shaft", "blob") + s3_register("pillar::is_vector_s3", "blob") invisible() } - -register_s3_method <- function(pkg, generic, class, fun = NULL) { - stopifnot(is.character(pkg), length(pkg) == 1) - stopifnot(is.character(generic), length(generic) == 1) - stopifnot(is.character(class), length(class) == 1) - - if (is.null(fun)) { - fun <- get(paste0(generic, ".", class), envir = parent.frame()) - } else { - stopifnot(is.function(fun)) - } - - if (pkg %in% loadedNamespaces()) { - registerS3method(generic, class, fun, envir = asNamespace(pkg)) - } - - # Always register hook in case package is later unloaded & reloaded - setHook( - packageEvent(pkg, "onLoad"), - function(...) { - registerS3method(generic, class, fun, envir = asNamespace(pkg)) - } - ) -} # nocov end From 0715ff1fc8eaa72455963c32c352029983fee336 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kirill=20M=C3=BCller?= Date: Sun, 20 Jan 2019 09:28:32 -0600 Subject: [PATCH 17/28] Remove vctrs_blob class --- NAMESPACE | 38 +++++++++---------- R/blob.R | 8 ++-- R/cast.R | 38 +++++++++---------- R/coerce.R | 26 ++++++------- R/format.R | 4 +- man/as.blob.Rd | 4 +- ...ec_cast.vctrs_blob.Rd => vec_cast.blob.Rd} | 6 +-- ..._type2.vctrs_blob.Rd => vec_type2.blob.Rd} | 6 +-- 8 files changed, 65 insertions(+), 65 deletions(-) rename man/{vec_cast.vctrs_blob.Rd => vec_cast.blob.Rd} (78%) rename man/{vec_type2.vctrs_blob.Rd => vec_type2.blob.Rd} (76%) diff --git a/NAMESPACE b/NAMESPACE index 8b2b115..afd9ed2 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -4,30 +4,30 @@ S3method("[[<-",blob) S3method("is.na<-",blob) S3method(as.blob,default) S3method(format,blob) -S3method(vec_cast,vctrs_blob) -S3method(vec_cast.list,vctrs_blob) -S3method(vec_cast.vctrs_blob,character) -S3method(vec_cast.vctrs_blob,default) -S3method(vec_cast.vctrs_blob,integer) -S3method(vec_cast.vctrs_blob,list) -S3method(vec_cast.vctrs_blob,logical) -S3method(vec_cast.vctrs_blob,raw) -S3method(vec_cast.vctrs_blob,vctrs_blob) -S3method(vec_ptype_abbr,vctrs_blob) -S3method(vec_ptype_full,vctrs_blob) -S3method(vec_type2,vctrs_blob) -S3method(vec_type2.list,vctrs_blob) -S3method(vec_type2.vctrs_blob,default) -S3method(vec_type2.vctrs_blob,list) -S3method(vec_type2.vctrs_blob,vctrs_blob) -S3method(vec_type2.vctrs_blob,vctrs_unspecified) +S3method(vec_cast,blob) +S3method(vec_cast.blob,blob) +S3method(vec_cast.blob,character) +S3method(vec_cast.blob,default) +S3method(vec_cast.blob,integer) +S3method(vec_cast.blob,list) +S3method(vec_cast.blob,logical) +S3method(vec_cast.blob,raw) +S3method(vec_cast.list,blob) +S3method(vec_ptype_abbr,blob) +S3method(vec_ptype_full,blob) +S3method(vec_type2,blob) +S3method(vec_type2.blob,blob) +S3method(vec_type2.blob,default) +S3method(vec_type2.blob,list) +S3method(vec_type2.blob,vctrs_unspecified) +S3method(vec_type2.list,blob) export(as.blob) export(as_blob) export(blob) export(is_blob) export(new_blob) -export(vec_cast.vctrs_blob) -export(vec_type2.vctrs_blob) +export(vec_cast.blob) +export(vec_type2.blob) import(rlang) import(vctrs) importFrom(methods,setOldClass) diff --git a/R/blob.R b/R/blob.R index 57ef234..1260506 100644 --- a/R/blob.R +++ b/R/blob.R @@ -3,7 +3,7 @@ NULL #' @importFrom methods setOldClass -setOldClass(c("blob", "vctrs_blob", "vctrs_vctr")) +setOldClass(c("blob", "vctrs_vctr")) #' Construct a blob object #' @@ -43,7 +43,7 @@ check_raw_list <- function(x) { #' @rdname blob new_blob <- function(x = list()) { vec_assert(x, list()) - new_vctr(x, class = c("blob", "vctrs_blob")) + new_vctr(x, class = "blob") } #' @export @@ -61,8 +61,8 @@ is_blob <- function(x) { #' Deprecated generic #' #' The `as.blob()` generic has been deprecated in favor of -#' [vec_cast.vctrs_blob()]. -#' Implement a `vec_cast.vctrs_blob.myclass()` method to support +#' [vec_cast.blob()]. +#' Implement a `vec_cast.blob.myclass()` method to support #' coercing objects of your class to blobs. #' See [vctrs::vec_cast()] for more detail. #' diff --git a/R/cast.R b/R/cast.R index 06b0dba..91136a5 100644 --- a/R/cast.R +++ b/R/cast.R @@ -4,39 +4,39 @@ #' #' @inheritParams vctrs::vec_cast #' -#' @method vec_cast vctrs_blob +#' @method vec_cast blob #' @export -#' @export vec_cast.vctrs_blob -vec_cast.vctrs_blob <- function(x, to) UseMethod("vec_cast.vctrs_blob") +#' @export vec_cast.blob +vec_cast.blob <- function(x, to) UseMethod("vec_cast.blob") -#' @method vec_cast.vctrs_blob default +#' @method vec_cast.blob default #' @export -vec_cast.vctrs_blob.default <- function(x, to) stop_incompatible_cast(x, to) +vec_cast.blob.default <- function(x, to) stop_incompatible_cast(x, to) -#' @method vec_cast.vctrs_blob logical +#' @method vec_cast.blob logical #' @export -vec_cast.vctrs_blob.logical <- function(x, to) vec_unspecified_cast(x, to) +vec_cast.blob.logical <- function(x, to) vec_unspecified_cast(x, to) -#' @method vec_cast.vctrs_blob vctrs_blob +#' @method vec_cast.blob blob #' @export -vec_cast.vctrs_blob.vctrs_blob <- function(x, to) x +vec_cast.blob.blob <- function(x, to) x -#' @method vec_cast.vctrs_blob list +#' @method vec_cast.blob list #' @export -vec_cast.vctrs_blob.list <- function(x, to) blob(!!!x) +vec_cast.blob.list <- function(x, to) blob(!!!x) -#' @method vec_cast.vctrs_blob integer +#' @method vec_cast.blob integer #' @export -vec_cast.vctrs_blob.integer <- function(x, to) blob(!!!lapply(x, as.raw)) +vec_cast.blob.integer <- function(x, to) blob(!!!lapply(x, as.raw)) -#' @method vec_cast.vctrs_blob raw +#' @method vec_cast.blob raw #' @export -vec_cast.vctrs_blob.raw <- function(x, to) blob(x) +vec_cast.blob.raw <- function(x, to) blob(x) -#' @method vec_cast.vctrs_blob character +#' @method vec_cast.blob character #' @export -vec_cast.vctrs_blob.character <- function(x, to) blob(!!!lapply(x, charToRaw)) +vec_cast.blob.character <- function(x, to) blob(!!!lapply(x, charToRaw)) -#' @method vec_cast.list vctrs_blob +#' @method vec_cast.list blob #' @export -vec_cast.list.vctrs_blob <- function(x, to) vec_data(x) +vec_cast.list.blob <- function(x, to) vec_data(x) diff --git a/R/coerce.R b/R/coerce.R index de3e97b..933260c 100644 --- a/R/coerce.R +++ b/R/coerce.R @@ -4,35 +4,35 @@ #' #' @inheritParams vctrs::vec_type2 #' -#' @method vec_type2 vctrs_blob +#' @method vec_type2 blob #' @export -#' @export vec_type2.vctrs_blob -vec_type2.vctrs_blob <- function(x, y) UseMethod("vec_type2.vctrs_blob", y) +#' @export vec_type2.blob +vec_type2.blob <- function(x, y) UseMethod("vec_type2.blob", y) -#' @method vec_type2.vctrs_blob default +#' @method vec_type2.blob default #' @export -vec_type2.vctrs_blob.default <- function(x, y) stop_incompatible_type(x, y) +vec_type2.blob.default <- function(x, y) stop_incompatible_type(x, y) -#' @method vec_type2.vctrs_blob vctrs_blob +#' @method vec_type2.blob blob #' @export -vec_type2.vctrs_blob.vctrs_blob <- function(x, y) { +vec_type2.blob.blob <- function(x, y) { new_blob(list()) } -#' @method vec_type2.vctrs_blob vctrs_unspecified +#' @method vec_type2.blob vctrs_unspecified #' @export -vec_type2.vctrs_blob.vctrs_unspecified <- function(x, y) x +vec_type2.blob.vctrs_unspecified <- function(x, y) x -#' @method vec_type2.vctrs_blob list +#' @method vec_type2.blob list #' @export -vec_type2.vctrs_blob.list <- function(x, y) { +vec_type2.blob.list <- function(x, y) { check_raw_list(y) new_blob(list()) } -#' @method vec_type2.list vctrs_blob +#' @method vec_type2.list blob #' @export -vec_type2.list.vctrs_blob <- function(x, y) { +vec_type2.list.blob <- function(x, y) { check_raw_list(x) new_blob(list()) } diff --git a/R/format.R b/R/format.R index 675d474..ef80e84 100644 --- a/R/format.R +++ b/R/format.R @@ -7,12 +7,12 @@ format.blob <- function(x, ...) { } #' @export -vec_ptype_abbr.vctrs_blob <- function(x) { +vec_ptype_abbr.blob <- function(x) { "blob" } #' @export -vec_ptype_full.vctrs_blob <- function(x) { +vec_ptype_full.blob <- function(x) { "blob" } diff --git a/man/as.blob.Rd b/man/as.blob.Rd index 4d9ecbb..5e5022c 100644 --- a/man/as.blob.Rd +++ b/man/as.blob.Rd @@ -8,8 +8,8 @@ as.blob(x, ...) } \description{ The \code{as.blob()} generic has been deprecated in favor of -\code{\link[=vec_cast.vctrs_blob]{vec_cast.vctrs_blob()}}. -Implement a \code{vec_cast.vctrs_blob.myclass()} method to support +\code{\link[=vec_cast.blob]{vec_cast.blob()}}. +Implement a \code{vec_cast.blob.myclass()} method to support coercing objects of your class to blobs. See \code{\link[vctrs:vec_cast]{vctrs::vec_cast()}} for more detail. } diff --git a/man/vec_cast.vctrs_blob.Rd b/man/vec_cast.blob.Rd similarity index 78% rename from man/vec_cast.vctrs_blob.Rd rename to man/vec_cast.blob.Rd index c9b7cdb..dea8bb7 100644 --- a/man/vec_cast.vctrs_blob.Rd +++ b/man/vec_cast.blob.Rd @@ -1,10 +1,10 @@ % Generated by roxygen2: do not edit by hand % Please edit documentation in R/cast.R -\name{vec_cast.vctrs_blob} -\alias{vec_cast.vctrs_blob} +\name{vec_cast.blob} +\alias{vec_cast.blob} \title{Casting} \usage{ -\method{vec_cast}{vctrs_blob}(x, to) +\method{vec_cast}{blob}(x, to) } \arguments{ \item{x}{Vectors to cast.} diff --git a/man/vec_type2.vctrs_blob.Rd b/man/vec_type2.blob.Rd similarity index 76% rename from man/vec_type2.vctrs_blob.Rd rename to man/vec_type2.blob.Rd index 76ee737..5d3b928 100644 --- a/man/vec_type2.vctrs_blob.Rd +++ b/man/vec_type2.blob.Rd @@ -1,10 +1,10 @@ % Generated by roxygen2: do not edit by hand % Please edit documentation in R/coerce.R -\name{vec_type2.vctrs_blob} -\alias{vec_type2.vctrs_blob} +\name{vec_type2.blob} +\alias{vec_type2.blob} \title{Coercion} \usage{ -\method{vec_type2}{vctrs_blob}(x, y) +\method{vec_type2}{blob}(x, y) } \arguments{ \item{x}{Either vector types; i.e.} From c67c462a21f3e32184329b1dd9e4070cff805e2b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kirill=20M=C3=BCller?= Date: Sun, 20 Jan 2019 09:49:59 -0600 Subject: [PATCH 18/28] Use vctrs_list_of --- R/blob.R | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/R/blob.R b/R/blob.R index 1260506..33c62a9 100644 --- a/R/blob.R +++ b/R/blob.R @@ -3,7 +3,7 @@ NULL #' @importFrom methods setOldClass -setOldClass(c("blob", "vctrs_vctr")) +setOldClass(c("blob", "vctrs_list_of", "vctrs_vctr")) #' Construct a blob object #' @@ -43,7 +43,7 @@ check_raw_list <- function(x) { #' @rdname blob new_blob <- function(x = list()) { vec_assert(x, list()) - new_vctr(x, class = "blob") + new_list_of(x, ptype = raw(), class = "blob") } #' @export From 89269327cd805327d01a8a3a585ffcc23004b07a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kirill=20M=C3=BCller?= Date: Sun, 20 Jan 2019 09:58:55 -0600 Subject: [PATCH 19/28] Remove [[<- --- NAMESPACE | 1 - R/accessors.R | 17 ----------------- tests/testthat/test-accessors.R | 2 +- 3 files changed, 1 insertion(+), 19 deletions(-) delete mode 100644 R/accessors.R diff --git a/NAMESPACE b/NAMESPACE index afd9ed2..1c014c7 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -1,6 +1,5 @@ # Generated by roxygen2: do not edit by hand -S3method("[[<-",blob) S3method("is.na<-",blob) S3method(as.blob,default) S3method(format,blob) diff --git a/R/accessors.R b/R/accessors.R deleted file mode 100644 index eb6f48f..0000000 --- a/R/accessors.R +++ /dev/null @@ -1,17 +0,0 @@ -# Required, because blob wraps a list, and the default implementation -# doesn't cast if the underlying type is a list. -#' @export -`[[<-.blob` <- function(x, i, ..., value) { - if (!is.raw(value) && !is.null(value)) { - stop("RHS must be raw vector or NULL", call. = FALSE) - } - - if (is.null(value)) { - # Setting to NULL via [[ shortens the list! Example: - # `[[<-`(list(1), 1, NULL) - x[i] <- list(NULL) - x - } else { - NextMethod() - } -} diff --git a/tests/testthat/test-accessors.R b/tests/testthat/test-accessors.R index d7fc608..8db6fdd 100644 --- a/tests/testthat/test-accessors.R +++ b/tests/testthat/test-accessors.R @@ -8,7 +8,7 @@ test_that("subsetting blob returns blob", { test_that("can't insert objects of incorrect type", { x <- as_blob(1:5) - expect_error(x[[1]] <- 1, "RHS must be raw vector or NULL", fixed = TRUE) + expect_error(x[[1]] <- 1, "Can't cast to ", fixed = TRUE) expect_error(x[1] <- 1, "Can't cast to ", fixed = TRUE) }) From 5e3514e5d88ad5f6963965f0d65f1cbfef040f88 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kirill=20M=C3=BCller?= Date: Sun, 20 Jan 2019 11:20:37 -0600 Subject: [PATCH 20/28] - Deprecate as_blob.integer(). --- R/cast.R | 5 ++++- R/util.R | 4 ++++ tests/testthat/test-accessors.R | 6 +++--- tests/testthat/test-cast.R | 2 +- tests/testthat/test-missing.R | 6 +++--- 5 files changed, 15 insertions(+), 8 deletions(-) diff --git a/R/cast.R b/R/cast.R index 91136a5..255880a 100644 --- a/R/cast.R +++ b/R/cast.R @@ -27,7 +27,10 @@ vec_cast.blob.list <- function(x, to) blob(!!!x) #' @method vec_cast.blob integer #' @export -vec_cast.blob.integer <- function(x, to) blob(!!!lapply(x, as.raw)) +vec_cast.blob.integer <- function(x, to) { + warn_deprecated("Coercing an integer vector to a blob is deprecated, please coerce to a list first.") + blob(!!!lapply(x, as_single_raw)) +} #' @method vec_cast.blob raw #' @export diff --git a/R/util.R b/R/util.R index cd149d5..673aaac 100644 --- a/R/util.R +++ b/R/util.R @@ -10,3 +10,7 @@ is_raw_list <- function(x) { TRUE } + +as_single_raw <- function(x) { + if (is.na(x)) NULL else as.raw(x) +} diff --git a/tests/testthat/test-accessors.R b/tests/testthat/test-accessors.R index 8db6fdd..b7b7f60 100644 --- a/tests/testthat/test-accessors.R +++ b/tests/testthat/test-accessors.R @@ -1,19 +1,19 @@ context("accessors") test_that("subsetting blob returns blob", { - x <- as_blob(1:5) + x <- blob(!!!as.raw(1:5)) expect_s3_class(x[1], "blob") }) test_that("can't insert objects of incorrect type", { - x <- as_blob(1:5) + x <- blob(!!!as.raw(1:5)) expect_error(x[[1]] <- 1, "Can't cast to ", fixed = TRUE) expect_error(x[1] <- 1, "Can't cast to ", fixed = TRUE) }) test_that("can insert raw or NULL", { - x <- as_blob(1:4) + x <- blob(!!!as.raw(1:4)) x[[1]] <- as.raw(0) x[2] <- list(as.raw(0)) diff --git a/tests/testthat/test-cast.R b/tests/testthat/test-cast.R index 84b7437..a0daa09 100644 --- a/tests/testthat/test-cast.R +++ b/tests/testthat/test-cast.R @@ -15,6 +15,6 @@ test_that("casting with as_blob()", { expect_identical(as_blob(blob(raw(1))), blob(raw(1))) expect_identical(as_blob(list(raw(1))), blob(raw(1))) expect_identical(as_blob(raw(1)), blob(raw(1))) - expect_identical(as_blob(1:3), blob(as.raw(1), as.raw(2), as.raw(3))) + expect_identical(blob(!!!as.raw(1:3)), blob(as.raw(1), as.raw(2), as.raw(3))) expect_identical(as_blob(c("abc", "def")), blob(charToRaw("abc"), charToRaw("def"))) }) diff --git a/tests/testthat/test-missing.R b/tests/testthat/test-missing.R index a0e02ad..16013f5 100644 --- a/tests/testthat/test-missing.R +++ b/tests/testthat/test-missing.R @@ -6,14 +6,14 @@ test_that("is.na detects nulls", { }) test_that("is.na<- sets missing values", { - x <- as_blob(1:4) + x <- blob(!!!as.raw(1:4)) is.na(x) <- (1:4 %% 2 == 0) expect_equal(x, blob(as.raw(1), NULL, as.raw(3), NULL)) }) -test_that("is.na<- error", { - x <- as_blob(1:4) +test_that("is.na<- errors", { + x <- blob(!!!as.raw(1:4)) expect_error(is.na(x) <- rep(TRUE, 26)) expect_error(is.na(x) <- letters[1:4]) }) From 3e81ecb9d9bdf258a5257001f748ef550e49fd26 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kirill=20M=C3=BCller?= Date: Sun, 20 Jan 2019 11:25:33 -0600 Subject: [PATCH 21/28] Remove is.na<-() --- NAMESPACE | 1 - R/missing.R | 10 ---------- tests/testthat/test-missing.R | 11 ++++++++--- 3 files changed, 8 insertions(+), 14 deletions(-) delete mode 100644 R/missing.R diff --git a/NAMESPACE b/NAMESPACE index 1c014c7..eb82433 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -1,6 +1,5 @@ # Generated by roxygen2: do not edit by hand -S3method("is.na<-",blob) S3method(as.blob,default) S3method(format,blob) S3method(vec_cast,blob) diff --git a/R/missing.R b/R/missing.R deleted file mode 100644 index 63b59af..0000000 --- a/R/missing.R +++ /dev/null @@ -1,10 +0,0 @@ -# No implementation in vctrs 0.1.0 -#' @export -`is.na<-.blob` <- function(x, value) { - if (!is.logical(value) || length(x) != length(value)) { - stop("RHS must be a logical the same length as `x`", call. = FALSE) - } - - x[value] <- list(NULL) - x -} diff --git a/tests/testthat/test-missing.R b/tests/testthat/test-missing.R index 16013f5..0d8e5aa 100644 --- a/tests/testthat/test-missing.R +++ b/tests/testthat/test-missing.R @@ -12,8 +12,13 @@ test_that("is.na<- sets missing values", { expect_equal(x, blob(as.raw(1), NULL, as.raw(3), NULL)) }) -test_that("is.na<- errors", { +test_that("is.na<- auto-expansion for logical indexes", { x <- blob(!!!as.raw(1:4)) - expect_error(is.na(x) <- rep(TRUE, 26)) - expect_error(is.na(x) <- letters[1:4]) + is.na(x) <- rep(TRUE, 5) + expect_identical(x, rep(blob(NULL), 5)) +}) + +test_that("is.na<- auto-expansion for character indices", { + x <- blob(!!!as.raw(1:4)) + expect_error(is.na(x) <- letters[1:2]) }) From 140c9955d08da07671d240497b2cb32cdacd09e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kirill=20M=C3=BCller?= Date: Sun, 20 Jan 2019 11:26:05 -0600 Subject: [PATCH 22/28] Add tests --- tests/testthat/test-accessors.R | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/tests/testthat/test-accessors.R b/tests/testthat/test-accessors.R index b7b7f60..20bc37d 100644 --- a/tests/testthat/test-accessors.R +++ b/tests/testthat/test-accessors.R @@ -5,6 +5,22 @@ test_that("subsetting blob returns blob", { expect_s3_class(x[1], "blob") }) +test_that("subsetting can return NA", { + x <- blob(!!!as.raw(1:5)) + expect_identical(x[6], blob(NULL)) + expect_identical(x[5:6], blob(as.raw(5L), NULL)) +}) + +test_that("subset assignment works", { + x <- blob(!!!as.raw(1:5)) + x[3] <- blob(raw(1)) + expect_identical(x, blob(!!!as.raw(c(1:2, 0L, 4:5)))) + x[[4]] <- raw(1) + expect_identical(x, blob(!!!as.raw(c(1:2, 0L, 0L, 5L)))) + x[7] <- blob(raw(1)) + expect_identical(x, blob(!!!as.raw(c(1:2, 0L, 0L, 5L)), NULL, raw(1))) +}) + test_that("can't insert objects of incorrect type", { x <- blob(!!!as.raw(1:5)) From 059f9a3328105d2f2bfb7da642ea92e9410e51a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kirill=20M=C3=BCller?= Date: Tue, 29 Jan 2019 00:42:26 +0100 Subject: [PATCH 23/28] Final tweaks --- tests/testthat/test-construction.R | 2 +- tests/testthat/test-missing.R | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/tests/testthat/test-construction.R b/tests/testthat/test-construction.R index 560d2d8..415a2e1 100644 --- a/tests/testthat/test-construction.R +++ b/tests/testthat/test-construction.R @@ -1,7 +1,7 @@ context("construction") test_that("input must be list of raw blobs", { - expect_error(new_blob(1), "`x` must be , not .") + expect_error(new_blob(1), "`1` must be , not .") expect_error(blob(1), "must be a list of raw vectors") expect_error(blob(1, as.raw(1)), "must be a list of raw vectors") }) diff --git a/tests/testthat/test-missing.R b/tests/testthat/test-missing.R index 0d8e5aa..7753b4e 100644 --- a/tests/testthat/test-missing.R +++ b/tests/testthat/test-missing.R @@ -14,8 +14,7 @@ test_that("is.na<- sets missing values", { test_that("is.na<- auto-expansion for logical indexes", { x <- blob(!!!as.raw(1:4)) - is.na(x) <- rep(TRUE, 5) - expect_identical(x, rep(blob(NULL), 5)) + expect_error(is.na(x) <- rep(TRUE, 5)) }) test_that("is.na<- auto-expansion for character indices", { From 1212c24f9ee18d536b969dbe5300c203da432bd6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kirill=20M=C3=BCller?= Date: Tue, 29 Jan 2019 00:42:58 +0100 Subject: [PATCH 24/28] Add remote --- DESCRIPTION | 2 ++ 1 file changed, 2 insertions(+) diff --git a/DESCRIPTION b/DESCRIPTION index 42e724f..59ad7ed 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -28,6 +28,8 @@ Suggests: covr, pillar (>= 1.2.1), testthat +Remotes: + krlmlr/vctrs@f-blob-2 Encoding: UTF-8 LazyData: true Roxygen: list(markdown = TRUE, roclets = c("collate", "namespace", "rd", "pkgapi::api_roclet")) From c15672754f8f8d0818625113268420e3cd9ea532 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kirill=20M=C3=BCller?= Date: Tue, 29 Jan 2019 00:52:02 +0100 Subject: [PATCH 25/28] Declare crayon dependency --- DESCRIPTION | 1 + 1 file changed, 1 insertion(+) diff --git a/DESCRIPTION b/DESCRIPTION index 59ad7ed..5dd3e1c 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -26,6 +26,7 @@ Imports: vctrs Suggests: covr, + crayon, pillar (>= 1.2.1), testthat Remotes: From 40259ee95b826b171bbf850619bf564e68b30d2c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kirill=20M=C3=BCller?= Date: Tue, 29 Jan 2019 00:52:08 +0100 Subject: [PATCH 26/28] Document params --- R/blob.R | 3 +++ man/as.blob.Rd | 5 +++++ 2 files changed, 8 insertions(+) diff --git a/R/blob.R b/R/blob.R index 33c62a9..676af23 100644 --- a/R/blob.R +++ b/R/blob.R @@ -66,6 +66,9 @@ is_blob <- function(x) { #' coercing objects of your class to blobs. #' See [vctrs::vec_cast()] for more detail. #' +#' @param x An object. +#' @param ... Passed on to methods. +#' #' @export as.blob <- function(x, ...) { signal_soft_deprecated("as.blob() is deprecated, use as_blob().") diff --git a/man/as.blob.Rd b/man/as.blob.Rd index 5e5022c..b896500 100644 --- a/man/as.blob.Rd +++ b/man/as.blob.Rd @@ -6,6 +6,11 @@ \usage{ as.blob(x, ...) } +\arguments{ +\item{x}{An object.} + +\item{...}{Passed on to methods.} +} \description{ The \code{as.blob()} generic has been deprecated in favor of \code{\link[=vec_cast.blob]{vec_cast.blob()}}. From 309b71ff8640d8f4d5c861d9bb6436c33fad505f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kirill=20M=C3=BCller?= Date: Sat, 9 Feb 2019 15:52:02 +0100 Subject: [PATCH 27/28] Use dev version of vctrs --- DESCRIPTION | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/DESCRIPTION b/DESCRIPTION index 5dd3e1c..f77d223 100644 --- a/DESCRIPTION +++ b/DESCRIPTION @@ -30,7 +30,7 @@ Suggests: pillar (>= 1.2.1), testthat Remotes: - krlmlr/vctrs@f-blob-2 + r-lib/vctrs Encoding: UTF-8 LazyData: true Roxygen: list(markdown = TRUE, roclets = c("collate", "namespace", "rd", "pkgapi::api_roclet")) From a0d96dbfa81fcb69d54d6c088badfa1a5310dfe5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kirill=20M=C3=BCller?= Date: Sat, 9 Feb 2019 17:03:39 +0100 Subject: [PATCH 28/28] Printing --- NAMESPACE | 1 + R/format.R | 11 +++++++++++ README.md | 2 ++ tests/testthat/blob.txt | 1 + 4 files changed, 15 insertions(+) diff --git a/NAMESPACE b/NAMESPACE index eb82433..3b1499a 100644 --- a/NAMESPACE +++ b/NAMESPACE @@ -2,6 +2,7 @@ S3method(as.blob,default) S3method(format,blob) +S3method(obj_print_data,blob) S3method(vec_cast,blob) S3method(vec_cast.blob,blob) S3method(vec_cast.blob,character) diff --git a/R/format.R b/R/format.R index ef80e84..55c1d28 100644 --- a/R/format.R +++ b/R/format.R @@ -6,6 +6,17 @@ format.blob <- function(x, ...) { ifelse(is.na(x), "", paste0("blob[", blob_size(x, ...), "]")) } +#' @export +obj_print_data.blob <- function(x, ...) { + if (length(x) == 0) + return() + + out <- stats::setNames(format(x), names(x)) + print(out, quote = FALSE) + + invisible(x) +} + #' @export vec_ptype_abbr.blob <- function(x) { "blob" diff --git a/README.md b/README.md index 56d4e00..10a0667 100644 --- a/README.md +++ b/README.md @@ -9,6 +9,8 @@ Status](https://codecov.io/gh/tidyverse/blob/branch/master/graph/badge.svg)](htt # blob +## Overview + The goal of blob is to provide a simple S3 class to represent a vector of binary objects, aka blobs. The `blob` class is a lightweight wrapper around a list of raw vectors, suitable for inclusion in a data frame. diff --git a/tests/testthat/blob.txt b/tests/testthat/blob.txt index 4b88767..1bd6302 100644 --- a/tests/testthat/blob.txt +++ b/tests/testthat/blob.txt @@ -1 +1,2 @@ + [1] blob[4.00 B] blob[2.05 kB] blob[1.05 MB]