PageRenderTime 60ms CodeModel.GetById 16ms RepoModel.GetById 1ms app.codeStats 0ms

/SHCTools/@trywarning/trywarning.m

http://github.com/horchler/SHCTools
MATLAB | 340 lines | 161 code | 27 blank | 152 comment | 33 complexity | 38788f42b1c18149b5d3325b6e8e2150 MD5 | raw file
Possible License(s): BSD-3-Clause
  1. classdef (Sealed) trywarning < handle
  2. %TRYWARNING Create a TRYWARNING object and begin catching warnings.
  3. % OBJ = TRYWARNING() constructs a TRYWARNING object and begins catching
  4. % warnings by reseting the lastwarn function so that it will return an
  5. % empty string. Warning messages are still displayed according to the
  6. % state returned by the WARNING function.
  7. %
  8. % OBJ = TRYWARNING('ALL') disables display of all warnings. The warning
  9. % state is automatically reset by the CATCHWARNING and DELETE methods.
  10. %
  11. % OBJ = TRYWARNING(MSGID) only disables warnings with message identifier
  12. % strings matching MSGID, which may be a string or cell array of strings.
  13. % Matching is case insensitive.
  14. %
  15. % Only one TRYWARNING instance may exist at any given point. Thus, calls
  16. % to the TRYWARNING constructor and its CATCHWARNING method may not be
  17. % nested or interleaved. CATCHWARNING implicitly calls the DELETE method
  18. % that allows another instance to be created. Or the DELETE method can be
  19. % called explicitly.
  20. %
  21. % Methods:
  22. % catchwarning - Check for caught warning and call DELETE method.
  23. % delete - Reset warning state and delete TRYWARNING object.
  24. %
  25. % Examples:
  26. % % Last warning, Example2, will be caught and an error thrown
  27. % obj = trywarning('all');
  28. % warning('trywarning:Example1','Example warning message 1.');
  29. % warning('trywarning:Example2','Example warning message 2.');
  30. % obj.catchwarning;
  31. %
  32. % % Example1 warning will not be matched, no warning caught
  33. % obj = trywarning('all');
  34. % warning('trywarning:Example1','Example warning message 1.');
  35. % warning('trywarning:Example2','Example warning message 2.');
  36. % obj.catchwarning('trywarning:Example1')
  37. %
  38. % % Specific warning disabled and matched with handler function
  39. % str = 'Iteration %d: Caught warning ID %s\n "%s"\n ';
  40. % matchfun = @(msgid)regexprep([str msgid],'(\s\w+:.*2|.*[^2])$','');
  41. % for i = 1:3
  42. % % Create object and disable specific warning
  43. % obj = trywarning('trywarning:example2');
  44. % if i == 1
  45. % warning('trywarning:Example1','Example uncaught warning.');
  46. % elseif i == 2
  47. % warning('trywarning:Example2','Example caught warning.');
  48. % else
  49. % % Example2 not displayed, unable to catch because not last
  50. % warning('trywarning:Example2','Example uncaught warning.');
  51. % warning('trywarning:Example1','Example uncaught warning.');
  52. % end
  53. % % Handler funtion to match Example2 and print details
  54. % fun = @(msg,msgid)fprintf(1,matchfun(msgid),i,msgid,msg);
  55. % obj.catchwarning(fun);
  56. % end
  57. %
  58. % See also TRYWARNING/CATCHWARNING, TRYWARNING/DELETE, LASTWARN, WARNING.
  59. % Andrew D. Horchler, adh9 @ case . edu
  60. % Created: 4-24-12, Revision: 1.1, 6-21-12
  61. properties (SetAccess=private,Hidden)
  62. lastIdentifier
  63. lastMessage
  64. warningHandler
  65. warningState
  66. end
  67. % ==========================================================================
  68. methods
  69. % ----------------------------------------------------------------------
  70. function TryWarningObj=trywarning(varargin)
  71. % Toggle/check mutex to allow only one trywarning instance
  72. if trywarning.instance()
  73. error('SHCTools:trywarning:trywarning:TryWarningExists',...
  74. 'TRYWARNING/TRYCATCH cannot be nested or interleaved.');
  75. end
  76. % Save warning state and disable specified warnings, reset by delete
  77. if nargin == 1
  78. v = varargin{1};
  79. if ischar(v)
  80. if ~strcmpi(v,'all') ...
  81. && isempty(regexp(v,'^(\w+:\w+)+$','once'))
  82. error('SHCTools:trywarning:trywarning:InvalidStringMsgID',...
  83. ['String must be ''all'' or a valid warning '...
  84. 'message identifier string.']);
  85. end
  86. TryWarningObj.warningState = warning('off',v);
  87. elseif iscell(v)
  88. if ~all(cellfun(@ischar,v)) ...
  89. || any(cellfun(@(id)isempty(regexp(id,'^(\w+:\w+)+$',...
  90. 'once')),v))
  91. error('SHCTools:trywarning:trywarning:CellMsgIDNotString',...
  92. ['Elements of the cell array must be valid '...
  93. 'warning message identifier strings.']);
  94. end
  95. for i = 1:numel(v)-1
  96. warning('off',v{i});
  97. end
  98. TryWarningObj.warningState = warning('off',v{end});
  99. else
  100. error('SHCTools:trywarning:trywarning:InvalidMsgID',...
  101. ['Optional warning message IDs must be a string or '...
  102. 'a cell array of strings.']);
  103. end
  104. elseif nargin > 1
  105. error('SHCTools:trywarning:trywarning:TooManyInputs',...
  106. 'Too many input arguments.');
  107. end
  108. % Save lastwarn state and clear, reset by delete
  109. [TryWarningObj.lastMessage TryWarningObj.lastIdentifier] = lastwarn;
  110. lastwarn('');
  111. end
  112. % ----------------------------------------------------------------------
  113. function varargout=catchwarning(TryWarningObj,varargin)
  114. %CATCHWARNING Check for caught warning and reset warning state.
  115. % CATCHWARNING(OBJ) with no output, catches the last warning and
  116. % converts it to an error thrown by the calling function. OBJ is a
  117. % TRYWARNING object. An empty string is returned if no warning
  118. % occured.
  119. %
  120. % MSG = CATCHWARNING(OBJ) returns the last warning message, MSG.
  121. % An empty string is returned if no warning occured.
  122. %
  123. % [MSG MSGID] = CATCHWARNING(OBJ) returns the last warning message
  124. % and its assosciated message identifier string, MSGID. Empty
  125. % strings are returned if no warning occurred.
  126. %
  127. % [...] = CATCHWARNING(OBJ,MSGID) performs a case-insensitive
  128. % comparison between the last warning and MSGID, which may be a
  129. % message identifier string or a cell array of message identifier
  130. % strings. If a match is found, then the output options is as
  131. % above. If no match is found or no warning occured, then no error
  132. % will be thrown and MSG and MSGID will both be empty strings.
  133. %
  134. % [...] = CATCHWARNING(OBJ,FUN) passes the last warning to a
  135. % handler function with function handle FUN. FUN must accept two
  136. % input arguments, MSG and MSGID, the last warning message and its
  137. % assosciated message identifier string, respectively. FUN may
  138. % generate an error, which will be caught and then thrown by the
  139. % calling function.
  140. %
  141. % CATCHWARNING calls the DELETE method upon completion and before
  142. % errors are thrown by a handler function, FUN, or by CATCHWARNING
  143. % itself due to invalid input.
  144. %
  145. % Examples:
  146. % % Last warning, Example2, will be caught and an error thrown
  147. % obj = trywarning('all');
  148. % warning('trywarning:Example1','Example warning message 1.');
  149. % warning('trywarning:Example2','Example warning message 2.');
  150. % obj.catchwarning;
  151. %
  152. % % Example1 warning will not be matched, no warning caught
  153. % obj = trywarning('all');
  154. % warning('trywarning:Example1','Example warning message 1.');
  155. % warning('trywarning:Example2','Example warning message 2.');
  156. % obj.catchwarning('trywarning:Example1')
  157. %
  158. % % Example2 is caught and handled by function
  159. % obj = trywarning('trywarning:Example2');
  160. % warning('trywarning:Example1','Example warning message 1.');
  161. % warning('trywarning:Example2','Example warning message 2.');
  162. % fun = @(msg,msgid)fprintf(1,'ID: %s\nMSG: %s\n',msgid,msg);
  163. % obj.catchwarning(fun);
  164. %
  165. % See also TRYWARNING, TRYWARNING/DELETE, FUNCTION_HANDLE,
  166. % LASTWARN, WARNING.
  167. try
  168. if numel(TryWarningObj) ~= 1 || ~isa(TryWarningObj,...
  169. 'trywarning') || ~isvalid(TryWarningObj)
  170. error('SHCTools:trywarning:catchwarning:InvalidObject',...
  171. 'Argument is not a valid scalar trywarning object.');
  172. end
  173. % Set warning handler and warning identifier to catch
  174. if nargin == 1
  175. warningIdentifier = '';
  176. TryWarningObj.warningHandler = @error;
  177. defaultWarningHandler = true;
  178. elseif nargin == 2
  179. v = varargin{1};
  180. if ischar(v)
  181. if strcmpi(v,'all')
  182. warningIdentifier = '';
  183. elseif ~isempty(regexp(v,'^(\w+:\w+)+$','once'))
  184. warningIdentifier = v;
  185. else
  186. error('SHCTools:trywarning:catchwarning:InvalidStringMsgID',...
  187. ['String must be ''all'' or a valid '...
  188. 'warning message identifier string.']);
  189. end
  190. TryWarningObj.warningHandler = @error;
  191. defaultWarningHandler = true;
  192. elseif iscell(v)
  193. if ~all(cellfun(@ischar,v)) ...
  194. || any(cellfun(@(id)isempty(regexp(id,...
  195. '^(\w+:\w+)+$','once')),v))
  196. error('SHCTools:trywarning:catchwarning:CellMsgIDNotString',...
  197. ['Elements of the cell array must be valid '...
  198. 'warning message identifier strings.']);
  199. end
  200. warningIdentifier = v;
  201. TryWarningObj.warningHandler = @error;
  202. defaultWarningHandler = true;
  203. elseif isa(v,'function_handle')
  204. warningIdentifier = '';
  205. TryWarningObj.warningHandler = v;
  206. defaultWarningHandler = false;
  207. else
  208. error('SHCTools:trywarning:catchwarning:UnkownInput',...
  209. ['Unknown input type. Optional warning message '...
  210. 'IDs must be a string or a cell array of '...
  211. 'strings. Warning handler must be a function '...
  212. 'handle.']);
  213. end
  214. elseif nargin > 2
  215. error('SHCTools:trywarning:catchwarning:TooManyInputs',...
  216. 'Too many input arguments.');
  217. end
  218. catch ERR
  219. % Call destructor
  220. delete(TryWarningObj);
  221. rethrow(ERR);
  222. end
  223. % Check for warning between trywarning() and call to catchwarning()
  224. caughtWarning = false;
  225. if ~isempty(lastwarn)
  226. % Check if caught warning matches specified identifier(s)
  227. [caughtMessage caughtIdentifier] = lastwarn;
  228. if isempty(warningIdentifier) ...
  229. || any(strcmpi(caughtIdentifier,warningIdentifier))
  230. if ~defaultWarningHandler || nargout == 0
  231. try
  232. feval(TryWarningObj.warningHandler,caughtMessage,...
  233. caughtIdentifier);
  234. catch ME
  235. % Call destructor
  236. delete(TryWarningObj);
  237. % Throw error as if from calling function
  238. throwAsCaller(ME);
  239. end
  240. end
  241. caughtWarning = true;
  242. end
  243. end
  244. % Handle variable output if warning handler didn't generate error
  245. if caughtWarning
  246. varargout{1} = caughtMessage;
  247. else
  248. varargout{1} = '';
  249. end
  250. if nargout > 1
  251. if caughtWarning
  252. varargout{2} = caughtIdentifier;
  253. else
  254. varargout{2} = '';
  255. end
  256. end
  257. % Call destructor
  258. delete(TryWarningObj);
  259. end
  260. % ----------------------------------------------------------------------
  261. function delete(TryWarningObj)
  262. %DELETE Reset warning state and delete TRYWARNING object.
  263. % DELETE(OBJ) deletes the TRYWARNING object OBJ allowing another
  264. % TRYWARNING object to be created. The warning display state and
  265. % the message returned by LASTWARN are reset to their values at
  266. % the time OBJ was created.
  267. %
  268. % DELETE is called by CATCHWARNING before exit, and before errors
  269. % thrown by the handler function or by CATCHWARNING itself due to
  270. % invlaid input.
  271. %
  272. % See also TRYWARNING, TRYWARNING/CATCHWARNING, LASTWARN, WARNING.
  273. % Ensure that input is an valid (undeleted) scalar trywarning object
  274. if numel(TryWarningObj) == 1 && isa(TryWarningObj,'trywarning') ...
  275. && length(findprop(TryWarningObj,'warningState')) == 1
  276. % Reset instance mutex
  277. trywarning.instance(true);
  278. % Clear warning handler function handle
  279. if isa(TryWarningObj.warningHandler,'function_handle')
  280. clear TryWarningObj.warningHandler;
  281. end
  282. % Reset warning state
  283. warning(TryWarningObj.warningState);
  284. % Reset lastwarn state
  285. lastwarn(TryWarningObj.lastMessage,...
  286. TryWarningObj.lastIdentifier);
  287. end
  288. end
  289. end
  290. % ==========================================================================
  291. methods (Access=private,Static,Hidden)
  292. % ----------------------------------------------------------------------
  293. function isInstance=instance(reset)
  294. %INSTANCE Mutex to allow only a single TRYWARNING instance.
  295. % INSTANCE returns a logical value (true or false) indicating if
  296. % another TRYWARNING instance exists or not.
  297. %
  298. % INSTANCE(RESET) is called by the DELETE method and toggles the
  299. % Boolean returned by INSTANCE if RESET is TRUE, allowing a new
  300. % TRYWARNING object to be created.
  301. persistent isTryWarningObject
  302. if isempty(isTryWarningObject) || isTryWarningObject == false
  303. isTryWarningObject = true;
  304. isInstance = false;
  305. else
  306. if nargin == 1 && reset == true
  307. isTryWarningObject = false;
  308. end
  309. isInstance = isTryWarningObject;
  310. end
  311. end
  312. end
  313. end