changeset 10215:3bd3e4f9ad8c octave-forge

inputParser: if a supposed Optional argument is a string and fails to validate, consider start of ParamValue arguments
author carandraug
date Thu, 10 May 2012 14:55:27 +0000
parents b71b1d87cc89
children 8710ef5d29fa
files main/general/inst/@inputParser/addOptional.m main/general/inst/@inputParser/inputParser.m main/general/inst/@inputParser/subsref.m
diffstat 3 files changed, 52 insertions(+), 24 deletions(-) [+]
line wrap: on
line diff
--- a/main/general/inst/@inputParser/addOptional.m	Thu May 10 13:18:41 2012 +0000
+++ b/main/general/inst/@inputParser/addOptional.m	Thu May 10 14:55:27 2012 +0000
@@ -33,8 +33,11 @@
 ##
 ## See @command{help @inputParser} for examples.
 ##
-## @emph{Note}: if @command{ParamValue} arguments are also specified, all @command{Optional}
-## arguments will have to be specified before.
+## @emph{Note}: if a string argument does not validate, it will be considered a
+## ParamValue key. If an optional argument is not given a validator, anything
+## will be valid, and so any string will be considered will be the value of the
+## optional argument (in @sc{matlab}, if no validator is given and argument is
+## a string it will also be considered a ParamValue key).
 ##
 ## @seealso{inputParser, @@inputParser/addParamValue, @@inputParser/addSwitch,
 ## @@inputParser/addParamValue, @@inputParser/addRequired, @@inputParser/parse}
--- a/main/general/inst/@inputParser/inputParser.m	Thu May 10 13:18:41 2012 +0000
+++ b/main/general/inst/@inputParser/inputParser.m	Thu May 10 14:55:27 2012 +0000
@@ -116,9 +116,9 @@
 ## must be at the end.
 ##
 ## @emph{Note 2}: if both @command{Optional} and @command{ParamValue} arguments
-## are mixed in a function API, the user will have to specify @emph{all}
-## @command{Optional} arguments before the @command{ParamValue} and
-## @command{Switch}arguments.
+## are mixed in a function API, once a string Optional argument fails to validate
+## against, it will be considered the end of @command{Optional} arguments and the
+## first key for a @command{ParamValue} and @command{Switch} arguments.
 ##
 ## @seealso{@@inputParser/addOptional, @@inputParser/addSwitch,
 ## @@inputParser/addParamValue, @@inputParser/addRequired,
--- a/main/general/inst/@inputParser/subsref.m	Thu May 10 13:18:41 2012 +0000
+++ b/main/general/inst/@inputParser/subsref.m	Thu May 10 14:55:27 2012 +0000
@@ -59,7 +59,7 @@
 
 ## when parsing options, here's the principle: Required options have to be the
 ## first ones. They are followed by Optional if any. In the end come the
-## ParamValue. Any other order makes no sense
+## ParamValue mixed with Switch. Any other order makes no sense
 function inPar = parse_args (inPar, idx)
 
   ## make copy of ordered list of Parameters to keep the original intact and readable
@@ -80,8 +80,8 @@
   ## we take names out of 'copy' and values out of 'args', evaluate them and
   ## store them into 'Results'
   for i = 1 : numel (fieldnames (inPar.Required))
-    [name, inPar.copy] = pop (inPar.copy);
-    [value, args]      = pop (args);
+    [name, inPar.copy] = shift (inPar.copy);
+    [value, args]      = shift (args);
     if ( !feval (inPar.Required.(name).validator, value) )
       error("%sinvalid value for parameter '%s'", inPar.FunctionName, name);
     endif
@@ -91,22 +91,39 @@
   ## loop a maximum #times of the number of Optional, similarly to the required
   ## loop. Once ran out of 'args', move their name into usingDefaults, place
   ## their default values into 'Results', and break
+
+  ## because if an argument is string and does not validate, should be considered
+  ## a ParamValue key
+  found_possible_key = false;
+
   for i = 1 : numel (fieldnames (inPar.Optional))
-    if ( !numel (args) )
+    if ( !numel (args) || found_possible_key)
       ## loops the number of Optional options minus the number of them already processed
       for n = 1 : (numel (fieldnames (inPar.Optional)) - i + 1 )
