Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion R/asJSON.character.R
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
setMethod("asJSON", "character", function(x, collapse = TRUE, na = c("null", "string", "NA"), auto_unbox = FALSE, ...) {
setMethod("asJSON", "character", function(x, collapse = TRUE, na = c("null", "string", "NA"),
auto_unbox = FALSE, ..., keep_vec_names = FALSE) {

# vectorized escaping
tmp <- deparse_vector(x)
Expand All @@ -22,6 +23,11 @@ setMethod("asJSON", "character", function(x, collapse = TRUE, na = c("null", "st
}
}

if (isTRUE(keep_vec_names) && !is.null(names(x))) {
warn_keep_vec_names()
return(asJSON(as.list(x), collapse = collapse, na = na, auto_unbox = TRUE, ...))
}

if(isTRUE(auto_unbox) && length(tmp) == 1){
return(tmp);
}
Expand Down
14 changes: 12 additions & 2 deletions R/asJSON.factor.R
Original file line number Diff line number Diff line change
@@ -1,13 +1,23 @@
setMethod("asJSON", "factor", function(x, factor = c("string", "integer"), ...) {
setMethod("asJSON", "factor", function(x, factor = c("string", "integer"), ...,
keep_vec_names = FALSE) {

# validate
factor <- match.arg(factor)

# dispatch
if (factor == "integer") {
# encode factor as enum
asJSON(unclass(x), ...)

} else {
xc <- as.character(x)

if (isTRUE(keep_vec_names) && !is.null(names(x))) {
# as.character drops names, so we need to explicitly keep them
names(xc) <- names(x)
}

# encode as strings
asJSON(as.character(x), ...)
asJSON(xc, keep_vec_names = keep_vec_names, ...)
}
})
9 changes: 8 additions & 1 deletion R/asJSON.logical.R
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
setMethod("asJSON", "logical", function(x, collapse = TRUE, na = c("null", "string", "NA"), auto_unbox = FALSE, ...) {
setMethod("asJSON", "logical", function(x, collapse = TRUE,
na = c("null", "string", "NA"), auto_unbox = FALSE, ..., keep_vec_names = FALSE) {

# validate arg
na <- match.arg(na)

Expand All @@ -18,6 +20,11 @@ setMethod("asJSON", "logical", function(x, collapse = TRUE, na = c("null", "stri
tmp <- as.character(tmp);
}

if (isTRUE(keep_vec_names) && !is.null(names(x))) {
warn_keep_vec_names()
return(asJSON(as.list(x), collapse = collapse, na = na, auto_unbox = TRUE, ...))
}

if(isTRUE(auto_unbox) && length(tmp) == 1){
return(tmp);
}
Expand Down
9 changes: 8 additions & 1 deletion R/asJSON.numeric.R
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
setMethod("asJSON", "numeric", function(x, digits = 5, use_signif = is(digits, "AsIs"),
na = c("string", "null", "NA"), auto_unbox = FALSE, collapse = TRUE, ...) {
na = c("string", "null", "NA"), auto_unbox = FALSE, collapse = TRUE,
..., keep_vec_names = FALSE) {

na <- match.arg(na);
na_as_string <- switch(na,
Expand All @@ -12,6 +13,12 @@ setMethod("asJSON", "numeric", function(x, digits = 5, use_signif = is(digits, "
# old R implementation
# tmp <- num_to_char_R(x, digits, na_as_string);

if (isTRUE(keep_vec_names) && !is.null(names(x))) {
warn_keep_vec_names()
return(asJSON(as.list(x), digits = digits, use_signif = use_signif, na = na,
auto_unbox = TRUE, collapse = collapse, ...))
}

# fast C implementation
tmp <- if(is(x, "integer64")){
integer64_to_char(x, na_as_string)
Expand Down
4 changes: 4 additions & 0 deletions R/fromJSON.R
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,10 @@
#' @param digits max number of decimal digits to print for numeric values. Use \code{I()} to specify significant digits.
#' @param force unclass/skip objects of classes with no defined JSON mapping
#' @param pretty adds indentation whitespace to JSON output. Can be TRUE/FALSE or a number specifying the number of spaces to indent. See \code{\link{prettify}}
#' @param keep_vec_names if \code{FALSE} (the default), named vectors will be converted to JSON arrays, dropping names.
#' If \code{TRUE}, they will be converted to JSON objects (with names), similar to named lists.
#' The \code{TRUE} setting is only for backward compatibility with RJSONIO, and a message will be printed each time a named vector is encountered.
#' This option will stop being supported in a future version of jsonlite.
#' @param ... arguments passed on to class specific \code{print} methods
#' @references Jeroen Ooms (2014). The \code{jsonlite} Package: A Practical and Consistent Mapping Between JSON Data and \R{} Objects. \emph{arXiv:1403.2805}. \url{http://arxiv.org/abs/1403.2805}
#' @examples # Stringify some data
Expand Down
4 changes: 2 additions & 2 deletions R/toJSON.R
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ toJSON <- function(x, dataframe = c("rows", "columns", "values"), matrix = c("ro
Date = c("ISO8601", "epoch"), POSIXt = c("string", "ISO8601", "epoch", "mongo"),
factor = c("string", "integer"), complex = c("string", "list"), raw = c("base64", "hex", "mongo"),
null = c("list", "null"), na = c("null", "string"), auto_unbox = FALSE, digits = 4,
pretty = FALSE, force = FALSE, ...) {
pretty = FALSE, force = FALSE, keep_vec_names = FALSE, ...) {

# validate args
dataframe <- match.arg(dataframe)
Expand Down Expand Up @@ -33,7 +33,7 @@ toJSON <- function(x, dataframe = c("rows", "columns", "values"), matrix = c("ro
# dispatch
ans <- asJSON(x, dataframe = dataframe, Date = Date, POSIXt = POSIXt, factor = factor,
complex = complex, raw = raw, matrix = matrix, auto_unbox = auto_unbox, digits = digits,
na = na, null = null, force = force, ...)
na = na, null = null, force = force, keep_vec_names = keep_vec_names, ...)

#prettify
if (isTRUE(pretty)) {
Expand Down
6 changes: 6 additions & 0 deletions R/warn_keep_vec_names.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
warn_keep_vec_names <- function() {
message("Input to asJSON(keep_vec_names=TRUE) is a named vector. ",
"In a future version of jsonlite, this option will not be supported, ",
"and named vectors will be translated into arrays instead of objects. ",
"If you want JSON object output, please use a named list instead. See ?toJSON.")
}
39 changes: 39 additions & 0 deletions inst/tests/test-toJSON-keep-vec-names.R
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
context("toJSON keep_vec_names")

test_that("keep_vec_names with named vectors", {
toJSON2 <- function(x) {
toJSON(x, keep_vec_names = TRUE, auto_unbox = TRUE)
}

# Basic types should give messages
# Length-1 vectors
expect_message(expect_equal(toJSON2(c(a=1)), '{"a":1}'))
expect_message(expect_equal(toJSON2(c(a="x")), '{"a":"x"}'))
expect_message(expect_equal(toJSON2(c(a=TRUE)), '{"a":true}'))

# Longer vectors
expect_message(expect_equal(toJSON2(c(a=1,b=2)), '{"a":1,"b":2}'))
expect_message(expect_equal(toJSON2(c(a="x",b="y")), '{"a":"x","b":"y"}'))
expect_message(expect_equal(toJSON2(c(a=FALSE,b=TRUE)), '{"a":false,"b":true}'))

# Some other types
expect_message(expect_equal(toJSON2(factor(c(a="x"))), '{"a":"x"}'))
expect_message(expect_equal(toJSON2(c(a=as.Date("2015-01-01"))), '{"a":"2015-01-01"}'))
expect_message(expect_equal(toJSON2(c(a=as.POSIXct("2015-01-01 3:00:00"))), '{"a":"2015-01-01 03:00:00"}'))
expect_message(expect_equal(toJSON2(c(a=as.POSIXlt("2015-01-01 3:00:00"))), '{"a":"2015-01-01 03:00:00"}'))

# keep_vec_names shouldn't affect unnamed vectors
expect_equal(toJSON2(1), '1')
expect_equal(toJSON2(c(1:3)), '[1,2,3]')
}


# Data frames generally don't allow named columns, except in very unusual cases
test_that("keep_vec_names with data frames", {
toJSON2 <- function(x) {
toJSON(x, keep_vec_names = TRUE, auto_unbox = TRUE, dataframe = "columns", rownames = FALSE)
}

expect_equal(toJSON2(data.frame(x=c(a=1), y=2)), '{"x":[1],"y":[2]}')
expect_equal(toJSON2(data.frame(x=c(a=1,b=2), y=c(c=3,d=4))), '{"x":[1,2],"y":[3,4]}')
}
8 changes: 7 additions & 1 deletion man/fromJSON.Rd
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ toJSON(x, dataframe = c("rows", "columns", "values"), matrix = c("rowmajor",
"ISO8601", "epoch", "mongo"), factor = c("string", "integer"),
complex = c("string", "list"), raw = c("base64", "hex", "mongo"),
null = c("list", "null"), na = c("null", "string"), auto_unbox = FALSE,
digits = 4, pretty = FALSE, force = FALSE, ...)
digits = 4, pretty = FALSE, force = FALSE, keep_vec_names = FALSE,
...)
}
\arguments{
\item{txt}{a JSON string, URL or file}
Expand Down Expand Up @@ -58,6 +59,11 @@ An exception is that objects of class \code{AsIs} (i.e. wrapped in \code{I()}) a
\item{pretty}{adds indentation whitespace to JSON output. Can be TRUE/FALSE or a number specifying the number of spaces to indent. See \code{\link{prettify}}}

\item{force}{unclass/skip objects of classes with no defined JSON mapping}

\item{keep_vec_names}{if \code{FALSE} (the default), named vectors will be converted to JSON arrays, dropping names.
If \code{TRUE}, they will be converted to JSON objects (with names), similar to named lists.
The \code{TRUE} setting is only for backward compatibility with RJSONIO, and a message will be printed each time a named vector is encountered.
This option will stop being supported in a future version of jsonlite.}
}
\description{
These functions are used to convert between JSON data and \R{} objects. The \code{\link{toJSON}} and \code{\link{fromJSON}}
Expand Down