-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathworkspace.m
487 lines (431 loc) · 17.9 KB
/
workspace.m
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
classdef workspace < handle
properties
wstype = 'caller'; % ['caller'] or 'base'
verbose = 1; % interger (0: no verbose
% 1: basic info
% 2: warning when clear unknown variables)
end % properties
properties %(Hidden=true)
% list of local variables that have been assigned through the
% workspace
localasgn
end % properties (Hidden=true)
events
ClearEvent % method clearstrvar is invoked (clear variables)
end
methods
% Constructor to create workspace object
function obj = workspace(varargin)
% CLASS workspace
%
% Purpose: create and manipulate variable names in the target
% workspace by using strings
% Create workspace container syntax:
% ws=worskpace
% ws=workspace(wstype) % with wstype is 'caller' (default)
% % or 'base'
% ws=workspace(..., Property1, Val1, ...)
%
% Modify properties
% ws=workspace(ws, Property1, Val1, ...)
% Properties are 'wstype' or 'verbose'
% Value for 'verbose' is interger
% 0: no verbose
% 1: basic info displayed [default]
% 2: warning when clear unknown variables
%
% Example of usages:
% % Create variables on your workspace from strings
% ws('data1', 'y') = load('data1.txt')
% ws{'data1', 'y'} = load('data1.txt') % comma is neeed
% ws.('data1') = load('data1.txt')
% ws.('data1')(10:end-10)=0 % data1 must exists
% ws{:}(1:10) = rand(1,10) % assign a part of all variables
%
% % Accessing variables on your workspace from strings
% rhs = ws.('data1')(1:30)
% [dtruncated ytruncated] = ws{'data1', 'y'}(1:60)
% % Note: unreferenced (to variables) expressions are allowed
% [d newy] = ws('data1', data1.^2)
% % A string expression must be enclosed in double quote
% d = ws('data1') % returns the *value* of variable data1
% d = ws('"data1"') % returns the *string* 'data1'
% [a b] = ws{:}(1:10) % return truncated subarray
% % of all assigned variables
%
% Methods:
% varnames = getstrvar(ws) % get variable names has been
% % assigned
% clearstrvar(ws) % clear variable names has been assigned
% clearstrvar(ws, var1, ...) % clear specified variables
% clearstrvar(..., wildchar, '-regexp', p1, p2, ...)
% % Clear selected variables that match wilchard (X*)
% % or regular expressions with pattern p1, p2, ...
%
% Restriction: Matlab version 7.7 (R2006b) and ulterior
%
% Author: Bruno Luong <[email protected]>
% Original: 23/Feb/2009 (Bug corrected)
% 24/Feb/2009: can clear specified variables
% + wildcard/regexp to filter clear variables
% 27/Feb/2008: Java containers map
% Backward compatible (test with 2006B)
options = varargin;
% Create containers Maps
if isempty(obj.localasgn)
if containersMapdefined()
% containers defined from 2008B
obj.localasgn = containers.Map('uniformvalues', ...
true);
else
% Java containers
obj.localasgn = java.util.Hashtable;
end
end
% Sparse first input
if nargin>=1
% valid wstype
if (ischar(varargin{1}) && ...
(strcmpi(varargin{1},'caller') || ...
strcmpi(varargin{1},'base')))
obj.wstype = varargin{1};
options(1) = []; % delete from the list
elseif strcmp(class(varargin{1}),'workspace')
% modifyng workspace
% nothing to do beside this
obj = varargin{1};
options(1) = []; % delete from the list
end
end
% Retrieve the list of properties
privatepropnames = fieldnames(obj);
% delete last underscore
publicpropnames = regexprep(privatepropnames,'\_$','');
% propnames = properties('workspace');
% Check validity of input properties
for propin=options(1:2:end)
if isempty(strmatch(lower(propin{1}), publicpropnames))
error('workspace: unknown property ''%s''', propin{1});
end
end
% Assign properties
for k=1:length(publicpropnames)
privatefieldk=privatepropnames{k};
publicfieldk=regexprep(privatefieldk,'\_$','');
obj.(privatefieldk) = getvarginopt(options, publicfieldk, ...
obj.(privatefieldk));
end
% print some info
if obj.verbose
fprintf('workspace ''%s'' (ws) usage:\n', obj.wstype);
fprintf('\tws.(name)(...) = value;\n');
fprintf('\trhs = ws.(name)(...);\n');
fprintf('\thelp workspace %% for more\n');
end
end % constructor workspace
% Assign verbose
function obj = set.verbose(obj, val) %#ok
if isscalar(val)
obj.verbose = val;
else
error('workspace: verbose must be a scalar');
end
end
% Assign wstype
function obj = set.wstype(obj, val)
if ischar(val) && (strcmpi(val,'caller') || strcmpi(val,'base'))
obj.wstype = val;
else
error('workspace: wstype must be ''base'' or ''caller''');
end
end
function varnames = getstrvar(obj, varargin)
% Implementation for workspace ws:
% varnames = getstrvar(ws)
% purpose: Get the names of variables that has been assigned
[listvar pattern] = regexppattern(varargin{:});
if isempty(listvar)
% Get the list of variables
if containersMapdefined()
varnames = obj.localasgn.keys;
else
varnames = alljavakeys(obj.localasgn);
end
else
% Check if they are known by ws
if containersMapdefined()
isVar = obj.localasgn.isKey(listvar);
else
vknown = alljavakeys(obj.localasgn);
isVar = cellfun(@(v) ~isempty(strmatch(v, vknown)), ...
varargin);
end
varnames = varargin(isVar);
% Warning if clear variables in unknown
if any(~isVar) && obj.verbose>1
vlist = sprintf('''%s'' ', varargin{~isVar});
warning('workspace:UnknownVariables', ...
'Unknown variable(s) to workspace: %s\n', vlist);
end
end
% Filtering: Select those who match regular expressions (by OR)
if ~isempty(pattern)
keep = false(size(varnames));
for p=pattern
idx = regexp(varnames,p,'once');
match = ~cellfun(@isempty, idx);
keep = keep | match; % OR between selections
end
varnames = varnames(keep);
end
% nested function regexppattern, separate the list of variables
% and regular expressions from the input argument list
function [listvar pattern] = regexppattern(varargin)
% Look for where the string '-regexp' appears
regpos = ~cellfun(@isempty,strfind(varargin,'-regexp'));
% Find it
if any(regpos)
pos1 = find(regpos,1,'first');
regexpflag = ~regpos;
regexpflag(1:pos1)=false;
listvar = varargin(1:pos1-1);
pattern = varargin(regexpflag);
else
listvar = varargin;
pattern = {};
end
% Look for wildcard '*'
starpos = ~cellfun(@isempty,strfind(listvar,'*'));
wildcardlist = listvar(starpos);
% Add '^' at the begining
wildcardlist = cellfun(@(p) ['^' p], wildcardlist, ...
'UniformOutput', false);
% move the string with wildcard to pattern list
[listvar pattern] = deal(listvar(~starpos), ...
[pattern wildcardlist]);
end % regexppattern
end % getstrvar
function obj = clearstrvar(obj, varargin)
% Implementation for workspace ws:
% ws=clearstrvar(ws);
% purpose: Clear variables that has been assigned
varnames=getstrvar(obj, varargin{:});
if ~isempty(varnames)
% add a two quotes and comma
vlist = sprintf('''%s'', ', varnames{:});
% remove trailing space-comma
vlist = vlist(1:end-2);
% clear-command string
clearcmd = ['clear(' vlist ')'];
evalin(obj.wstype, clearcmd);
% Clear variables from the internal list
if containersMapdefined()
obj.localasgn.remove(varnames);
else
for k=1:length(varnames)
obj.localasgn.remove(varnames{k});
end
end
if obj.verbose
fprintf('\tPerform: %s\n', clearcmd);
end
% Broadcast notice of ClearEvent
notify(obj,'ClearEvent');
end
end % clearstrvar
function obj = subsasgn(obj, s, value)
% Implementation for workspace ws:
% ws('data1', 'y') = load('data1.txt')
% ws{'data1', 'y'} = load('data1.txt') % comma is neeed
% ws.('data1') = load('data1.txt')
% ws.('data1')(10:end-10)=0 % data1 must exists
% ws{:}(1:10) = rand(1,10) % assign a part of all variables
if isstruct(s) && isfield(s,'type')
switch s(1).type
case {'()' '{}'},
subs = s(1).subs;
case ('.')
subs = {s(1).subs};
end
subs = subsprocess(obj, subs);
% Loop over variables in parenthesis
for k=1:length(subs)
vname = subs{k};
if ischar(vname)
% assign workspace own properties
if isWorkspaceProperty(obj, vname)
ss = [substruct('.',vname) s(2:end)];
obj = builtin('subsasgn', obj, ss, value);
return
end
if length(s)>1 % assign subsref of variables
tmp = evalin(obj.wstype, vname);
val = builtin('subsasgn', tmp, s(2:end), value);
else
val = value;
end
assignin(obj.wstype, vname, val);
% Keep track of names of assigned variables locally
if containersMapdefined()
obj.localasgn(vname) = vname;
else
obj.localasgn.put(vname,vname);
end
if obj.verbose
fprintf('\tValue assigned to %s\n', vname);
end
end
end % for-loop
end
end %subsasgn
function varargout = subsref(obj, s)
% Implementation for workspace ws:
% % Accessing variables on your workspace from strings
% rhs = ws.('data1')(1:60)
% [dtruncated ytruncated] = ws{'data1', 'y'}(1:60)
% % Note: unreferenced (to variables) expressions are allowed
% [d newy] = ws('data1', data1.^2)
% % A string expression must be enclosed in double quote
% d = ws('data1') % returns the *value* of variable data1
% d = ws('"data1"') % returns the *string* 'data1'
% [a b] = ws{:}(1:10) % return truncated subarray
% % of all assigned variables
vout = cell(nargout);
if isstruct(s) && isfield(s,'type')
switch s(1).type
case {'()' '{}'},
subs = s(1).subs;
case ('.')
subs = {s(1).subs};
end
subs = subsprocess(obj, subs);
% Loop over the list of variables (only parentheis or
% curly-braket syntax allow a list)
for k=1:length(subs)
vname = subs{k};
if ischar(vname)
% retreive workspace own properties
if isWorkspaceProperty(obj, vname)
ss = [substruct('.',vname) s(2:end)];
val = builtin('subsref', obj, ss);
elseif isWorkspaceMethod(obj, vname)
mfun = str2func(vname);
if length(s)==1
argfun = {};
elseif length(s)==2 && strcmp(s(2).type,'()')
argfun = s(2).subs;
else
error('workspace: invalid syntax');
end
varargout{k} = mfun(obj, argfun{:});
return
elseif vname(1)=='"' && vname(end)=='"'
% string, must be passed as '"AString"' (double
% quote) by convention
val = vname(2:end-1);
else
val = evalin(obj.wstype,vname);
end
else
val = vname;
end
if length(s)==1
vout{k} = val;
else % retreive subsref of variable
vout{k} = builtin('subsref', val, s(2:end));
end
end % for-loop
end
varargout = vout;
end % subsref
end % methods
methods %(Access=protected)
% Check if name is workspace property
function yesno = isWorkspaceProperty(obj, name)
if ischar(name) && ~isempty(name)
% Get the list of properties
privatepropnames = fieldnames(obj);
yesno = ~isempty(strmatch(name, privatepropnames, 'exact'));
else
yesno = false;
end
end
function yesno = isWorkspaceMethod(obj, name)
if ischar(name) && ~isempty(name)
% Get the list of properties
methodnames = methods(obj);
yesno = ~isempty(strmatch(name, methodnames, 'exact'));
else
yesno = false;
end
end
end
end % workspace classdef
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% private nested function
function value = getvarginopt(argin, keyword, default)
% function value = getvarginopt(argin, keyword, default)
%
% Try to parse the argin cell list of the form:
% { option1, value1, ... }
% to match keyword
% If keyword is not found, then return DEFAULT as value
% History: Original: 13/Jan/2009, Bruno Luong <[email protected]>
if nargin<3
default = [];
end
if ~iscell(keyword)
keyword = {keyword};
end
% remove space and trim
optnames = strtrim(upper(argin(1:2:end)));
keyword = strtrim(upper(keyword));
values = argin(2:2:end);
value = default;
for k=1:length(keyword)
kw = keyword{k};
where = strmatch(kw,optnames);
if ~isempty(where)
value = values{where};
return
end
end
end % getvarginopt(argin, keyword, default)
% Process subs index.
function subs = subsprocess(obj, subs)
% if ':', return all the variable names
if length(subs)==1 && ischar(subs{1}) && strcmp(subs{1},':')
subs = getstrvar(obj);
end
end
% Check if built-in containers.Map exists
function yesno = containersMapdefined
persistent flag
if isempty(flag)
s=which('containers.Map');
flag=ischar(s) && ~isempty(findstr('built-in',s));
end
% already check, return the persistent result
yesno=flag;
end
function list=splitstr(s)
s = [s ','];
comma=[0 find(s==',')];
l=comma(2:end)-comma(1:end-1);
c=mat2cell(s,1,l);
list=cellfun(@(s) strtrim(s(1:end-1)), c, 'UniformOutput', 0);
end
% Return the cell list of key in Java containers Maps;
function varnames = alljavakeys(javaMaps)
javakeys=char(javaMaps.keySet);
javakeys=javakeys(2:end-1); % remove '[' and ']'
if isempty(javakeys)
varnames = {};
else
% split them
varnames=splitstr(javakeys);
%varnames=strtrim(regexp(javakeys,',','split'));
end
end
% End of workspace.m
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%