--- toJSON.m	2020-10-31 18:00:18.038655800 +0100
+++ test/toJSON.m	2020-11-01 14:58:31.470676200 +0100
@@ -1,10 +1,10 @@
-## Copyright (C) 2019 Ketan M. Patel
-## 
+## Copyright (C) 2019-2020 Ketan M. Patel
+##
 ## This program is free software: you can redistribute it and/or modify it
 ## under the terms of the GNU General Public License as published by
 ## the Free Software Foundation, either version 3 of the License, or
 ## (at your option) any later version.
-## 
+##
 ## This program is distributed in the hope that it will be useful, but
 ## WITHOUT ANY WARRANTY; without even the implied warranty of
 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
@@ -14,55 +14,80 @@
 ## along with this program.  If not, see
 ## <https://www.gnu.org/licenses/>.
 
-## -*- texinfo -*- 
+## -*- texinfo -*-
 ## @deftypefn  {} {@var{str} =} toJSON (@var{obj})
 ## @deftypefnx {} {@var{str} =} toJSON (@var{obj}, @var{prec})
 ## @deftypefnx {} {@var{str} =} toJSON (@var{obj}, @var{compact})
 ## @deftypefnx {} {@var{str} =} toJSON (@var{obj}, @var{prec}, @var{compact})
+## Convert any @var{obj} into a compact JSON string.
+##
+## Input arguments:
 ##
-##  Converts any @var{obj} into a compact JSON string.
-##  Default value for optional numeric @var{prec} is 15.
-##  Default value for optional logical @var{compact} is FALSE.
-## 
-##  @var{prec} specifies the number of significant digits for numerical conversion.  
-##
-##  There are no limitation on the numerical class: double, float, int, logical, 
-##  complex, char, etc.  Except for char and logical, however, all numerical class 
-##  are treated as double precision floating point.
-##
-##  Complex number, C, is converted to JSON object: 
-##         "{'re': real(C), 'im': imag(C)}"
-##
-##  @var{compact} specifies the compactness of converting structured number 
-##  arrays, such as complex number or numerical coordinates. Consider an Octave 
-##  struct array containing fiels x,y:  
-##    s = [[ struct('x', ..., 'y', ...) ]]
-##
-##  @var{compact} set to TRUE converts the above to a JSON object of arrays, e.g: 
-##         "{'x': [[s.x]], 'y': [[s.y]]}"
-##
-##  @var{compact} set to FALSE convert the above to a JSON array of objects, e.g: 
-##         "[[ {'x': s.x, 'y': s.y } ]]"
-##
-##  The former can be much more compact and faster to parse, while the 
-##  latter might be preferred for expressiveness or ease of iterating
-##  in other programming environments.
-##
-##  The body of inline functions are stored as string; however, reference to 
-##  external values will be lost. Consider the following inline function with 
-##  external reference 'c',
-##
-##    @(a) a + c
-## 
-##  The encoding will turn the above to string "@(a) a+c", but the value 
-##  of 'c' is lost in conversion.
-##
-##  JSON string contained within other Octave objects (i.e struct or cell array)
-##  are left unchanged.
-##
-##  CAUTION:  In most cases, `toJSON` output will be sucessfully parse by
-##            `jsondecode`.  A very important exception, however, is
-##            ND arrays (greater than 2 dims), which is handled differently.
+## @itemize
+## @item
+## @var{obj} is an object to be converted to a JSON string.  There are no
+## limitation on the class: double, float, int, logical, complex, char,
+## etc.  Except for char and logical, however, all numerical data are
+## treated as double precision floating point.
+##
+## Complex numbers are converted to JSON object as follows:
+## @verbatim
+##        "{'re': real(C), 'im': imag(C)}"
+## @end verbatim
+## @end item
+##
+## @item
+## @var{prec} (optional argument) specifies the number of significant digits
+## for numerical conversion.  The default value for optional numeric
+## @var{prec} is 15.
+## @end item
+##
+## @item
+## @var{compact} (also optional) specifies the compactness of converting
+## structured number arrays, such as complex numbers or numerical
+## coordinates.  Consider an Octave struct array containing fields x,y:
+## @verbatim
+##        s = [[ struct('x', ..., 'y', ...) ]]
+## @end verbatim
+##
+## @var{compact} set to TRUE converts the struct above to a JSON object of
+## arrays, e.g:
+## @verbatim
+##        "{'x': [[s.x]], 'y': [[s.y]]}"
+## @end verbatim
+##
+## @var{compact} set to FALSE convert the above struct to a JSON array of
+## objects, e.g:
+## @verbatim
+##        "[[ {'x': s.x, 'y': s.y } ]]"
+## @end verbatim
+##
+## The former can be much more compact and faster to parse, while the
+## latter might be preferred for expressiveness or ease of iterating
+## in other programming environments. @*
+## The default value for optional logical @var{compact} is FALSE.
+## @end item
+## @end itemize
+##
+## NOTE 1 @*
+## The bodies of inline functions are stored as string; however, reference to
+## external values will be lost. Consider the following inline function with
+## external reference 'c',
+## @verbatim
+##      @(a) a + c
+## @end verbatim
+##
+## The encoding will turn the above to string "@@(a) a+c", but the value
+## of 'c' is lost in conversion.
+##
+## NOTE 2 @*
+## JSON strings contained within other Octave objects (i.e struct or cell
+## arrays) are left unchanged.
+##
+## NOTE 3 @*
+## Java and COM objects are not converted but merely referenced along the
+## lines of @code{"[java.lang.Double]"} and @code{"[octave_com_object]"},
+## resp.
 ##
 ## @seealso{fromJSON}
 ## @end deftypefn
