diff m-toolbox/classes/+utils/@helper/callerIsMethod.m @ 0:f0afece42f48

Import.
author Daniele Nicolodi <nicolodi@science.unitn.it>
date Wed, 23 Nov 2011 19:22:13 +0100
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/m-toolbox/classes/+utils/@helper/callerIsMethod.m	Wed Nov 23 19:22:13 2011 +0100
@@ -0,0 +1,157 @@
+% CALLERISMETHOD(varargin) checks if a method was called by another LTPDA method.
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+%
+% DESCRIPTION: CALLERISMETHOD(varargin) checks if the method it is inserted in,
+% was called by another LTPDA method
+%
+% CALL:                         callerIsMethod = utils.helper.callerIsMethod()
+%                  [callerIsMethod, className] = utils.helper.callerIsMethod()
+%      [callerIsMethod, className, methodName] = utils.helper.callerIsMethod()
+%
+% The name of the caller function is retrieved from a call to dbstack
+%
+% The name of the higher level caller function, if any is tested against the structure
+% /../../classes/@class_name/method_name.m
+%
+% If the higher level caller is found to be a method of LTPDA classes, out is TRUE
+% If the caller is found not to be a method of LTPDA classes, out is FALSE
+%
+% Optional outputs:
+%     className     the name of the class the caller methods is associated
+%     methodName    the name of the caller method is associated
+%
+% HISTORY: 09-02-11 M Hueller
+%            Creation
+%
+% VERSION: $Id: callerIsMethod.m,v 1.16 2011/04/09 06:58:47 hewitson Exp $
+%
+%
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+function varargout = callerIsMethod(varargin)
+
+  % This is just some thinking about make a scheme that can override the
+  % behaviour of callerIsMethod. The idea is to create a variable called
+  % 'callerIsMethod' in the calling function and pass it in here. We would
+  % have to pass varargin and inputnames down the chain always. It almost
+  % works but will be too much work for the moment.  
+  %   if nargin == 2
+  %
+  %     inputs = varargin{1};
+  %     names = varargin{2};
+  %
+  %     idx = strcmpi('callerIsMethod', names);
+  %     if any(idx)
+  %       varargout{1} = inputs{idx};
+  %       return
+  %     end
+  %   end
+  
+  persistent exceptions;
+  
+  if isempty(exceptions)
+    exceptions = {'compute', 'rebuild', 'collect_values', 'generic_getInfo', 'executeCommands'};
+  end
+  
+  stack = dbstack('-completenames');
+  index = 2;
+  
+  if size (stack, 1) < index
+    error('### This utility can only be used inside other functions!');
+  end
+  
+  if size (stack, 1) == index
+    
+    % This is the highest level function call.
+    % The caller is not a method
+    callerIsMethod  = false;
+    className       = [];
+    methodName      = [];
+    
+  else
+    % This is not the highest level function call.
+    
+    % Serching for class methods assuming the folder/files structure is:
+    % /../../classes/@class_name/method_name.m
+        
+    % In the case that we are inside a nested function, we need to climb up
+    % until we get out of the calling file.
+    firstFile = stack(index).file;
+    firstName = stack(index).name;
+    
+    while index < length(stack) && strcmp(firstFile, stack(index).file) && ~strcmp(firstName, stack(index+1).name)
+      index = index+1;
+    end
+    
+    % capture method name
+    methodName = stack(index).name;
+      
+    if index == length(stack) && length(stack)>3
+      callerIsMethod = false;
+      className = '';
+    else
+      % filesep is quite slow, so we cache the value and use it three times.
+      % The \ character is also a command in regexp, so we need to go for a trick
+      if strncmp(computer, 'PC', 2)
+        fs = '\\';
+      else
+        fs = '/';
+      end
+      
+      % capture class name
+      tokenStr  = regexp(stack(index).file, ['.*' fs '@(\w+)' fs '\w+.m$'], 'tokens');
+
+      % *********
+      % At the moment this bit of code is a bad thing because models which
+      % create objects in their default plists (AOs for example) can't be
+      % rebuilt because the objects have no history. An example of this is
+      % smodel_model_psd_feeps.
+      % *********
+      
+%       % If we are being called deep inside a built-in model constructor,
+%       % then the stack will contain fromModel and we are called from a
+%       % method.
+%       if utils.helper.ismember('fromModel', {stack(:).name})
+%         callerIsMethod = true;
+%         className = 'ltpda_uo';
+%         methodName = 'fromModel';
+%       
+%       % If the method is a unit test (test_*) then we add history
+%       else
+
+
+      if strncmp(methodName, 'test_', 5)
+        callerIsMethod = false;
+        if ~isempty(tokenStr)
+          className = tokenStr{1}{1};
+        end
+        
+      % if we get a match and if the caller is not in the exception list
+      % then we were called by a method.
+      elseif ~isempty(tokenStr) && ~any(strcmp(stack(index).name, exceptions))
+        callerIsMethod = true;
+        className = tokenStr{1}{1};
+      else
+        callerIsMethod = false;
+        className = '';
+      end
+    end
+    
+  end
+  
+  % Assigning outputs
+  switch nargout
+    case 0
+    case 1
+      varargout{1} = callerIsMethod;
+    case 2
+      varargout{1} = callerIsMethod;
+      varargout{2} = className;
+    case 3
+      varargout{1} = callerIsMethod;
+      varargout{2} = className;
+      varargout{3} = methodName;
+    otherwise
+      error('### Incorrect number of outputs');
+  end
+end