]> Creatis software - CreaPhase.git/blob - 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
1 ## Copyright (C) 2011-2012 CarnĂ« Draug <carandraug+dev@gmail.com>
2 ##
3 ## This program is free software; you can redistribute it and/or modify it under
4 ## the terms of the GNU General Public License as published by the Free Software
5 ## Foundation; either version 3 of the License, or (at your option) any later
6 ## version.
7 ##
8 ## This program is distributed in the hope that it will be useful, but WITHOUT
9 ## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 ## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
11 ## details.
12 ##
13 ## You should have received a copy of the GNU General Public License along with
14 ## this program; if not, see <http://www.gnu.org/licenses/>.
15
16 ## -*- texinfo -*-
17 ## @deftypefn {Function File} {@var{parser} =} inputParser ()
18 ## Create object @var{parser} of the inputParser class.
19 ##
20 ## This class is designed to allow easy parsing of function arguments. This class
21 ## supports four types of arguments:
22 ##
23 ## @enumerate
24 ## @item mandatory (see @command{@@inputParser/addRequired});
25 ## @item optional (see @command{@@inputParser/addOptional});
26 ## @item named (see @command{@@inputParser/addParamValue});
27 ## @item switch (see @command{@@inputParser/addSwitch}).
28 ## @end enumerate
29 ##
30 ## After defining the function API with this methods, the supplied arguments can
31 ## be parsed with the @command{@@inputParser/parse} method and the parsing results
32 ## accessed with the @command{Results} accessor.
33 ##
34 ## @deftypefnx {Accessor method} parser.Parameters
35 ## Return list of parameters name already defined.
36 ##
37 ## @deftypefnx {Accessor method} parser.Results
38 ## Return structure with argument names as fieldnames and corresponding values.
39 ##
40 ## @deftypefnx {Accessor method} parser.Unmatched
41 ## Return structure similar to @command{Results} for unmatched parameters. See
42 ## the @command{KeepUnmatched} property.
43 ##
44 ## @deftypefnx {Accessor method} parser.UsingDefaults
45 ## Return cell array with the names of arguments that are using default values.
46 ##
47 ## @deftypefnx {Class property} parser.CaseSensitive = @var{boolean}
48 ## Set whether matching of argument names should be case sensitive. Defaults to false.
49 ##
50 ## @deftypefnx {Class property} parser.FunctionName = @var{name}
51 ## Set function name to be used on error messages. Defauls to empty string.
52 ##
53 ## @deftypefnx {Class property} parser.KeepUnmatched = @var{boolean}
54 ## Set whether an error should be given for non-defined arguments. Defaults to
55 ## false. If set to true, the extra arguments can be accessed through
56 ## @code{Unmatched} after the @code{parse} method. Note that since @command{Switch}
57 ## and @command{ParamValue} arguments can be mixed, it is not possible to know
58 ## the unmatched type. If argument is found unmatched it is assumed to be of the
59 ## @command{ParamValue} type and it is expected to be followed by a value.
60 ##
61 ## @deftypefnx {Class property} parser.StructExpand = @var{boolean}
62 ## Set whether a structure can be passed to the function instead of parameter
63 ## value pairs. Defaults to true. Not implemented yet.
64 ##
65 ## The following example shows how to use this class:
66 ##
67 ## @example
68 ## @group
69 ## function check (pack, path, mat, varargin)
70 ##     p = inputParser;                             # create object
71 ##     p.FunctionName = "check";                    # set function name
72 ##     p = p.addRequired ("pack", @@ischar);         # create mandatory argument
73 ##
74 ##     p = p.addOptional ("path", pwd(), @@ischar);  # create optional argument
75 ##
76 ##     ## one can create a function handle to anonymous functions for validators
77 ##     val_mat = @@(x)isvector(x) && all( x <= 1) && all(x >= 0);
78 ##     p = p.addOptional ("mat", [0 0], @@val_mat);
79 ##
80 ##     ## create two ParamValue type of arguments
81 ##     val_type = @@(x) ischar(x) && any(strcmp(x, @{"linear", "quadratic"@});
82 ##     p = p.addParamValue ("type", "linear", @@val_type);
83 ##     val_verb = @@(x) ischar(x) && any(strcmp(x, @{"low", "medium", "high"@});
84 ##     p = p.addParamValue ("tolerance", "low", @@val_verb);
85 ##
86 ##     ## create a switch type of argument
87 ##     p = p.addSwitch ("verbose");
88 ##
89 ##     p = p.parse (pack, path, mat, varargin@{:@});
90 ##
91 ##     ## the rest of the function can access the input by accessing p.Results
92 ##     ## for example, to access the value of tolerance, use p.Results.tolerance
93 ## endfunction
94 ##
95 ## check ("mech");            # valid, will use defaults for other arguments
96 ## check ();                  # error since at least one argument is mandatory
97 ## check (1);                 # error since !ischar
98 ## check ("mech", "~/dev");   # valid, will use defaults for other arguments
99 ##
100 ## check ("mech", "~/dev", [0 1 0 0], "type", "linear");  # valid
101 ##
102 ## ## the following is also valid. Note how the Switch type of argument can be
103 ## ## mixed into or before the ParamValue (but still after Optional)
104 ## check ("mech", "~/dev", [0 1 0 0], "verbose", "tolerance", "high");
105 ##
106 ## ## the following returns an error since not all optional arguments, `path' and
107 ## ## `mat', were given before the named argument `type'.
108 ## check ("mech", "~/dev", "type", "linear");
109 ## @end group
110 ## @end example
111 ##
112 ## @emph{Note 1}: a function can have any mixture of the four API types but they
113 ## must appear in a specific order. @command{Required} arguments must be the very
114 ## first which can be followed by @command{Optional} arguments. Only the
115 ## @command{ParamValue} and @command{Switch} arguments can be mixed together but
116 ## must be at the end.
117 ##
118 ## @emph{Note 2}: if both @command{Optional} and @command{ParamValue} arguments
119 ## are mixed in a function API, once a string Optional argument fails to validate
120 ## against, it will be considered the end of @command{Optional} arguments and the
121 ## first key for a @command{ParamValue} and @command{Switch} arguments.
122 ##
123 ## @seealso{@@inputParser/addOptional, @@inputParser/addSwitch,
124 ## @@inputParser/addParamValue, @@inputParser/addRequired,
125 ## @@inputParser/createCopy, @@inputParser/parse}
126 ## @end deftypefn
127
128 function inPar = inputParser
129
130   if (nargin != 0)
131     print_usage;
132   endif
133
134   inPar = struct;
135
136   ## these are not to be accessed by users. Each will have a field whose names
137   ## are the argnames which will also be a struct with fieldnames 'validator'
138   ## and 'default'
139   inPar.ParamValue    = struct;
140   inPar.Optional      = struct;
141   inPar.Required      = struct;
142   inPar.Switch        = struct;
143
144   ## this will be filled when the methodd parse is used and will be a struct whose
145   ## fieldnames are the argnames that return their value
146   inPar.Results       = struct;
147
148   ## an 1xN cell array with argnames. It is read only by the user and its order
149   ## showws the order that they were added to the object (which is the order they
150   ## will be expected)
151   inPar.Parameters    = {};
152
153   inPar.CaseSensitive = false;
154   inPar.FunctionName  = '';      # name of the function for the error message
155   inPar.KeepUnmatched = false;
156   inPar.StructExpand  = true;
157   inPar.Unmatched     = struct;
158   inPar.UsingDefaults = {};
159
160   inPar = class (inPar, 'inputParser');
161
162 endfunction
163
164 %!shared p, out
165 %! p = inputParser;
166 %! p = p.addRequired   ("req1", @(x) ischar (x));
167 %! p = p.addOptional   ("op1", "val", @(x) ischar (x) && any (strcmp (x, {"val", "foo"})));
168 %! p = p.addOptional   ("op2", 78, @(x) (x) > 50);
169 %! p = p.addSwitch     ("verbose");
170 %! p = p.addParamValue ("line", "tree", @(x) ischar (x) && any (strcmp (x, {"tree", "circle"})));
171 %! ## check normal use, only required are given
172 %! out = p.parse ("file");
173 %!assert ({out.Results.req1, out.Results.op1, out.Results.op2, out.Results.verbose, out.Results.line}, 
174 %!        {"file"          , "val"          , 78             , false              , "tree"});
175 %!assert (out.UsingDefaults, {"op1", "op2", "verbose", "line"});
176 %! ## check normal use, but give values different than defaults
177 %! out = p.parse ("file", "foo", 80, "line", "circle", "verbose");
178 %!assert ({out.Results.req1, out.Results.op1, out.Results.op2, out.Results.verbose, out.Results.line}, 
179 %!        {"file"          , "foo"          , 80             , true              , "circle"});
180 %! ## check optional is skipped and considered ParamValue if unvalidated string
181 %! out = p.parse ("file", "line", "circle");
182 %!assert ({out.Results.req1, out.Results.op1, out.Results.op2, out.Results.verbose, out.Results.line}, 
183 %!        {"file"          , "val"          , 78             , false              , "circle"});
184 %! ## check case insensitivity
185 %! out = p.parse ("file", "foo", 80, "LiNE", "circle", "vERbOSe");
186 %!assert ({out.Results.req1, out.Results.op1, out.Results.op2, out.Results.verbose, out.Results.line}, 
187 %!        {"file"          , "foo"          , 80             , true              , "circle"});
188 %! ## check KeepUnmatched
189 %! p.KeepUnmatched = true;
190 %! out = p.parse ("file", "foo", 80, "line", "circle", "verbose", "extra", 50);
191 %!assert (out.Unmatched.extra, 50)
192 %! ## check error when missing required
193 %!error(p.parse())
194 %! ## check error when given required do not validate
195 %!error(p.parse(50))
196 %! ## check error when given optional do not validate
197 %!error(p.parse("file", "no-val"))
198 %! ## check error when given ParamValue do not validate
199 %!error(p.parse("file", "foo", 51, "line", "round"))
200
201 ## check alternative method (obj), ...) API
202 %!shared p, out
203 %! p = inputParser;
204 %! p = addRequired   (p, "req1", @(x) ischar (x));
205 %! p = addOptional   (p, "op1", "val", @(x) ischar (x) && any (strcmp (x, {"val", "foo"})));
206 %! p = addOptional   (p, "op2", 78, @(x) (x) > 50);
207 %! p = addSwitch     (p, "verbose");
208 %! p = addParamValue (p, "line", "tree", @(x) ischar (x) && any (strcmp (x, {"tree", "circle"})));
209 %! ## check normal use, only required are given
210 %! out = parse (p, "file");
211 %!assert ({out.Results.req1, out.Results.op1, out.Results.op2, out.Results.verbose, out.Results.line}, 
212 %!        {"file"          , "val"          , 78             , false              , "tree"});
213 %!assert (out.UsingDefaults, {"op1", "op2", "verbose", "line"});
214 %! ## check normal use, but give values different than defaults
215 %! out = parse (p, "file", "foo", 80, "line", "circle", "verbose");
216 %!assert ({out.Results.req1, out.Results.op1, out.Results.op2, out.Results.verbose, out.Results.line}, 
217 %!        {"file"          , "foo"          , 80             , true              , "circle"});
218
219 ## if we were matlab compatible...
220 %!shared p, out
221 %! p = inputParser;
222 %! p = p.addOptional   ("op1", "val");
223 %! p = p.addParamValue ("line", "tree");
224 %!xtest assert (getfield (p.parse("line", "circle"), "Results"), struct ("op1", "val", "line", "circle"));