Argument validation and config file

1 view (last 30 days)
Martin Hock
Martin Hock on 22 Mar 2022
Answered: Ravi on 21 Dec 2023
We've written a little tool andsome options can be stored in a config file.
So for options, they can be read from the config file or handed over manually as name/value-pairs, and we also have defaults defined in the argument validation.
At this point, the config file takes priority over default and manual input, because it is read after the argument validation, and we cannot differentiate between manual inputs and defaults after the validation.
I'll add some code to show what the issue is.
function math(numbers, options)
arguments
numbers (1,1) {mustBeNumeric} = [1,1]
options.basic (1,:) {mustBeText} = 'add'
end
% At this point I don't know, whether options.basic is from argument or default
% test for config file
if exist('config.json')
configfromfile = jsondecode('config.json');
if isfield(configfromfile,basic)
options.basic = configfromfile.basic;
end % Overwriting with config file.
end
% do maths here
switch basic
case 'add'
add(numbers)
end
end
So at the moment the priority is config file > argument > default
But obviously we'd want to have a "user defined default" in the config file, and possible adjustments via argument: argument > config file > default.
The only way I can think of doing this is by using a wrapper, that is already testing the config file and reading its values, and compiling options for the inner function.
function math(numbers, options)
% test for config file
if exist('config.json')
configfromfile = jsondecode('config.json');
for i=fieldnames(configfromfile)
if ~isfield(options.(i)) % manual input gets priority
options.(i)=configfromfile.(i)
end
end
end
realmath(numbers, options)
end
function realmath(numbers, options)
arguments
numbers (1,1) {mustBeNumeric} = [1,1]
options.basic (1,:) {mustBeText} = 'add'
end
% do maths here
switch basic
case 'add'
add(numbers)
end
end
So what would be the elegant way to handle this?

Answers (1)

Ravi
Ravi on 21 Dec 2023
Hi Martin Hock,
Please find an approach for prioritizing the inputs in the order arguments > config > default.
function math(numbers, options)
% Define the default options
defaultOptions = struct('basic', 'add');
% If a config file exists, read it and merge with default options
if exist('config.json')
configOptions = jsondecode(configFile);
optionsFromConfig = mergeOptions(defaultOptions, configOptions);
else
optionsFromConfig = defaultOptions;
end
% If options are provided manually, merge them with options from config
finalOptions = mergeOptions(optionsFromConfig, options);
% Do the math operation based on the final options
switch finalOptions.basic
case 'add'
% Call the add function with the provided numbers
result = add(numbers);
end
end
function mergedOptions = mergeOptions(defaults, overrides)
% Merge two structures, where fields in 'overrides' take precedence
mergedOptions = defaults;
overrideFields = fieldnames(overrides);
for i = 1:numel(overrideFields)
mergedOptions.(overrideFields{i}) = overrides.(overrideFields{i});
end
end
We create a variable “defaultOptions” to store the defaults. We check for the “config.json” file and if it exists we merge the options with the already created “defaultOptions”. In this situation, the “config.json” gets priority over “defaultOptions” and if any variable present in “config.json” is already present in “defaultOptions”, then it gets overridden.
Next, we create a variable, “finalOptions” that combines the options from config file, default options, and passed arguments.
The “mergeOptions” function takes two arguments; second one takes higher priority over the other. The variables are overridden with the second argument.
Hope this helps.
Thanks,
Ravi Chandra

Categories

Find more on Interactive Control and Callbacks in Help Center and File Exchange

Products


Release

R2021b

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!