Skip to content

Commit 43cdffb

Browse files
authored
Merge pull request #506 from NeurodataWithoutBorders/238-allow-unit-vectordata
Allows Vectordata objects to support optional Units-column properties `unit`, `resolution`, and `sampling_rate`
2 parents 442c604 + 235c16f commit 43cdffb

File tree

13 files changed

+696
-536
lines changed

13 files changed

+696
-536
lines changed

+file/fillClass.m

Lines changed: 123 additions & 101 deletions
Original file line numberDiff line numberDiff line change
@@ -1,119 +1,141 @@
11
function template = fillClass(name, namespace, processed, classprops, inherited)
2-
%name is the name of the scheme
3-
%namespace is the namespace context for this class
2+
%name is the name of the scheme
3+
%namespace is the namespace context for this class
44

5-
%% PROCESSING
6-
class = processed(1);
5+
%% PROCESSING
6+
class = processed(1);
77

8-
allprops = keys(classprops);
9-
required = {};
10-
optional = {};
11-
readonly = {};
12-
defaults = {};
13-
dependent = {};
14-
%separate into readonly, required, and optional properties
15-
for i=1:length(allprops)
16-
pnm = allprops{i};
17-
prop = classprops(pnm);
8+
allProperties = keys(classprops);
9+
required = {};
10+
optional = {};
11+
readonly = {};
12+
defaults = {};
13+
dependent = {};
14+
hidden = {}; % special hidden properties for hard-coded workarounds
15+
%separate into readonly, required, and optional properties
16+
for iGroup = 1:length(allProperties)
17+
propertyName = allProperties{iGroup};
18+
prop = classprops(propertyName);
1819

19-
isRequired = ischar(prop) || isa(prop, 'containers.Map') || isstruct(prop);
20-
iIsPropertyRequired = false;
21-
if isa(prop, 'file.interface.HasProps')
22-
iIsPropertyRequired = false(size(prop));
23-
for iProp = 1:length(prop)
24-
p = prop(iProp);
25-
iIsPropertyRequired(iProp) = p.required;
26-
end
27-
end
28-
29-
if isRequired || all(iIsPropertyRequired)
30-
required = [required {pnm}];
31-
else
32-
optional = [optional {pnm}];
33-
end
34-
35-
if isa(prop, 'file.Attribute')
36-
if prop.readonly
37-
readonly = [readonly {pnm}];
20+
isRequired = ischar(prop) || isa(prop, 'containers.Map') || isstruct(prop);
21+
isPropertyRequired = false;
22+
if isa(prop, 'file.interface.HasProps')
23+
isPropertyRequired = false(size(prop));
24+
for iProp = 1:length(prop)
25+
p = prop(iProp);
26+
isPropertyRequired(iProp) = p.required;
27+
end
3828
end
39-
40-
if ~isempty(prop.value)
41-
defaults = [defaults {pnm}];
29+
30+
if isRequired || all(isPropertyRequired)
31+
required = [required {propertyName}];
32+
else
33+
optional = [optional {propertyName}];
4234
end
43-
44-
if ~isempty(prop.dependent)
45-
%extract prefix
46-
parentName = strrep(pnm, ['_' prop.name], '');
47-
parent = classprops(parentName);
48-
if ~parent.required
49-
dependent = [dependent {pnm}];
35+
36+
if isa(prop, 'file.Attribute')
37+
if prop.readonly
38+
readonly = [readonly {propertyName}];
39+
end
40+
41+
if ~isempty(prop.value)
42+
defaults = [defaults {propertyName}];
43+
end
44+
45+
if ~isempty(prop.dependent)
46+
%extract prefix
47+
parentName = strrep(propertyName, ['_' prop.name], '');
48+
parent = classprops(parentName);
49+
if ~parent.required
50+
dependent = [dependent {propertyName}];
51+
end
52+
end
53+
54+
if strcmp(namespace.name, 'hdmf_common') ...
55+
&& strcmp(name, 'VectorData') ...
56+
&& any(strcmp(prop.name, {'unit', 'sampling_rate', 'resolution'}))
57+
hidden{end+1} = propertyName;
5058
end
5159
end
5260
end
53-
end
54-
nonInherited = setdiff(allprops, inherited);
55-
readonly = intersect(readonly, nonInherited);
56-
required = intersect(required, nonInherited);
57-
optional = intersect(optional, nonInherited);
61+
nonInherited = setdiff(allProperties, inherited);
62+
readonly = intersect(readonly, nonInherited);
63+
exclusivePropertyGroups = union(readonly, hidden);
64+
required = setdiff(intersect(required, nonInherited), exclusivePropertyGroups);
65+
optional = setdiff(intersect(optional, nonInherited), exclusivePropertyGroups);
5866

59-
%% CLASSDEF
60-
if length(processed) <= 1
61-
depnm = 'types.untyped.MetaClass'; %WRITE
62-
else
63-
parentName = processed(2).type; %WRITE
64-
depnm = namespace.getFullClassName(parentName);
65-
end
67+
%% CLASSDEF
68+
if length(processed) <= 1
69+
depnm = 'types.untyped.MetaClass'; %WRITE
70+
else
71+
parentName = processed(2).type; %WRITE
72+
depnm = namespace.getFullClassName(parentName);
73+
end
6674

