So I have the following (simplified) project structure.
scripts/
client.m
src/
+estimators/
#estimator1/
3party/
shell_script.sh
estimator1.m
Basically, what I try to do is, calling estimator1.m from client.m. This is working very well, no issues. However, from within estimator1.m I try to call shell_script.sh. The problem, relative paths do not work since it is always looking from the path client.m is called.
What I tried from estimator1.m is:
pathToScript = fullfile('3Party','shell_script');
system(pathToScript);
I would really like to avoid absolute paths since I'd like this package to be used by others as well. So hardcoding paths to my home directory is not good.
Use mfilename('fullpath') to get the full path of the currently executing file. Use fileparts to get just the directory part. Putting it together,
scriptdir = fullfile (fileparts(mfilename('fullpath')), '3Party');
Here is an additional answer to the one by #Edric. My second issue was that I wanted to implement the feature in the parent class since it is a functionality used by all child classes. The proposed answer is perfect when you have the function implemented in the class itself. However:
scriptdir = fullfile (fileparts(mfilename('fullpath')));
would always return the location of my parent class. So I implemented following in the parent class to retrieve the correct location in child classes:
function classdir= getClassDir(obj)
[classdir, ~, ~] = fileparts(which(class(obj)));
end
Related
I would like to use two versions of the same Matlab software package at the same time (I would like to compare their outputs for testing). The package modifies the path so that functions in subdirectories can be found. This seems problematic since the package assumes that it is the only copy running on the machine. The path is essentially a global variable which is unintentionally shared between the two copies of the code.
Example simplified code structure:
/main_code.m
/compare_results.m
/code_a/somefn.m
/code_a/submethods/
/code_b/somefn.m
/code_b/submethods/
Note that somefn.m adds the submethods directory to the path, and calls code from the submethods folder by relying on the path.
Example of code that I would like to run:
for i = 1:1000000
% Run version A:
result_a = code_a.somefn(i);
% Run version B:
result_b = code_b.somefn(i);
% Compare the output from the two versions:
compare_results(a,b);
end
One solution that I can think of is to manually update the Matlab path every time that I want to switch to a different version of the package. This seems like unnecessary coding overhead, and potentially a performance problem (due to switching the path so often).
Another solution might be to rewrite the code to be object oriented, so that the functions are attached to objects, and I can create objects of different versions. The problem with this is that in reality the code package contains hundreds of files, and I was not the original author so rewriting would be a huge task .
(Yet another option would be to change directory all the time, so that the code to run is always in the current directory. This would be so much of a headache due to the number of subfolders that I do not think this is a serious solution. It also has potential performance overhead drawbacks similar to always changing the path.)
Is there a cleaner way to handle this? Can I somehow specify the folder of the code that I want to run? What is the best way to design such a code package so that this problem does not come up?
Just create packages, which can contain functions with the same names: Packages Create Namespaces
Basically create two folders named, say, +package1 and +package2. The "+" in the folder name is important. Then place your functions under both of them, say, foo.m. Then, you can call each separately without messing with MATLAB path as:
>> package1.foo
>> package2.foo
You can use private functions. Change the directory structure as:
/main_code.m
/compare_results.m
/+code_a/somefn.m
/+code_a/private/
/+code_b/somefn.m
/+code_b/private/
Each somefn has access to the functions contained in its private sub-folder. So there is no need to create global variable and to add private sub-folders to the path.
As a follow up to my previous question, I run into a new obstacle: how to generate stubs for functions in a toolbox?
I found Andy Campbell's solution for the non toolbox case. This does not work in my case because Matlab complains: package directories are not allowed in MATLAB path in Pathfixtures!
I also don't see how this concept will overwrite the import statements within the toolbox, e.g. in file2.
This is my setup:
+folder1/file1.m
+folder1/runtestsuite.m
+folder1/unittest_data/file1_testdata.mat
+folder1/+folder2/file2.m
+folder1/+folder2/unittest_data/overloads/file1.m
...
Let's say I want to stub file1 in file2. And file2 has as a first statement: import folder1.file1.
With
methods(Access=private)
function inject_file1_stub(testCase, answer)
import matlab.unittest.fixtures.PathFixture;
testCase.applyFixture(PathFixture(fullfile(testCase.path,'overloads')));
file1('', answer);
end
end
So currently I believe this concept is not applicable in my case, so how is this done correctly with matlab?
I know one can shadow an implementation of a function in a toolbox, if one adds another path with the same toolboxname and function to the path. For this I would have to recreate a subset of the current folder setup:
So my current idea for a fixture is
create temporary folder with tempdir
use mfilename to check what subset of the toolbox directories I have to recreate
generate folder structure
copy from the overload folder to the new toolbox system
Add this to path
Run tests
In teardown
remove the temporary folder
remove the entry from path
I have not implemented this yet, and seems a bit redundant knowing that there is a Pathfixture in matlab already.
Pointers to other toolboxes which show how they have solved these kind of problems are also welcome.
It is true that you can't add subfolders of packages to the path, but that doesn't mean you can't shadow these path functions. To do this you need to separate the test related content out of your source location. For example, if your source looks like:
<source-home>/+folder1/file1.m
<source-home>/+folder1/+folder2/file2.m
Then you can put your tests somewhere else so your structure would look something like:
<test-home>/file1Test.m
<test-home>/file2Test.m % could also put tests into packages if you want
<test-home>/overloads/+folder1/file1.m
<test-home>/overloads/+folder1/+folder2/file2.m
Then inside of file1Test and/or file2Test you would use a PathFixture to add:
<test-home>/overloads/
to the path.
Also, another thing to consider is defining an interface in your source code for these dependencies and leveraging dependency injection (with or without a DI framework) in order to get test specific behavior into your tests.
I'm having a lot of issues with Quandl in Matlab lately.
I tried adding +urlread2 to the Matlab search path but I got the message "you cannot add method folders or private folders to the matlab search path." I don't know why I'm getting this message since I'm supposed to add +urlread2 to the path to use Quandl.
Thoughts?
For class directories you shall only add the parent folder containing them to the path: MATLAB will then recognize the classes below automatically. This is what the message you get "means".
See for example how the genpath function is implemented.
I am working with the financial tooldbox that has a type called FINTS. If I copy some code out of its toolbox directory to customize it, when I try do do something like fts.data, `I get
The specified field, 'data', does not exist in the object.
But the same thing works fine in the MATLAB library directory. They are both in my path, so what else do I need to change?
I think, but I haven't checked the documentation on this one, that it is a peculiarity of MATLAB that the class FINTS must be defined in the directory #fints. So if you want to extend the class, you have to put your code into that directory. And if you want to work on a class MYFINTS, you need to put the code into directory #myfints.
OK, I figured it out. MATLAB defines class methods in what it calls method directories which are named after the class. So in this case, the class is fints, so all its methods are in #fints. All I had to do was make a new directory in my own workspace called #fints, and it will become another class method of fints. You can see all the methods a class has by calling what className.
Make sure the path is specified from the root directory, and not relative.
For instance
addpath 'c:\...\...\MATLAB\mytoolbox
not
addpath 'mytoolbox'
the latter will break if you change your working directory
We have a lot of MATLAB code in my lab. The problem is there's really no way to organize it. Since all the functions have to be in the same folder to be called (or you have to add a bunch of folders to MATLAB's path environment variable), it seems that we're doomed have loads of files in the same folder, all in the global namespace. Is there a better way to organize our files and functions? I really wish there were some sort of module system...
MATLAB has a notion of packages which can be nested and include both classes and functions.
Just make a directory somewhere on your path with a + as the first character, like +mypkg. Then, if there is a class or function in that directory, it may be referred to as mypkg.mything. You can also import from a package using import mypkg.mysubpkg.*.
The one main gotcha about moving a bunch of functions into a package is that functions and classes do not automatically import the package they live in. This means that if you have a bunch of functions in different m-files that call each other, you may have to spend a while dropping imports in or qualifying function calls. Don't forget to put imports into subfunctions that call out as well. More info:
http://www.mathworks.com/help/matlab/matlab_oop/scoping-classes-with-packages.html
I don't see the problem with having to add some folder to Matlab's search path. I have modified startup.m so that it recursively looks for directories in my Matlab startup directory, and adds them to the path (it also runs svn update on everything). This way, if I change the directory structure, Matlab is still going to see all the functions the next time I start it.
Otherwise, you can look into object-oriented code, where you store all the methods in a #objectName folder. However, this may lead to a lot of re-writing code that can be avoided by updating the path (there is even a button add with subfolders if you add the folder to the path from the File menu) and doing a bit of moving code.
EDIT
If you would like to organize your code so that some functions are only visible to the functions that call them directly (and if you don't want to re-write in OOP), you put the calling functions in a directory, and within this directory, you create a subdirectory called private. The functions in there will only be visible to the functions in the parent directory. This is very useful if you have to overload some built-in Matlab functions for a subset of your code.
Another way to organize & reuse code is using matlab's object-oriented features. Each Object is customarily in a folder that begins with an "#" and has the file(s) for that class inside. (though the newer syntax does not require this for a class defined in a single file.) Using private folders inside class folders, matlab even supports private class members. Matlab's new class notation is relatively fully-featured, but even the old syntax is useful.
BTW, my startup.m that examines a well-known location that I do my SVN checkouts into, and adds all of the subfolders onto my path automatically.
The package system is probably the best. I use the class system (#ClassName folder), but I actually write objects. If you're not doing that, it's silly just to write a bunch of static methods. One thing that can be helpful is to put all your matlab code into a folder that isn't on the matlab path. Then you can selectively add just the code you need to the path.
So say you have two projects, stored in "c:\matlabcode\foo" and "c"\matlabcode\bar", that both use common code stored in "c:\matlabcode\common," you might have a function "setupPaths.m" like this:
function setupPaths(projectName)
basedir = fullfile('c:', 'matlabcode');
addpath(genpath(fullfile(basedir, projectName)));
switch (projectName)
case {'foo', 'bar'}
addpath(genpath(fullfile(basedir, 'common')));
end
Of course you could extend this. An obvious extension would be to include a text file in each directory saying what other directories should be added to the path to use the functions in that directory.
Another useful thing if you share code is to set up a "user specific/LabMember" directory structure, where you have different lab members save code they are working on. That way you have access to their code if you need it, but don't get clobbered when they write a function with the same name as one of yours.