@@ -71,42 +96,42 @@
 ## Created: 2019-06-01
 ## Updates:
 ## 2020-10-22 Refactored and documented (Ketan M. Patel)
-## 2020-10-27 Updated from Octave 7 compatibility (Ketan M. Patel)
+## 2020-10-27 Updated for Octave 7 compatibility (Ketan M. Patel)
 
 function str = toJSON (obj='',PREC=[],COMPACT=[]);
 
   if( isbool(PREC) );
     [PREC,COMPACT] = {[],PREC}{:};
   elseif ~(isempty(PREC) || isnumeric(PREC));
-    warning("Invalid PREC");
+    warning ("toJSON: invalid PREC");
     PREC = [];
   elseif ~(isempty(COMPACT) || isbool(COMPACT));
-    warning("Invalid COMPACT");
+    warning ("toJSSON: invalid COMPACT");
     COMPACT = [];
   endif
-  
-  % set defaults 
+
+  % set defaults
   isempty(PREC)    && (PREC=15);
-  isempty(COMPACT) && (COMPACT=false);  
+  isempty(COMPACT) && (COMPACT=false);
 
   fmt = sprintf('%%.%dg,',fix(abs(PREC)));
   opt = struct('fmt',fmt,'prec',PREC,'compact',COMPACT);
-  
+
   if( nargin == 0 );
     str = '';
   else
     str = _tojson_(obj,opt);
   endif
-  
+
 endfunction
-    
+
 % convert any object into some kind of JSON string
 function [str] = _tojson_(obj,opt);
-  
+
   ND = ndims(obj);
 
   if( iscomplex(obj) );
-    
+
       obj = {real(obj) imag(obj)};
 
       if( ~opt.compact );
@@ -116,10 +141,10 @@
       str = _tojson_(struct('re',obj{1},'im',obj{2}),opt);
 
   elseif( isstruct(obj) && (ND == 2 || opt.compact) );
-    
+
       keys = __fieldnames__(obj);
       vals = struct2cell(obj);
-     
+
       if( isempty(vals) );
         str = '{}';
 
@@ -129,10 +154,10 @@
            vals = _nestdim_(vals,1);
         endif
 
-        str  = _map_(@(k,v)['"',k,'":',_tojson_(v,opt)], keys(:),vals(:)); 
+        str  = _map_(@(k,v)['"',k,'":',_tojson_(v,opt)], keys(:),vals(:));
         str  = _csv_('{',str,'}');
 
-      elseif( ~isvector(obj) ); 
+      elseif( ~isvector(obj) );
         str = _tojson_(_nestdim_(obj,1),opt);
 
       else   % a 1D struct array
@@ -159,19 +184,19 @@
         str = _tojson_(reshape([obj{:}],size(obj)),opt);
       catch; if( isempty(obj) );
         str = '[]';
-      elseif( ~isvector(obj) ); 
-        str = _tojson_(_nestdim_(obj,1),opt); 
+      elseif( ~isvector(obj) );
+        str = _tojson_(_nestdim_(obj,1),opt);
       else
         str = _csv_('[', _map_(@(o) _tojson_(o,opt),obj), ']');
       endif; end_try_catch;
 
   elseif( isnumeric(obj) || isbool(obj) );
-      
+
       % stringify
