]> Creatis software - CreaPhase.git/blobdiff - octave_packages/general-1.3.1/@inputParser/inputParser.m
Add a useful package (from Source forge) for octave
[CreaPhase.git] / octave_packages / general-1.3.1 / @inputParser / inputParser.m
diff --git a/octave_packages/general-1.3.1/@inputParser/inputParser.m b/octave_packages/general-1.3.1/@inputParser/inputParser.m
new file mode 100644 (file)
index 0000000..a8718ef
--- /dev/null
@@ -0,0 +1,224 @@
+## Copyright (C) 2011-2012 CarnĂ« Draug <carandraug+dev@gmail.com>
+##
+## 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 GNU General Public License for more
+## details.
+##
+## You should have received a copy of the GNU General Public License along with
+## this program; if not, see <http://www.gnu.org/licenses/>.
+
+## -*- texinfo -*-
+## @deftypefn {Function File} {@var{parser} =} inputParser ()
+## Create object @var{parser} of the inputParser class.
+##
+## This class is designed to allow easy parsing of function arguments. This class
+## supports four types of arguments:
+##
+## @enumerate
+## @item mandatory (see @command{@@inputParser/addRequired});
+## @item optional (see @command{@@inputParser/addOptional});
+## @item named (see @command{@@inputParser/addParamValue});
+## @item switch (see @command{@@inputParser/addSwitch}).
+## @end enumerate
+##
+## After defining the function API with this methods, the supplied arguments can
+## be parsed with the @command{@@inputParser/parse} method and the parsing results
+## accessed with the @command{Results} accessor.
+##
+## @deftypefnx {Accessor method} parser.Parameters
+## Return list of parameters name already defined.
+##
+## @deftypefnx {Accessor method} parser.Results
+## Return structure with argument names as fieldnames and corresponding values.
+##
+## @deftypefnx {Accessor method} parser.Unmatched
+## Return structure similar to @command{Results} for unmatched parameters. See
+## the @command{KeepUnmatched} property.
+##
+## @deftypefnx {Accessor method} parser.UsingDefaults
+## Return cell array with the names of arguments that are using default values.
+##
+## @deftypefnx {Class property} parser.CaseSensitive = @var{boolean}
+## Set whether matching of argument names should be case sensitive. Defaults to false.
+##
+## @deftypefnx {Class property} parser.FunctionName = @var{name}
+## Set function name to be used on error messages. Defauls to empty string.
+##
+## @deftypefnx {Class property} parser.KeepUnmatched = @var{boolean}
+## Set whether an error should be given for non-defined arguments. Defaults to
+## false. If set to true, the extra arguments can be accessed through
+## @code{Unmatched} after the @code{parse} method. Note that since @command{Switch}
+## and @command{ParamValue} arguments can be mixed, it is not possible to know
+## the unmatched type. If argument is found unmatched it is assumed to be of the
+## @command{ParamValue} type and it is expected to be followed by a value.
+##
+## @deftypefnx {Class property} parser.StructExpand = @var{boolean}
+## Set whether a structure can be passed to the function instead of parameter
+## value pairs. Defaults to true. Not implemented yet.
+##
+## The following example shows how to use this class:
+##
+## @example
+## @group
+## function check (pack, path, mat, varargin)
+##     p = inputParser;                             # create object
+##     p.FunctionName = "check";                    # set function name
+##     p = p.addRequired ("pack", @@ischar);         # create mandatory argument
+##
+##     p = p.addOptional ("path", pwd(), @@ischar);  # create optional argument
+##
+##     ## one can create a function handle to anonymous functions for validators
+##     val_mat = @@(x)isvector(x) && all( x <= 1) && all(x >= 0);
+##     p = p.addOptional ("mat", [0 0], @@val_mat);
+##
+##     ## create two ParamValue type of arguments
+##     val_type = @@(x) ischar(x) && any(strcmp(x, @{"linear", "quadratic"@});
+##     p = p.addParamValue ("type", "linear", @@val_type);
+##     val_verb = @@(x) ischar(x) && any(strcmp(x, @{"low", "medium", "high"@});
+##     p = p.addParamValue ("tolerance", "low", @@val_verb);
+##
+##     ## create a switch type of argument
+##     p = p.addSwitch ("verbose");
+##
+##     p = p.parse (pack, path, mat, varargin@{:@});
+##
+##     ## the rest of the function can access the input by accessing p.Results
+##     ## for example, to access the value of tolerance, use p.Results.tolerance
+## endfunction
+##
+## check ("mech");            # valid, will use defaults for other arguments
+## check ();                  # error since at least one argument is mandatory
+## check (1);                 # error since !ischar
+## check ("mech", "~/dev");   # valid, will use defaults for other arguments
+##
+## check ("mech", "~/dev", [0 1 0 0], "type", "linear");  # valid
+##
+## ## the following is also valid. Note how the Switch type of argument can be
+## ## mixed into or before the ParamValue (but still after Optional)
+## check ("mech", "~/dev", [0 1 0 0], "verbose", "tolerance", "high");
+##
+## ## the following returns an error since not all optional arguments, `path' and
+## ## `mat', were given before the named argument `type'.
+## check ("mech", "~/dev", "type", "linear");
+## @end group
+## @end example
+##
+## @emph{Note 1}: a function can have any mixture of the four API types but they
+## must appear in a specific order. @command{Required} arguments must be the very
+## first which can be followed by @command{Optional} arguments. Only the
+## @command{ParamValue} and @command{Switch} arguments can be mixed together but
+## must be at the end.
+##
+## @emph{Note 2}: if both @command{Optional} and @command{ParamValue} 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,
+## @@inputParser/createCopy, @@inputParser/parse}
+## @end deftypefn
+
+function inPar = inputParser
+
+  if (nargin != 0)
+    print_usage;
+  endif
+
+  inPar = struct;
+
+  ## these are not to be accessed by users. Each will have a field whose names
+  ## are the argnames which will also be a struct with fieldnames 'validator'
+  ## and 'default'
+  inPar.ParamValue    = struct;
+  inPar.Optional      = struct;
+  inPar.Required      = struct;
+  inPar.Switch        = struct;
+
+  ## this will be filled when the methodd parse is used and will be a struct whose
+  ## fieldnames are the argnames that return their value
+  inPar.Results       = struct;
+
+  ## an 1xN cell array with argnames. It is read only by the user and its order
+  ## showws the order that they were added to the object (which is the order they
+  ## will be expected)
+  inPar.Parameters    = {};
+
+  inPar.CaseSensitive = false;
+  inPar.FunctionName  = '';      # name of the function for the error message
+  inPar.KeepUnmatched = false;
+  inPar.StructExpand  = true;
+  inPar.Unmatched     = struct;
+  inPar.UsingDefaults = {};
+
+  inPar = class (inPar, 'inputParser');
+
+endfunction
+
+%!shared p, out
+%! p = inputParser;
+%! p = p.addRequired   ("req1", @(x) ischar (x));
+%! p = p.addOptional   ("op1", "val", @(x) ischar (x) && any (strcmp (x, {"val", "foo"})));
+%! p = p.addOptional   ("op2", 78, @(x) (x) > 50);
+%! p = p.addSwitch     ("verbose");
+%! p = p.addParamValue ("line", "tree", @(x) ischar (x) && any (strcmp (x, {"tree", "circle"})));
+%! ## check normal use, only required are given
+%! out = p.parse ("file");
+%!assert ({out.Results.req1, out.Results.op1, out.Results.op2, out.Results.verbose, out.Results.line}, 
+%!        {"file"          , "val"          , 78             , false              , "tree"});
+%!assert (out.UsingDefaults, {"op1", "op2", "verbose", "line"});
+%! ## check normal use, but give values different than defaults
+%! out = p.parse ("file", "foo", 80, "line", "circle", "verbose");
+%!assert ({out.Results.req1, out.Results.op1, out.Results.op2, out.Results.verbose, out.Results.line}, 
+%!        {"file"          , "foo"          , 80             , true              , "circle"});
+%! ## check optional is skipped and considered ParamValue if unvalidated string
+%! out = p.parse ("file", "line", "circle");
+%!assert ({out.Results.req1, out.Results.op1, out.Results.op2, out.Results.verbose, out.Results.line}, 
+%!        {"file"          , "val"          , 78             , false              , "circle"});
+%! ## check case insensitivity
+%! out = p.parse ("file", "foo", 80, "LiNE", "circle", "vERbOSe");
+%!assert ({out.Results.req1, out.Results.op1, out.Results.op2, out.Results.verbose, out.Results.line}, 
+%!        {"file"          , "foo"          , 80             , true              , "circle"});
+%! ## check KeepUnmatched
+%! p.KeepUnmatched = true;
+%! out = p.parse ("file", "foo", 80, "line", "circle", "verbose", "extra", 50);
+%!assert (out.Unmatched.extra, 50)
+%! ## check error when missing required
+%!error(p.parse())
+%! ## check error when given required do not validate
+%!error(p.parse(50))
+%! ## check error when given optional do not validate
+%!error(p.parse("file", "no-val"))
+%! ## check error when given ParamValue do not validate
+%!error(p.parse("file", "foo", 51, "line", "round"))
+
+## check alternative method (obj), ...) API
+%!shared p, out
+%! p = inputParser;
+%! p = addRequired   (p, "req1", @(x) ischar (x));
+%! p = addOptional   (p, "op1", "val", @(x) ischar (x) && any (strcmp (x, {"val", "foo"})));
+%! p = addOptional   (p, "op2", 78, @(x) (x) > 50);
+%! p = addSwitch     (p, "verbose");
+%! p = addParamValue (p, "line", "tree", @(x) ischar (x) && any (strcmp (x, {"tree", "circle"})));
+%! ## check normal use, only required are given
+%! out = parse (p, "file");
+%!assert ({out.Results.req1, out.Results.op1, out.Results.op2, out.Results.verbose, out.Results.line}, 
+%!        {"file"          , "val"          , 78             , false              , "tree"});
+%!assert (out.UsingDefaults, {"op1", "op2", "verbose", "line"});
+%! ## check normal use, but give values different than defaults
+%! out = parse (p, "file", "foo", 80, "line", "circle", "verbose");
+%!assert ({out.Results.req1, out.Results.op1, out.Results.op2, out.Results.verbose, out.Results.line}, 
+%!        {"file"          , "foo"          , 80             , true              , "circle"});
+
+## if we were matlab compatible...
+%!shared p, out
+%! p = inputParser;
+%! p = p.addOptional   ("op1", "val");
+%! p = p.addParamValue ("line", "tree");
+%!xtest assert (getfield (p.parse("line", "circle"), "Results"), struct ("op1", "val", "line", "circle"));