Skip to content

Commit

Permalink
added indent option to json output
Browse files Browse the repository at this point in the history
  • Loading branch information
alexcb committed Jun 7, 2018
1 parent b60b413 commit 6130db1
Show file tree
Hide file tree
Showing 6 changed files with 43 additions and 17 deletions.
2 changes: 1 addition & 1 deletion rjson/DESCRIPTION
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
Package: rjson
Version: 0.2.19
Version: 0.2.20
Date: 2018-05-18
Title: JSON for R
Author: Alex Couture-Beil <rjson_pkg@mofo.ca>
Expand Down
4 changes: 2 additions & 2 deletions rjson/R/json.R
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
toJSON <- function( x, method = "C" )
toJSON <- function( x, indent = 0, method = "C" )
{
if( method == "C" ) {
return( .Call("toJSON", x, PACKAGE="rjson")[[ 1 ]] )
return( .Call("toJSON", x, as.integer(indent), PACKAGE="rjson")[[ 1 ]] )
} else if( method != "R" ) {
stop("bad method - only R or C" )
}
Expand Down
3 changes: 2 additions & 1 deletion rjson/man/toJSON.Rd
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,11 @@
***Lists with unnamed components are not currently supported***
}

\usage{toJSON( x, method="C" )}
\usage{toJSON( x, indent=0, method="C" )}

\arguments{
\item{x}{a vector or list to convert into a JSON object}
\item{indent}{an integer specifying how much indentation to use when formatting the JSON object; if 0, no pretty-formatting is used}
\item{method}{use the \code{C} implementation, or the older slower (and one day to be depricated) \code{R} implementation}
}

Expand Down
46 changes: 35 additions & 11 deletions rjson/src/dump.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ std::string escapeString( const char *s )
}
s++;
}

oss << '"';
return oss.str();
}
Expand All @@ -67,7 +67,7 @@ std::string escapeString( const char *s )
#define ARRAY_CONTAINER 1
#define OBJECT_CONTAINER 2

std::string toJSON2( SEXP x )
std::string toJSON2( SEXP x, int indent, int indent_amount )
{
if( x == R_NilValue )
return "null";
Expand All @@ -83,11 +83,15 @@ std::string toJSON2( SEXP x )
if( names != NULL_USER_OBJECT ) {
oss << "{";
container_closer = "}";
if( indent_amount > 0 ) { oss << "\n"; }
indent += indent_amount;
if( length(names) != n )
error("number of names does not match number of elements\n");
} else if( n != 1 || TYPEOF(x) == VECSXP ) {
oss << "[";
container_closer = "]";
indent += indent_amount;
if( indent_amount > 0 ) { oss << "\n"; }
}

SEXP levels;
Expand All @@ -96,8 +100,11 @@ std::string toJSON2( SEXP x )
switch( TYPEOF(x) ) {
case LGLSXP:
for( i = 0; i < n; i++ ) {
if( i > 0 )
if( i > 0 ) {
oss << ",";
if( indent_amount > 0 ) { oss << "\n"; }
}
oss << std::setw(indent) << "";
if( names != NULL_USER_OBJECT )
oss << escapeString(CHAR(STRING_ELT(names, i))) << ":";
if( LOGICAL(x)[i] == NA_INTEGER )
Expand All @@ -112,8 +119,11 @@ std::string toJSON2( SEXP x )
break;
case INTSXP:
for( i = 0; i < n; i++ ) {
if( i > 0 )
if( i > 0 ) {
oss << ",";
if( indent_amount > 0 ) { oss << "\n"; }
}
oss << std::setw(indent) << "";
if( names != NULL_USER_OBJECT )
oss << escapeString(CHAR(STRING_ELT(names, i))) << ":";
if( INTEGER(x)[i] == NA_INTEGER )
Expand All @@ -130,7 +140,9 @@ std::string toJSON2( SEXP x )
for( i = 0; i < n; i++ ) {
if( i > 0 ) {
oss << ",";
if( indent_amount > 0 ) { oss << "\n"; }
}
oss << std::setw(indent) << "";
if( names != NULL_USER_OBJECT ) {
oss << escapeString(CHAR(STRING_ELT(names, i))) << ":";
}
Expand All @@ -157,14 +169,16 @@ std::string toJSON2( SEXP x )
REAL(p)[1] = COMPLEX(x)[i].i;

setAttrib( p, R_NamesSymbol, p_names );
oss << toJSON2(p);
oss << toJSON2(p, indent, indent_amount);
UNPROTECT(2);
}
break;
case STRSXP:
for( i = 0; i < n; i++ ) {
if( i > 0 )
if( i > 0 ) {
oss << ",";
if( indent_amount > 0 ) { oss << "\n"; }
}
if( names != NULL_USER_OBJECT )
oss << escapeString(CHAR(STRING_ELT(names, i))) << ":";
if( STRING_ELT(x,i) == NA_STRING )
Expand All @@ -175,25 +189,35 @@ std::string toJSON2( SEXP x )
break;
case VECSXP:
for( i = 0; i < n; i++ ) {
if( i > 0 )
if( i > 0 ) {
oss << ",";
if( indent_amount > 0 ) { oss << "\n"; }
}
oss << std::setw(indent) << "";
if( names != NULL_USER_OBJECT )
oss << escapeString(CHAR(STRING_ELT(names, i))) << ":";
oss << toJSON2( VECTOR_ELT(x,i) );
oss << toJSON2( VECTOR_ELT(x,i), indent, indent_amount );
}
break;
default:
error("unable to convert R type %i to JSON\n", TYPEOF(x));
}
UNPROTECT(1);
oss << container_closer;
if( !container_closer.empty() ) {
indent -= indent_amount;
if( indent_amount > 0 ) { oss << "\n"; }
oss << std::setw(indent) << "";
oss << container_closer;
}
return oss.str();
}

extern "C" {
SEXP toJSON( SEXP obj )
SEXP toJSON( SEXP obj, SEXP indent )
{
std::string buf = toJSON2( obj );
int indent_amount = INTEGER(indent)[0];

std::string buf = toJSON2( obj, 0, indent_amount );
SEXP p;
PROTECT(p=allocVector(STRSXP, 1));
SET_STRING_ELT(p, 0, mkCharCE( buf.c_str(), CE_UTF8 ));
Expand Down
2 changes: 1 addition & 1 deletion rjson/src/funcs.h
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
SEXP fromJSON( SEXP str_in, SEXP unexpected_escape_behavior, SEXP simplify );
SEXP toJSON( SEXP obj );
SEXP toJSON( SEXP obj, SEXP indent );
3 changes: 2 additions & 1 deletion test.r
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@
install.packages( '/foo/rjson', repos=NULL )
library( rjson )

RUnit = 'RUnit_0.4.31.tar.gz'
# change this to the latest version in https://cran.rstudio.com/web/packages/RUnit/index.html
RUnit = 'RUnit_0.4.32.tar.gz'
tmp_path = sprintf('/tmp/rjson/%s', RUnit )
if( !file.exists(tmp_path) ) {
url = sprintf('https://cloud.r-project.org/src/contrib/%s', RUnit)
Expand Down

0 comments on commit 6130db1

Please sign in to comment.