Running MATLAB code snippet without polluting the namespace

I am writing a Python version of doctest test-runner, for MATLAB (it partially works ...). For this to work, I need to run the code in people's examples in their help on the m file. I want variables to wrap from one line to another, for example.

 % >> I = 5 + 33; % expect no output % >> I % % I = % % 38 % 

To run the tests, I have a loop compared to REGEX, which is looking for tests. For each match, I evalc an evalc example and make sure the result matches:

 for I = 1:length(examples) try got = evalc(examples(I).source); catch exc got = ['??? ' exc.message]; end % process the result... end 

The problem is that the sample definition of I now knocked out the loop variable in my loop , as assignments are transferred from eval to the outer scope. I looked around for something that could create a new area / workspace, but evalin could only reuse the caller's workspace, which is even worse. I also looked at options for calling a subfunction or save / load , but didn't get it anywhere, but maybe I just didn't think hard enough.

So, I think, I just need to name all my variables doctest__system__* and live with namespace problems ... unless you have another idea for a strategy to avoid variable name conflicts ?

+4
source share
1 answer

Very interesting project. I think the best option you have is to write a separate function to run the tests and use a unique prefix for the whole variable inside this function to avoid name conflict. Here is my attempt:

 function [PREFIX_b varargout] = testContext(PREFIX_src, PREFIX_srcOutput) %# TESTCONTEXT Executes the source code and tests for %# equality against the expected output %# %# Input: %# PREFIX_src - source to execute, cellarry of statements %# PREFIX_srcOutput - output to expect, cellarray of output of each statement %# %# Output: %# PREFIX_b - true/false for success/failure of test %# note that the output is strtrim()'ed then strcmp()'ed %# varargout{1} - variable names assigned in this confined context %# varargout{2} - variable values assigned %# %# Example 1: %# source = { 'I = 5+33;' 'I' }; %# output = { [], ['I =' char(10) ' 38'] }; %# b = testContext(source, output); %# %# Example 2: %# source = { 'I = 5+33; J = 2;' 'K = 1;' 'disp(I+J+K)' }; %# output = { [], [], '41' }; %# [b varNames varValues] = testContext(source, output); %# %# See also: eval evalc %# PREFIX_b = true; try %# for each statement for PREFIX_i=1:numel(PREFIX_src) %# evaluate PREFIX_output = evalc( PREFIX_src{PREFIX_i} ); PREFIX_output = strtrim(PREFIX_output); %# trim whitespaces %# compare output if ~isempty( PREFIX_srcOutput{PREFIX_i} ) if ~strcmp(PREFIX_output,PREFIX_srcOutput{PREFIX_i}) PREFIX_b = false; return end end end if nargout > 1 %# list created variables in this context %#clear ans PREFIX_vars = whos('-regexp', '^(?!PREFIX_).*'); %# java regex negative lookahead varargout{1} = { PREFIX_vars.name }; if nargout > 2 %# return those variables varargout{2} = cell(1,numel(PREFIX_vars)); for PREFIX_i=1:numel(PREFIX_vars) [~,varargout{2}{PREFIX_i}] = evalc( PREFIX_vars(PREFIX_i).name ); end end end catch ME warning(ME.identifier, ME.message) PREFIX_b = false; varargout{1} = {}; varargout{2} = {}; end end 

I assume that you can parse the m file to restore examples for testing, where you have each statement along with its expected output.

As an example, consider this simple test built into the function header:

 I = 5 + 33; J = 2*I; disp(I+J) 

Since only the last statement has an output, we test it as:

 source = {'I = 5 + 33;' 'J = 2*I;' 'disp(I+J)'}; output = {[], [], '114'}; [b varNames varValues] = testContext(source, output) 

results:

 b = 1 varNames = 'I' 'J' varValues = [38] [76] 

Indicates whether the test that failed has passed. Optionally, the function returns a list of variables created in this context, along with its values.

+4
source

Source: https://habr.com/ru/post/1316196/


All Articles