-        [name, inPar.copy]   = pop (inPar.copy);
+        [name, inPar.copy]   = shift (inPar.copy);
         inPar.UsingDefaults  = push (inPar.UsingDefaults, name);
         inPar.Results.(name) = inPar.Optional.(name).default;
       endfor
       break
     endif
-    [name, inPar.copy] = pop (inPar.copy);
-    [value, args]      = pop (args);
+    [name, inPar.copy] = shift (inPar.copy);
+    [value, args]      = shift (args);
     if ( !feval (inPar.Optional.(name).validator, value) )
-      error("%sinvalid value for parameter '%s'", inPar.FunctionName, name);
+      if (ischar (value) )
+        ## maybe the other optional are not defined, this can be Paramvalue
+        ## place this one on defaults and go back to the top with note to clean loop
+        inPar.UsingDefaults  = push (inPar.UsingDefaults, name);
+        inPar.Results.(name) = inPar.Optional.(name).default;
+        found_possible_key   = true;
+        args = unshift (args, value);
+        continue
+      else
+        error("%sinvalid value for parameter '%s'", inPar.FunctionName, name);
+      endif
+    else
+      
+      inPar.Results.(name) = value;
     endif
-    inPar.Results.(name) = value;
   endfor
 
   ## loop a maximum #times of the number of ParamValue, taking pairs of keys and
@@ -117,7 +134,7 @@
     if ( !numel (args) )
       ## loops the number of times left in 'copy' since these are the last type
       for n = 1 : numel (inPar.copy)
-        [name, inPar.copy]   = pop (inPar.copy);
+        [name, inPar.copy]   = shift (inPar.copy);
         inPar.UsingDefaults  = push (inPar.UsingDefaults, name);
         if (isfield (inPar.ParamValue, name))
           inPar.Results.(name) = inPar.ParamValue.(name).default;
@@ -127,7 +144,7 @@
       endfor
       break
     endif
-    [key, args] = pop (args);
+    [key, args] = shift (args);
     if ( !ischar (key) )
       error("%sParameter/Switch names must be strings", inPar.FunctionName);
     endif
@@ -141,18 +158,18 @@
       value  = true;
       method = "Switch";
     else
-      ## then it must be a ParamValue, pop its value
-      [value, args] = pop (args);
+      ## then it must be a ParamValue, shift its value
+      [value, args] = shift (args);
       method = "ParamValue";
     endif
 
     ## index == 0 means no match so either return error or move them into 'Unmatched'
     if ( index != 0 )
-      [name, inPar.copy] = pop (inPar.copy, index);
+      [name, inPar.copy] = shift (inPar.copy, index);
       if ( !feval (inPar.(method).(name).validator, value))
         error("%sinvalid value for parameter '%s'", inPar.FunctionName, key);
       endif
-      ## we use the name popped from 'copy' instead of the key from 'args' in case
+      ## we use the name shifted from 'copy' instead of the key from 'args' in case
       ## the key is in the wrong case
       inPar.Results.(name) = value;
     elseif ( index == 0 && inPar.KeepUnmatched )
@@ -167,8 +184,8 @@
   ## have already been processed in the ParamValue loop
   if ( numel (args) && inPar.KeepUnmatched )
     for i = 1 : ( numel(args) / 2 )
-      [key, args]           = pop (args);
-      [value, args]         = pop (args);
+      [key, args]           = shift (args);
+      [value, args]         = shift (args);
       inPar.Unmatched.(key) = value;
     endfor
   elseif ( numel (args) )
@@ -192,7 +209,7 @@
     print_usage (func);
   endif
   def_val      = @() true;
-  [name, args] = pop (args);
+  [name, args] = shift (args);
   ## a validator is optional but that complicates handling all the parsing with
   ## few functions and conditions. If not specified @() true will always return
   ## true. Simply using true is not enough because if the argument is zero it
@@ -285,11 +302,19 @@
 ## very auxiliary functions
 ################################################################################
 
-function [out, in] = pop (in, idx = 1)
+function [out, in] = shift (in, idx = 1)
   out     = in{idx};
   in(idx) = [];
 endfunction
 
+function [in] = unshift (in, add)
+  if ( !iscell (add) )
+    add = {add};
+  endif
+  in (numel(add) + 1 : end + numel(add)) = in;
+  in (1:numel(add)) = add;
+endfunction
+
 function [in] = push (in, add)
   if ( !iscell (add) )
     add = {add};