Mercurial > hg > octave-nkf
comparison scripts/general/inputParser.m @ 19227:ff820f92cbb5
inputParser: classdef port of @inputParser from Octave Forge general pkg.
* scripts/general/classdef.m: an almost Matlab compatible version of this
class was part of the Octave Forge general package since 2011, and made use
of @class syntax. With classdef now implemented in Octave, this is a port
of that function with the incompatibilities fixed. The help text needs to
be adapted after a new format is decided for this files.
* scripts/general/module.mk: add new file to the build system.
* NEWS: reference new class.
* doc/interpreter/func.texi: add DOCSTRING on the manual.
author | Carnë Draug <carandraug@octave.org> |
---|---|
date | Wed, 20 Aug 2014 00:24:03 +0100 |
parents | |
children | d900f863335c |
comparison
equal
deleted
inserted
replaced
19226:f707835af867 | 19227:ff820f92cbb5 |
---|---|
1 ## Copyright (C) 2011-2014 Carnë Draug | |
2 ## | |
3 ## This file is part of Octave. | |
4 ## | |
5 # Octave is free software; you can redistribute it and/or modify it | |
6 ## under the terms of the GNU General Public License as published by | |
7 ## the Free Software Foundation; either version 3 of the License, or (at | |
8 ## your option) any later version. | |
9 ## | |
10 ## Octave is distributed in the hope that it will be useful, but | |
11 ## WITHOUT ANY WARRANTY; without even the implied warranty of | |
12 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
13 ## General Public License for more details. | |
14 ## | |
15 ## You should have received a copy of the GNU General Public License | |
16 ## along with Octave; see the file COPYING. If not, see | |
17 ## <http://www.gnu.org/licenses/>. | |
18 | |
19 ## -*- texinfo -*- | |
20 ## @deftypefn {Function File} {} inputParser () | |
21 ## Create object @var{parser} of the inputParser class. | |
22 ## | |
23 ## This class is designed to allow easy parsing of function arguments. This | |
24 ## class supports four types of arguments: | |
25 ## | |
26 ## @enumerate | |
27 ## @item mandatory (see @command{addRequired}); | |
28 ## @item optional (see @command{addOptional}); | |
29 ## @item named (see @command{addParamValue}); | |
30 ## @item switch (see @command{addSwitch}). | |
31 ## @end enumerate | |
32 ## | |
33 ## After defining the function API with this methods, the supplied arguments | |
34 ## can be parsed with the @command{parse} method and the parsing results | |
35 ## accessed with the @command{Results} accessor. | |
36 ## | |
37 ## @deftypefnx {Accessor method} parser.Parameters | |
38 ## Return list of parameters name already defined. | |
39 ## | |
40 ## @deftypefnx {Accessor method} parser.Results | |
41 ## Return structure with argument names as fieldnames and corresponding values. | |
42 ## | |
43 ## @deftypefnx {Accessor method} parser.Unmatched | |
44 ## Return structure similar to @command{Results} for unmatched parameters. See | |
45 ## the @command{KeepUnmatched} property. | |
46 ## | |
47 ## @deftypefnx {Accessor method} parser.UsingDefaults | |
48 ## Return cell array with the names of arguments that are using default values. | |
49 ## | |
50 ## @deftypefnx {Class property} parser.CaseSensitive = @var{boolean} | |
51 ## Set whether matching of argument names should be case sensitive. Defaults to false. | |
52 ## | |
53 ## @deftypefnx {Class property} parser.FunctionName = @var{name} | |
54 ## Set function name to be used on error messages. Defauls to empty string. | |
55 ## | |
56 ## @deftypefnx {Class property} parser.KeepUnmatched = @var{boolean} | |
57 ## Set whether an error should be given for non-defined arguments. Defaults to | |
58 ## false. If set to true, the extra arguments can be accessed through | |
59 ## @code{Unmatched} after the @code{parse} method. Note that since @command{Switch} | |
60 ## and @command{ParamValue} arguments can be mixed, it is not possible to know | |
61 ## the unmatched type. If argument is found unmatched it is assumed to be of the | |
62 ## @command{ParamValue} type and it is expected to be followed by a value. | |
63 ## | |
64 ## @deftypefnx {Class property} parser.StructExpand = @var{boolean} | |
65 ## Set whether a structure can be passed to the function instead of parameter | |
66 ## value pairs. Defaults to true. Not implemented yet. | |
67 ## | |
68 ## The following example shows how to use this class: | |
69 ## | |
70 ## @example | |
71 ## @group | |
72 ## function check (varargin) | |
73 ## p = inputParser (); # create object | |
74 ## p.FunctionName = "check"; # set function name | |
75 ## p.addRequired ("pack", @@ischar); # create mandatory argument | |
76 ## | |
77 ## p.addOptional ("path", pwd(), @@ischar); # create optional argument | |
78 ## | |
79 ## ## one can create a function handle to anonymous functions for validators | |
80 ## val_mat = @@(x) isvector (x) && all (x <= 1) && all (x >= 0); | |
81 ## p.addOptional ("mat", [0 0], val_mat); | |
82 ## | |
83 ## ## create two ParamValue type of arguments | |
84 ## val_type = @@(x) any (strcmp (x, @{"linear", "quadratic"@})); | |
85 ## p.addParamValue ("type", "linear", val_type); | |
86 ## val_verb = @@(x) any (strcmp (x, @{"low", "medium", "high"@})); | |
87 ## p.addParamValue ("tolerance", "low", val_verb); | |
88 ## | |
89 ## ## create a switch type of argument | |
90 ## p.addSwitch ("verbose"); | |
91 ## | |
92 ## p.parse (varargin@{:@}); | |
93 ## | |
94 ## ## the rest of the function can access the input by accessing p.Results | |
95 ## ## for example, to access the value of tolerance, use p.Results.tolerance | |
96 ## endfunction | |
97 ## | |
98 ## check ("mech"); # valid, will use defaults for other arguments | |
99 ## check (); # error since at least one argument is mandatory | |
100 ## check (1); # error since !ischar | |
101 ## check ("mech", "~/dev"); # valid, will use defaults for other arguments | |
102 ## | |
103 ## check ("mech", "~/dev", [0 1 0 0], "type", "linear"); # valid | |
104 ## | |
105 ## ## the following is also valid. Note how the Switch type of argument can be | |
106 ## ## mixed into or before the ParamValue (but still after Optional) | |
107 ## check ("mech", "~/dev", [0 1 0 0], "verbose", "tolerance", "high"); | |
108 ## | |
109 ## ## the following returns an error since not all optional arguments, `path' and | |
110 ## ## `mat', were given before the named argument `type'. | |
111 ## check ("mech", "~/dev", "type", "linear"); | |
112 ## @end group | |
113 ## @end example | |
114 ## | |
115 ## @emph{Note 1}: a function can have any mixture of the four API types but they | |
116 ## must appear in a specific order. @command{Required} arguments must be the very | |
117 ## first which can be followed by @command{Optional} arguments. Only the | |
118 ## @command{ParamValue} and @command{Switch} arguments can be mixed together but | |
119 ## must be at the end. | |
120 ## | |
121 ## @emph{Note 2}: if both @command{Optional} and @command{ParamValue} arguments | |
122 ## are mixed in a function API, once a string Optional argument fails to validate | |
123 ## against, it will be considered the end of @command{Optional} arguments and the | |
124 ## first key for a @command{ParamValue} and @command{Switch} arguments. | |
125 ## | |
126 ## @seealso{nargin, validateattributes, validatestring, varargin} | |
127 ## @end deftypefn | |
128 | |
129 ## -*- texinfo -*- | |
130 ## @deftypefnx {Function File} {} addOptional (@var{argname}, @var{default}) | |
131 ## @deftypefnx {Function File} {} addOptional (@var{argname}, @var{default}, @var{validator}) | |
132 ## Add new optional argument to the object @var{parser} of the class inputParser | |
133 ## to implement an ordered arguments type of API | |
134 ## | |
135 ## @var{argname} must be a string with the name of the new argument. The order | |
136 ## in which new arguments are added with @command{addOptional}, represents the | |
137 ## expected order of arguments. | |
138 ## | |
139 ## @var{default} will be the value used when the argument is not specified. | |
140 ## | |
141 ## @var{validator} is an optional anonymous function to validate the given values | |
142 ## for the argument with name @var{argname}. Alternatively, a function name | |
143 ## can be used. | |
144 ## | |
145 ## See @command{help inputParser} for examples. | |
146 ## | |
147 ## @emph{Note}: if a string argument does not validate, it will be considered a | |
148 ## ParamValue key. If an optional argument is not given a validator, anything | |
149 ## will be valid, and so any string will be considered will be the value of the | |
150 ## optional argument (in @sc{matlab}, if no validator is given and argument is | |
151 ## a string it will also be considered a ParamValue key). | |
152 ## | |
153 ## @end deftypefn | |
154 | |
155 ## -*- texinfo -*- | |
156 ## @deftypefn {Function File} {} addParamValue (@var{argname}, @var{default}) | |
157 ## @deftypefnx {Function File} {} addParamValue (@var{argname}, @var{default}, @var{validator}) | |
158 ## Add new parameter to the object @var{parser} of the class inputParser to implement | |
159 ## a name/value pair type of API. | |
160 ## | |
161 ## @var{argname} must be a string with the name of the new parameter. | |
162 ## | |
163 ## @var{default} will be the value used when the parameter is not specified. | |
164 ## | |
165 ## @var{validator} is an optional function handle to validate the given values | |
166 ## for the parameter with name @var{argname}. Alternatively, a function name | |
167 ## can be used. | |
168 ## | |
169 ## See @command{help inputParser} for examples. | |
170 ## | |
171 ## @end deftypefn | |
172 | |
173 ## -*- texinfo -*- | |
174 ## @deftypefn {Function File} {} addRequired (@var{argname}) | |
175 ## @deftypefnx {Function File} {} addRequired (@var{argname}, @var{validator}) | |
176 ## Add new mandatory argument to the object @var{parser} of inputParser class. | |
177 ## | |
178 ## This method belongs to the inputParser class and implements an ordered | |
179 ## arguments type of API. | |
180 ## | |
181 ## @var{argname} must be a string with the name of the new argument. The order | |
182 ## in which new arguments are added with @command{addrequired}, represents the | |
183 ## expected order of arguments. | |
184 ## | |
185 ## @var{validator} is an optional function handle to validate the given values | |
186 ## for the argument with name @var{argname}. Alternatively, a function name | |
187 ## can be used. | |
188 ## | |
189 ## See @command{help inputParser} for examples. | |
190 ## | |
191 ## @emph{Note}: this can be used together with the other type of arguments but | |
192 ## it must be the first (see @command{@@inputParser}). | |
193 ## | |
194 ## @end deftypefn | |
195 | |
196 ## -*- texinfo -*- | |
197 ## @deftypefn {Function File} {} addSwitch (@var{argname}) | |
198 ## Add new switch type of argument to the object @var{parser} of inputParser class. | |
199 ## | |
200 ## This method belongs to the inputParser class and implements a switch | |
201 ## arguments type of API. | |
202 ## | |
203 ## @var{argname} must be a string with the name of the new argument. Arguments | |
204 ## of this type can be specified at the end, after @code{Required} and @code{Optional}, | |
205 ## and mixed between the @code{ParamValue}. They default to false. If one of the | |
206 ## arguments supplied is a string like @var{argname}, then after parsing the value | |
207 ## of @var{parse}.Results.@var{argname} will be true. | |
208 ## | |
209 ## See @command{help inputParser} for examples. | |
210 ## | |
211 ## @end deftypefn | |
212 | |
213 ## -*- texinfo -*- | |
214 ## @deftypefn {Function File} {} parse (@var{varargin}) | |
215 ## Parses and validates list of arguments according to object @var{parser} of the | |
216 ## class inputParser. | |
217 ## | |
218 ## After parsing, the results can be accessed with the @command{Results} | |
219 ## accessor. See @command{help inputParser} for a more complete description. | |
220 ## | |
221 ## @end deftypefn | |
222 | |
223 ## Author: Carnë Draug <carandraug@octave.org> | |
224 | |
225 classdef inputParser < handle | |
226 properties | |
227 ## TODO set input checking for this properties | |
228 CaseSensitive = false; | |
229 FunctionName = ""; | |
230 KeepUnmatched = false; | |
231 # PartialMatching = true; # TODO unimplemented | |
232 # StructExpand = true; # TODO unimplemented | |
233 endproperties | |
234 | |
235 properties (SetAccess = protected) | |
236 Parameters = cell (); | |
237 Results = struct (); | |
238 Unmatched = struct (); | |
239 UsingDefaults = cell (); | |
240 endproperties | |
241 | |
242 properties (Access = protected) | |
243 ## Since Required and Optional are ordered, they get a cell array of | |
244 ## structs with the fields "name", "def" (default), and "val" (validator). | |
245 Required = cell (); | |
246 Optional = cell (); | |
247 ## ParamValue and Swicth are unordered so we have a struct whose fieldnames | |
248 ## are the argname, and values are a struct with fields "def" and "val" | |
249 ParamValue = struct (); | |
250 Switch = struct (); | |
251 | |
252 ## List of ParamValues and Switch names to ease searches | |
253 ParamValueNames = cell (); | |
254 SwitchNames = cell (); | |
255 | |
256 ## When checking for fieldnames in a Case Insensitive way, this variable | |
257 ## holds the correct identifier for the last searched named using the | |
258 ## is_argname method. | |
259 last_name = ""; | |
260 endproperties | |
261 | |
262 properties (Access = protected, Constant = true) | |
263 ## Default validator, always returns scalar true. | |
264 def_val = @() true; | |
265 endproperties | |
266 | |
267 methods | |
268 function addRequired (this, name, val = inputParser.def_val) | |
269 if (nargin < 2 || nargin > 3) | |
270 print_usage (); | |
271 elseif (numel (this.Optional) || numel (fieldnames (this.ParamValue)) | |
272 || numel (fieldnames (this.Switch))) | |
273 error (["inputParser.addRequired: can't have a Required argument " ... | |
274 "after Optional, ParamValue, or Switch"]); | |
275 endif | |
276 this.validate_name ("Required", name); | |
277 this.Required{end+1} = struct ("name", name, "val", val); | |
278 endfunction | |
279 | |
280 function addOptional (this, name, def, val = inputParser.def_val) | |
281 if (nargin < 3 || nargin > 4) | |
282 print_usage (); | |
283 elseif (numel (fieldnames (this.ParamValue)) | |
284 || numel (fieldnames (this.Switch))) | |
285 error (["inputParser.Optional: can't have Optional arguments " ... | |
286 "after ParamValue or Switch"]); | |
287 endif | |
288 this.validate_name ("Optional", name); | |
289 this.validate_default ("Optional", name, def, val); | |
290 this.Optional{end+1} = struct ("name", name, "def", def, "val", val); | |
291 endfunction | |
292 | |
293 function addParamValue (this, name, def, val = inputParser.def_val) | |
294 if (nargin < 3 || nargin > 4) | |
295 print_usage (); | |
296 endif | |
297 this.validate_name ("ParamValue", name); | |
298 this.validate_default ("ParamValue", name, def, val); | |
299 this.ParamValue.(name).def = def; | |
300 this.ParamValue.(name).val = val; | |
301 endfunction | |
302 | |
303 function addSwitch (this, name) | |
304 if (nargin != 2) | |
305 print_usage (); | |
306 endif | |
307 this.validate_name ("Switch", name); | |
308 this.Switch.(name).def = false; | |
309 endfunction | |
310 | |
311 function parse (this, varargin) | |
312 if (numel (varargin) < numel (this.Required)) | |
313 if (this.FunctionName) | |
314 print_usage (this.FunctionName); | |
315 else | |
316 this.error ("not enough input arguments"); | |
317 endif | |
318 endif | |
319 pnargin = numel (varargin); | |
320 | |
321 this.ParamValueNames = fieldnames (this.ParamValue); | |
322 this.SwitchNames = fieldnames (this.Switch); | |
323 | |
324 ## Evaluate the Required arguments first | |
325 nReq = numel (this.Required); | |
326 for idx = 1:nReq | |
327 req = this.Required{idx}; | |
328 this.validate_arg (req.name, req.val, varargin{idx}); | |
329 endfor | |
330 | |
331 vidx = nReq; # current index in varargin | |
332 | |
333 ## Search for a list of Optional arguments | |
334 idx = 0; # current index on the array of Optional | |
335 nOpt = numel (this.Optional); | |
336 while (vidx < pnargin && idx < nOpt) | |
337 opt = this.Optional{++idx}; | |
338 in = varargin{++vidx}; | |
339 if (! opt.val (in)) | |
340 ## If it does not match there's two options: | |
341 ## 1) input is actually wrong and we should error; | |
342 ## 2) it's a ParamValue or Switch name and we should use the | |
343 ## the default for the rest. | |
344 if (ischar (in)) | |
345 idx--; | |
346 vidx--; | |
347 break | |
348 else | |
349 this.error (sprintf ("failed validation of %s", | |
350 toupper (opt.name))); | |
351 endif | |
352 endif | |
353 this.Results.(opt.name) = in; | |
354 endwhile | |
355 | |
356 ## Fill in with defaults of missing Optional | |
357 while (idx++ < nOpt) | |
358 opt = this.Optional{idx}; | |
359 this.UsingDefaults{end+1} = opt.name; | |
360 this.Results.(opt.name) = opt.def; | |
361 endwhile | |
362 | |
363 ## Search unordered Options (Switch and ParamValue) | |
364 while (vidx++ < pnargin) | |
365 name = varargin{vidx}; | |
366 if (this.is_argname ("ParamValue", name)) | |
367 if (vidx++ > pnargin) | |
368 this.error (sprintf ("no matching value for option '%s'", | |
369 toupper (name))); | |
370 endif | |
371 this.validate_arg (this.last_name, this.ParamValue.(this.last_name).val, | |
372 varargin{vidx}); | |
373 elseif (this.is_argname ("Switch", name)) | |
374 this.Results.(this.last_name) = true; | |
375 else | |
376 if (vidx++ < pnargin && this.KeepUnmatched) | |
377 this.Unmatched.(name) = varargin{vidx}; | |
378 else | |
379 this.error (sprintf ("argument '%s' is not a valid parameter", | |
380 toupper (name))); | |
381 endif | |
382 endif | |
383 endwhile | |
384 ## Add them to the UsingDeafults list | |
385 this.add_missing ("ParamValue"); | |
386 this.add_missing ("Switch"); | |
387 | |
388 endfunction | |
389 | |
390 function display (this) | |
391 if (nargin > 1) | |
392 print_usage (); | |
393 endif | |
394 printf ("inputParser object with properties:\n\n"); | |
395 b2s = @(x) ifelse (any (x), "true", "false"); | |
396 printf ([" CaseSensitive : %s\n FunctionName : %s\n" ... | |
397 " KeepUnmatched : %s\n PartialMatching : %s\n" ... | |
398 " StructExpand : %s\n\n"], | |
399 b2s (this.CaseSensitive), b2s (this.FunctionName), | |
400 b2s (this.KeepUnmatched), b2s (this.PartialMatching), | |
401 b2s (this.StructExpand)); | |
402 printf ("Defined parameters:\n\n {%s}\n", | |
403 strjoin (this.Parameters, ", ")); | |
404 endfunction | |
405 endmethods | |
406 | |
407 methods (Access = private) | |
408 function validate_name (this, type, name) | |
409 if (! isvarname (name)) | |
410 error ("inputParser.add%s: NAME is an invalid identifier", method); | |
411 elseif (any (strcmpi (this.Parameters, name))) | |
412 ## Even if CaseSensitive is "on", we still shouldn't allow | |
413 ## two args with the same name. | |
414 error ("inputParser.add%s: argname '%s' has already been specified", | |
415 type, name); | |
416 endif | |
417 this.Parameters{end+1} = name; | |
418 endfunction | |
419 | |
420 function validate_default (this, type, name, def, val) | |
421 if (! feval (val, def)) | |
422 error ("inputParser.add%s: failed validation for '%s' default value", | |
423 type, name); | |
424 endif | |
425 endfunction | |
426 | |
427 function validate_arg (this, name, val, in) | |
428 if (! val (in)) | |
429 this.error (sprintf ("failed validation of %s", toupper (name))); | |
430 endif | |
431 this.Results.(name) = in; | |
432 endfunction | |
433 | |
434 function r = is_argname (this, type, name) | |
435 if (this.CaseSensitive) | |
436 r = isfield (this.(type), name); | |
437 this.last_name = name; | |
438 else | |
439 fnames = this.([type "Names"]); | |
440 l = strcmpi (name, fnames); | |
441 r = any (l(:)); | |
442 if (r) | |
443 this.last_name = fnames{l}; | |
444 endif | |
445 endif | |
446 endfunction | |
447 | |
448 function add_missing (this, type) | |
449 unmatched = setdiff (fieldnames (this.(type)), fieldnames (this.Results)); | |
450 for namec = unmatched(:)' | |
451 name = namec{1}; | |
452 this.UsingDefaults{end+1} = name; | |
453 this.Results.(name) = this.(type).(name).def; | |
454 endfor | |
455 endfunction | |
456 | |
457 function error (this, msg) | |
458 where = ""; | |
459 if (this.FunctionName) | |
460 where = [this.FunctionName ": "]; | |
461 endif | |
462 error ("%s%s", where, msg); | |
463 endfunction | |
464 endmethods | |
465 | |
466 endclassdef | |
467 | |
468 %!function p = create_p () | |
469 %! p = inputParser (); | |
470 %! p.CaseSensitive = true; | |
471 %! p.addRequired ("req1", @(x) ischar (x)); | |
472 %! p.addOptional ("op1", "val", @(x) any (strcmp (x, {"val", "foo"}))); | |
473 %! p.addOptional ("op2", 78, @(x) x > 50); | |
474 %! p.addSwitch ("verbose"); | |
475 %! p.addParamValue ("line", "tree", @(x) any (strcmp (x, {"tree", "circle"}))); | |
476 %!endfunction | |
477 | |
478 ## check normal use, only required are given | |
479 %!test | |
480 %! p = create_p (); | |
481 %! p.parse ("file"); | |
482 %! r = p.Results; | |
483 %! assert (r.req1, "file"); | |
484 %! assert (sort (p.UsingDefaults), sort ({"op1", "op2", "verbose", "line"})); | |
485 %! assert ({r.req1, r.op1, r.op2, r.verbose, r.line}, | |
486 %! {"file", "val", 78, false, "tree"}); | |
487 | |
488 ## check normal use, but give values different than defaults | |
489 %!test | |
490 %! p = create_p (); | |
491 %! p.parse ("file", "foo", 80, "line", "circle", "verbose"); | |
492 %! r = p.Results; | |
493 %! assert ({r.req1, r.op1, r.op2, r.verbose, r.line}, | |
494 %! {"file", "foo", 80, true, "circle"}); | |
495 | |
496 ## check optional is skipped and considered ParamValue if unvalidated string | |
497 %!test | |
498 %! p = create_p (); | |
499 %! p.parse ("file", "line", "circle"); | |
500 %! r = p.Results; | |
501 %! assert ({r.req1, r.op1, r.op2, r.verbose, r.line}, | |
502 %! {"file", "val", 78, false, "circle"}); | |
503 | |
504 ## check case insensitivity | |
505 %!test | |
506 %! p = create_p (); | |
507 %! p.CaseSensitive = false; | |
508 %! p.parse ("file", "foo", 80, "LiNE", "circle", "vERbOSe"); | |
509 %! r = p.Results; | |
510 %! assert ({r.req1, r.op1, r.op2, r.verbose, r.line}, | |
511 %! {"file", "foo", 80, true, "circle"}); | |
512 | |
513 ## check KeepUnmatched | |
514 %!test | |
515 %! p = create_p (); | |
516 %! p.KeepUnmatched = true; | |
517 %! p.parse ("file", "foo", 80, "line", "circle", "verbose", "extra", 50); | |
518 %! assert (p.Unmatched.extra, 50) | |
519 | |
520 ## check error when missing required | |
521 %!error <not enough input arguments> | |
522 %! p = create_p (); | |
523 %! p.parse (); | |
524 | |
525 ## check error when given required does not validate | |
526 %!error <failed validation of > | |
527 %! p = create_p (); | |
528 %! p.parse (50); | |
529 | |
530 ## check error when given optional does not validate | |
531 %!error <is not a valid parameter> | |
532 %! p = create_p (); | |
533 %! p.parse ("file", "no-val"); | |
534 | |
535 ## check error when given ParamValue does not validate | |
536 %!error <failed validation of > | |
537 %! p = create_p (); | |
538 %! p.parse ("file", "foo", 51, "line", "round"); | |
539 | |
540 ## check alternative method (obj, ...) API | |
541 %!function p2 = create_p2 (); | |
542 %! p2 = inputParser; | |
543 %! addRequired (p2, "req1", @(x) ischar (x)); | |
544 %! addOptional (p2, "op1", "val", @(x) any (strcmp (x, {"val", "foo"}))); | |
545 %! addOptional (p2, "op2", 78, @(x) x > 50); | |
546 %! addSwitch (p2, "verbose"); | |
547 %! addParamValue (p2, "line", "tree", @(x) any (strcmp (x, {"tree", "circle"}))); | |
548 %!endfunction | |
549 | |
550 ## check normal use, only required are given | |
551 %!test | |
552 %! p2 = create_p2 (); | |
553 %! parse (p2, "file"); | |
554 %! r = p2.Results; | |
555 %! assert ({r.req1, r.op1, r.op2, r.verbose, r.line}, | |
556 %! {"file", "val", 78, false, "tree"}); | |
557 %! assert (sort (p2.UsingDefaults), sort ({"op1", "op2", "verbose", "line"})); | |
558 | |
559 ## check normal use, but give values different than defaults | |
560 %!test | |
561 %! p2 = create_p2 (); | |
562 %! parse (p2, "file", "foo", 80, "line", "circle", "verbose"); | |
563 %! r = p2.Results; | |
564 %! assert ({r.req1, r.op1, r.op2, r.verbose, r.line}, | |
565 %! {"file", "foo", 80, true, "circle"}); | |
566 | |
567 ## FIXME: This somehow works in Matlab | |
568 #%!test | |
569 #%! p = inputParser; | |
570 #%! p.addOptional ("op1", "val"); | |
571 #%! p.addParamValue ("line", "tree"); | |
572 #%! p.parse ("line", "circle"); | |
573 #%! assert (p.Results, struct ("op1", "val", "line", "circle")); |