diff scripts/general/inputParser.m @ 21667:84092ccb45e2

inputParser.m: implement StructExpand option (struct with param/value pairs).
author Carnë Draug <carandraug@octave.org>
date Mon, 02 May 2016 13:48:09 +0300
parents 09517e0a8aa0
children 58f5a6347851
line wrap: on
line diff
--- a/scripts/general/inputParser.m	Tue May 03 03:09:49 2016 +0100
+++ b/scripts/general/inputParser.m	Mon May 02 13:48:09 2016 +0300
@@ -76,7 +76,7 @@
 ## @end deftypefn
 ## @deftypefn {} {} inputParser.StructExpand = @var{boolean}
 ## Set whether a structure can be passed to the function instead of
-## parameter/value pairs.  Defaults to true.  Not implemented yet.
+## parameter/value pairs.  Defaults to true.
 ##
 ## The following example shows how to use this class:
 ##
@@ -250,7 +250,7 @@
     FunctionName  = "";
     KeepUnmatched = false;
     # PartialMatching = true;   # FIXME: unimplemented
-    # StructExpand    = true;   # FIXME: unimplemented
+    StructExpand    = true;
   endproperties
 
   properties (SetAccess = protected)
@@ -364,7 +364,9 @@
           ##    1) input is actually wrong and we should error;
           ##    2) it's a ParamValue or Switch name and we should use the
           ##       the default for the rest.
-          if (ischar (in))
+          ##    3) it's a struct with the ParamValue pairs.
+          if (ischar (in) || (this.StructExpand && isstruct (in)
+                              && isscalar (in)))
             idx -= 1;
             vidx -= 1;
             break
@@ -386,6 +388,16 @@
       ## Search unordered Options (Switch and ParamValue)
       while (vidx++ < pnargin)
         name = varargin{vidx};
+
+        if (this.StructExpand && isstruct (name) && isscalar (name))
+          expanded_options = [fieldnames(name) struct2cell(name)]'(:);
+          n_new_args = numel (expanded_options) -1;
+          pnargin += n_new_args;
+          varargin(vidx+n_new_args+1:pnargin) = varargin(vidx+1:end);
+          varargin(vidx:vidx+n_new_args) = expanded_options;
+          name = varargin{vidx};
+        endif
+
         if (this.is_argname ("ParamValue", name))
           if (vidx++ > pnargin)
             this.error (sprintf ("no matching value for option '%s'",
@@ -605,6 +617,49 @@
 %! assert (p.Results.not_err, "qux")
 
 
+## With more ParamValues to test StructExpand
+%!function p3 = create_p3 ();
+%!  p3 = inputParser;
+%!  addOptional (p3, "op1", "val", @(x) any (strcmp (x, {"val", "foo"})));
+%!  addOptional (p3, "op2", 78, @(x) x > 50);
+%!  addSwitch (p3, "verbose");
+%!  addParamValue (p3, "line", "tree", @(x) any (strcmp (x, {"tree", "circle"})));
+%!  addParamValue (p3, "color", "red", @(x) any (strcmp (x, {"red", "green"})));
+%!  addParamValue (p3, "style", "tt", @(x) any (strcmp (x, {"tt", "f", "i"})));
+%!endfunction
+
+## Test StructExpand
+%!test
+%! p3 = create_p3 ();
+%! p3.parse (struct ("line", "circle", "color", "green"));
+%! assert (p3.Results, struct ("op1", "val", "op2", 78, "verbose", false,
+%!                             "line", "circle", "color", "green",
+%!                             "style", "tt"))
+
+%!test
+%! p3 = create_p3 ();
+%! p3.parse (struct ("line", "circle", "color", "green"), "line", "tree");
+%! assert (p3.Results.line, "tree")
+%! p3.parse ("line", "tree", struct ("line", "circle", "color", "green"));
+%! assert (p3.Results.line, "circle")
+
+%!test # unmatched parameters with StructExpand
+%! p3 = create_p3 ();
+%! p3.KeepUnmatched = true;
+%! p3.parse (struct ("line", "circle", "color", "green", "bar", "baz"));
+%! assert (p3.Unmatched.bar, "baz")
+
+## The validation for the second optional argument throws an error with
+## a struct so check that we can handle it.
+%!test
+%! p3 = create_p3 ();
+%! p3.parse ("foo", struct ("color", "green"), "line", "tree");
+%! assert (p3.Results.op1, "foo")
+%! assert (p3.Results.line, "tree")
+%! assert (p3.Results.color, "green")
+%! assert (p3.Results.verbose, false)
+
+
 %!function r = foobar (varargin)
 %!  p = inputParser ();
 %!  p.addParamValue ("foo", "bar", @ischar);