-      if( isbool(obj) ); 
-        str = _csv_('',{'false','true'}(obj.'+1),'');  
-        
-      else 
+      if( isbool(obj) );
+        str = _csv_('',{'false','true'}(obj.'+1),'');
+
+      else
         obj( nans=isnan(obj) ) = NaN;   % standardize NaN,nan,NA
         str = sprintf(opt.fmt,obj.')(1:end-1);
 
@@ -183,8 +208,8 @@
 
       % bracket string
       if( size(obj) > 1 );
-        idx = strfind(str,',');  
-        c   = columns(obj);  
+        idx = strfind(str,',');
+        c   = columns(obj);
         str(idx(c:c:end)) = ';';     % replace end of row ','  with ';'
         str = ['[['  _rep_(str,';','],[')   ']]'];
       elseif( numel(obj) ~= 1 );    % NOTE:  either empty or vector
@@ -194,7 +219,7 @@
   elseif( ischar(obj) );
 
       % 2D array of chars, make it a column vector of strings
-      if( rows(obj)>1 );    
+      if( rows(obj)>1 );
         str = _tojson_(mat2cell(obj,ones(1,rows(obj)),columns(obj)),opt);
       % else quote it, if not already JSON string (i.e. object/struct/quoted string)
       elseif ~( numel( str=strtrim(obj) ) && strfind('{}[]""',str([1,end])) );
@@ -210,27 +235,27 @@
   else
       str =  ['"[' class(obj) ']"'];
   endif
-  
+
 endfunction   ## _tojson()
 
 
 function str1 = _rep_(str,pat,rep);
   str1 = strrep(str,pat,rep,'overlaps',false);
 endfunction
- 
+
 function obj = _map_(fn,varargin);
   obj = cellfun(fn,varargin{:},'UniformOutput',false);
-endfunction 
+endfunction
 
-function C = _nestdim_(obj,D); 
+function C = _nestdim_(obj,D);
   index.type = '()';
   index.subs(1:ndims(obj)) = {':'};
-  
+
   for i = 1:size(obj,D);
     index.subs(D) = i;
     C{i} = squeeze(subsref(obj,index)); % allow rows => columns
   endfor
-endfunction            
+endfunction
 
 function str = _csv_(a,c,b);
   c      = c(:).';
@@ -238,9 +263,9 @@
   str = [a c{1:end-1} b];
 endfunction
 
-%!test ## invalid args 
-%!warning <Invalid PREC>   toJSON(0,struct);
-%!warning <Invalid COMPACT> toJSON(0,:,struct);
+%!test ## invalid args
+%!warning <invalid PREC>   toJSON(0,struct);
+%!warning <invalid COMPACT> toJSON(0,:,struct);
 
 %!test  ## no args
 %!  assert(toJSON(),'');
@@ -251,10 +276,10 @@
 %!test  ## empty array
 %!  assert(toJSON([]),'[]');
 
-%!test  ## zero 
+%!test  ## zero
 %!  assert(toJSON(0),"0")
 
-%!test  ## false 
+%!test  ## false
 %!  assert(toJSON(false),'false')
 
 %!test  ## float
@@ -268,7 +293,7 @@
 %!  assert(toJSON(pi,  :),'3.14159265358979')
 %!  assert(toJSON(pi, []),'3.14159265358979')
 %!  assert(toJSON(pi, false),'3.14159265358979');
-%!  assert(toJSON(pi, {}),'3.14159265358979'); 
+%!  assert(toJSON(pi, {}),'3.14159265358979');
 
 %!test  ## number single
 %!  assert(toJSON(single(pi)),'3.14159274101257')
@@ -339,7 +364,7 @@
 %!  json = toJSON(num2cell(reshape(1:8,2,2,2)));
 %!  assert(json,'[[[1,3],[2,4]],[[5,7],[6,8]]]')
 
-%!test   ## numerical ND cell array, with PREC 
+%!test   ## numerical ND cell array, with PREC
 %! c = num2cell(reshape(1:8,2,2,2)); c{5} = pi;
 %!  assert(toJSON(c,5),'[[[1,3],[2,4]],[[3.1416,7],[6,8]]]')
 
@@ -379,10 +404,10 @@
 %!test   ## mixed cell array
 %!  assert(toJSON({1,2,3,"a",struct("a",3)}, true),'[1,2,3,"a",{"a":3}]')
 
-%!test  ## complex number 
+%!test  ## complex number
 %!  assert(toJSON(i, true),'{"re":0,"im":1}');
 
-%!test    ## complex number 1D array 
+%!test    ## complex number 1D array
 %!  assert(toJSON([i,1], true),'{"re":[0,1],"im":[1,0]}');
 
 %!test  ## complex number COMPACT=false,
@@ -417,7 +442,7 @@
 %!test ## inline function
 %!  assert(toJSON(@sin),'"@(x) sin(x)"')
 %!  assert(toJSON(@(a,b)a+b+c),'"@(a, b) a + b + c"')
-    
+
 %!test  ## struct with java object
 %! obj = javaObject ("java.math.BigDecimal", 1.0);
 %!  assert(toJSON(struct('a',obj)), '{"a":"[java.math.BigDecimal]"}');