67-
if isa(processed, 'file.Group')
68-
classTag = 'types.untyped.GroupClass';
69-
else
70-
classTag = 'types.untyped.DatasetClass';
71-
end
75+
if isa(processed, 'file.Group')
76+
classTag = 'types.untyped.GroupClass';
77+
else
78+
classTag = 'types.untyped.DatasetClass';
79+
end
7280

73-
%% return classfile string
74-
classDef = [...
75-
'classdef ' name ' < ' depnm ' & ' classTag newline... %header, dependencies
76-
'% ' upper(name) ' ' class.doc]; %name, docstr
77-
propgroups = {...
78-
@()file.fillProps(classprops, readonly, 'PropertyAttributes', 'SetAccess=protected')...
79-
@()file.fillProps(classprops, setdiff(required, readonly), 'IsRequired', true)...
80-
@()file.fillProps(classprops, setdiff(optional, readonly))...
81-
};
82-
docsep = {...
83-
'% READONLY PROPERTIES'...
84-
'% REQUIRED PROPERTIES'...
85-
'% OPTIONAL PROPERTIES'...
86-
};
87-
propsDef = '';
88-
for i=1:length(propgroups)
89-
pg = propgroups{i};
90-
pdef = pg();
91-
if ~isempty(pdef)
92-
propsDef = strjoin({propsDef docsep{i} pdef}, newline);
81+
%% return classfile string
82+
classDefinitionHeader = [...
83+
'classdef ' name ' < ' depnm ' & ' classTag newline... %header, dependencies
84+
'% ' upper(name) ' ' class.doc]; %name, docstr
85+
hiddenAndReadonly = intersect(hidden, readonly);
86+
hidden = setdiff(hidden, hiddenAndReadonly);
87+
readonly = setdiff(readonly, hiddenAndReadonly);
88+
PropertyGroups = struct(...
89+
'Function', {...
90+
@()file.fillProps(classprops, hiddenAndReadonly, 'PropertyAttributes', 'Hidden, SetAccess = protected') ...
91+
, @()file.fillProps(classprops, hidden, 'PropertyAttributes', 'Hidden') ...
92+
, @()file.fillProps(classprops, readonly, 'PropertyAttributes', 'SetAccess = protected') ...
93+
, @()file.fillProps(classprops, required, 'IsRequired', true) ...
94+
, @()file.fillProps(classprops, optional)...
95+
} ...
96+
, 'Separator', { ...
97+
'% HIDDEN READONLY PROPERTIES' ...
98+
, '% HIDDEN PROPERTIES' ...
99+
, '% READONLY PROPERTIES' ...
100+
, '% REQUIRED PROPERTIES' ...
101+
, '% OPTIONAL PROPERTIES' ...
102+
} ...
103+
);
104+
fullPropertyDefinition = '';
105+
for iGroup = 1:length(PropertyGroups)
106+
Group = PropertyGroups(iGroup);
107+
propertyDefinitionBody = Group.Function();
108+
if isempty(propertyDefinitionBody)
109+
continue;
110+
end
111+
fullPropertyDefinition = strjoin({...
112+
fullPropertyDefinition ...
113+
, Group.Separator ...
114+
, propertyDefinitionBody ...
115+
}, newline);
93116
end
94-
end
95117

96-
constructorBody = file.fillConstructor(...
97-
name,...
98-
depnm,...
99-
defaults,... %all defaults, regardless of inheritance
100-
classprops,...
101-
namespace);
102-
setterFcns = file.fillSetters(setdiff(nonInherited, readonly));
103-
validatorFcns = file.fillValidators(allprops, classprops, namespace);
104-
exporterFcns = file.fillExport(nonInherited, class, depnm);
105-
methodBody = strjoin({constructorBody...
106-
'%% SETTERS' setterFcns...
107-
'%% VALIDATORS' validatorFcns...
108-
'%% EXPORT' exporterFcns}, newline);
118+
constructorBody = file.fillConstructor(...
119+
name,...
120+
depnm,...
121+
defaults,... %all defaults, regardless of inheritance
122+
classprops,...
123+
namespace);
124+
setterFcns = file.fillSetters(setdiff(nonInherited, union(readonly, hiddenAndReadonly)));
125+
validatorFcns = file.fillValidators(allProperties, classprops, namespace);
126+
exporterFcns = file.fillExport(nonInherited, class, depnm);
127+
methodBody = strjoin({constructorBody...
128+
'%% SETTERS' setterFcns...
129+
'%% VALIDATORS' validatorFcns...
130+
'%% EXPORT' exporterFcns}, newline);
109131

110-
if strcmp(name, 'DynamicTable')
111-
methodBody = strjoin({methodBody, '%% TABLE METHODS', file.fillDynamicTableMethods()}, newline);
112-
end
132+
if strcmp(name, 'DynamicTable')
133+
methodBody = strjoin({methodBody, '%% TABLE METHODS', file.fillDynamicTableMethods()}, newline);
134+
end
113135

114-
fullMethodBody = strjoin({'methods' ...
115-
file.addSpaces(methodBody, 4) 'end'}, newline);
116-
template = strjoin({classDef propsDef fullMethodBody 'end'}, ...
117-
[newline newline]);
136+
fullMethodBody = strjoin({'methods' ...
137+
file.addSpaces(methodBody, 4) 'end'}, newline);
138+
template = strjoin({classDefinitionHeader fullPropertyDefinition fullMethodBody 'end'}, ...
139+
[newline newline]);
118140
end
119141

0 commit comments

Comments
 (0)