|
| 1 | +function datasetConfiguration = applyCustomMatNWBPropertyNames(datasetConfiguration) |
| 2 | +% applyCustomMatNWBPropertyNames - Processes a dataset configuration structure to apply custom MatNWB property names. |
| 3 | +% |
| 4 | +% datasetConfiguration = applyCustomMatNWBPropertyNames(datasetConfiguration) |
| 5 | +% |
| 6 | +% This function iterates through each field of the input structure and checks |
| 7 | +% if the field corresponds to a known NWB type (using a mapping from short |
| 8 | +% names to fully qualified class names). For each recognized field: |
| 9 | +% |
| 10 | +% - It retrieves the full class name and determines its superclasses. |
| 11 | +% - If the class is a subclass of "types.untyped.MetaClass": |
| 12 | +% * If it is also a "types.untyped.GroupClass", the function recursively |
| 13 | +% processes the subgroup configuration. |
| 14 | +% * If it is a "types.untyped.DatasetClass", it wraps the existing |
| 15 | +% configuration in a structure with a "data" property. |
| 16 | +% - If the field is not associated with a recognized NWB type, it remains |
| 17 | +% unchanged. |
| 18 | +% |
| 19 | +% Input: |
| 20 | +% datasetConfiguration - A 1x1 struct containing dataset configuration |
| 21 | +% data. |
| 22 | +% |
| 23 | +% Output: |
| 24 | +% datasetConfiguration - The updated configuration structure with custom |
| 25 | +% property names. |
| 26 | + |
| 27 | + arguments |
| 28 | + datasetConfiguration (1,1) struct |
| 29 | + end |
| 30 | + |
| 31 | + classNameMap = getNwbTypesClassnameMap(); |
| 32 | + |
| 33 | + fields = fieldnames(datasetConfiguration); |
| 34 | + |
| 35 | + for i = 1:numel(fields) |
| 36 | + |
| 37 | + thisField = fields{i}; |
| 38 | + |
| 39 | + % Split of last part if the field name is "nested" |
| 40 | + if contains(thisField, '_') |
| 41 | + shortName = extractAfter(thisField, '_'); |
| 42 | + else |
| 43 | + shortName = thisField; |
| 44 | + end |
| 45 | + |
| 46 | + if ~isKey(classNameMap, shortName) |
| 47 | + continue % Not a neurodata / nwb type |
| 48 | + end |
| 49 | + |
| 50 | + fullClassName = classNameMap(shortName); |
| 51 | + superclassNames = superclasses(fullClassName); |
| 52 | + |
| 53 | + if any(strcmp(superclassNames, "types.untyped.MetaClass")) |
| 54 | + thisSubConfig = datasetConfiguration.(thisField); |
| 55 | + if any(strcmp(superclassNames, "types.untyped.GroupClass")) |
| 56 | + % Todo: Remove this? Nested specs are currently not supported. |
| 57 | + elseif any(strcmp(superclassNames, "types.untyped.DatasetClass")) |
| 58 | + % Rename the field to include the _data suffix |
| 59 | + newFieldName = sprintf('%s_data', thisField); |
| 60 | + datasetConfiguration.(newFieldName) = thisSubConfig; |
| 61 | + datasetConfiguration = rmfield(datasetConfiguration, thisField); |
| 62 | + end |
| 63 | + else |
| 64 | + % For non-NWB types, leave the field unmodified. |
| 65 | + end |
| 66 | + end |
| 67 | +end |
| 68 | + |
| 69 | +function ancestorPath = getAncestorPath(initialPath, numSteps) |
| 70 | +% getAncestorPath - Get an ancestor directory path. |
| 71 | +% |
| 72 | +% ancestorPath = GETANCESTORPATH(initialPath, numSteps) |
| 73 | +% |
| 74 | +% Input: |
| 75 | +% initialPath - A string representing the starting file or directory path. |
| 76 | +% numSteps - A positive integer indicating the number of directory |
| 77 | +% levels to move up. |
| 78 | +% |
| 79 | +% Output: |
| 80 | +% ancestorPath - A string representing the ancestor directory path. |
| 81 | + |
| 82 | + arguments |
| 83 | + initialPath (1,1) string |
| 84 | + numSteps (1,1) double |
| 85 | + end |
| 86 | + splitPath = split(initialPath, filesep); |
| 87 | + |
| 88 | + ancestorPath = fullfile(splitPath{1:end-numSteps}); % char output |
| 89 | + |
| 90 | + % Ensure the path starts with a file separator on Unix systems. |
| 91 | + if isunix && ~startsWith(ancestorPath, filesep) |
| 92 | + ancestorPath = [filesep ancestorPath]; |
| 93 | + end |
| 94 | +end |
| 95 | + |
| 96 | +function map = getNwbTypesClassnameMap() |
| 97 | +% getNwbTypesClassnameMap - Constructs a mapping between NWB type short names |
| 98 | +% and their fully qualified class names. |
| 99 | +% |
| 100 | +% map = GETNWBTYPESCLASSNAMEMAP() |
| 101 | +% |
| 102 | +% The function locates the directory containing NWB type definitions |
| 103 | +% (using the location of 'types.core.NWBFile' as a reference) and searches |
| 104 | +% recursively for all MATLAB class definition files (*.m). It then filters |
| 105 | +% out files in the '+types/+untyped' and '+types/+util' folders. |
| 106 | +% |
| 107 | +% Output: |
| 108 | +% map - A mapping object (either a dictionary or containers.Map) where: |
| 109 | +% * Keys : Short class names (derived from file names without the .m extension). |
| 110 | +% * Values : Fully qualified class names in the format "types.namespace.ClassName". |
| 111 | + |
| 112 | + typesClassDirectory = getAncestorPath( which('types.core.NWBFile'), 2 ); |
| 113 | + |
| 114 | + % Find all MATLAB class files recursively within the directory. |
| 115 | + L = dir(fullfile(typesClassDirectory, '**', '*.m')); |
| 116 | + |
| 117 | + % Exclude files from the '+types/+untyped' and '+types/+util' directories. |
| 118 | + ignore = contains({L.folder}, fullfile('+types', '+untyped')) | ... |
| 119 | + contains({L.folder}, fullfile('+types', '+util')); |
| 120 | + L(ignore) = []; |
| 121 | + |
| 122 | + % Extract namespace and class names from the file paths. |
| 123 | + [~, namespaceNames] = fileparts({L.folder}); |
| 124 | + namespaceNames = string( strrep(namespaceNames, '+', '') ); |
| 125 | + classNames = string( strrep( {L.name}, '.m', '') ); |
| 126 | + |
| 127 | + % Compose fully qualified class names using the namespace and class name. |
| 128 | + fullClassNames = matnwb.common.composeFullClassName(namespaceNames, classNames); |
| 129 | + |
| 130 | + % Create a mapping from the short class names to the fully qualified class names. |
| 131 | + try |
| 132 | + map = dictionary(classNames, fullClassNames); |
| 133 | + catch % Fallback for older versions of MATLAB. |
| 134 | + map = containers.Map(classNames, fullClassNames); |
| 135 | + end |
| 136 | +end |
0 commit comments