How to get the fully-qualified name of the currently executing function? - matlab

Suppose I have:
+MyPackage/+MySubPackage2/some_function.m
How can I generate the string 'MyPackage.MySubPackage2.some_function' from within this some_function.m when it's executing?
mfilename(), dbstack(), what(), etc. all just give 'some_function'
meta.package.fromName requires the string we're after as its input
parsing the full path (mfilename('fullpath')) or meta.package.getAllPackages() etc. seems to be the only way...
Seems that calling mfilename('class') in a class inside a package gives the right answer, but there's no equivalent for plain functions...
...or is there? Feels like I'm missing something obvious...

If it is possible to import the containing package (say p1/p2), then:
function outputArg1 = some_function()
import p1.p2.*
t = #some_function;
func2str(t)
%ans = 'p1.p2.some_function'
outputArg1 = ...;
end
The method in this answer may also be used (with some changes possibly) to automate the import process.

Related

Using unittest with own matlab toolbox

I inherited a code base in matlab, which I like to put under unittest with the matlab.unittest framework.
To make the code base more robust against arbitrary addpath of my users, I have put most of the code into +folders like a toolbox. So the general layout is:
+folder1/file1.m
+folder1/runtestsuite.m
+folder1/unittest_data/file1_testdata.mat
+folder1/+folder2/file2.m
+folder1/+folder2/unittest_data/file2_testdata.mat
...
and updated all internal references with the correct import statements.
Now, I like to add a unittest for file1.m. However if I put a file in +folder1/file1_test.m file1.m seems not to be visible.
Here is my example code of file1_test.m
classdef file1_test < matlab.unittest.TestCase
properties
path
end
methods(TestMethodSetup)
function setunittestdatapath(testCase)
p = mfilename('fullpath');
[directory,~,~]=fileparts(p);
testCase.path = fullfile(directory,'unittest_data');
end
end
methods (Test)
function file1_input(testCase)
%import folder1.file1
testdata = load(fullfile(testCase.path),'file1_testdata.mat');
result = file1(testdata.input);
testCase.verifyEqual(result, testdata.output);
end
end
end
If I uncomment the import statement the unittest works fine. So currently I have to add all import statements to each individual test, which I like to avoid. Is there a more elegant way for doing something like this?
I tried importing it at the beginning of the file, although matlab complains "Parse error at CLASSDEF: usage might be invalid MATLAB syntax." this also works. So what is the correct and most pragmatically way for doing something like this?
import statements only apply to the local scope of where they are used so if you want a function to be able to not use the full-qualified name, then you'll have to add the import statement to each function separately.
The import list scope is defined as follows:
Script invoked from the MATLAB® command prompt — Scope is the base MATLAB workspace.
Function, including nested and local function — Scope is the function and the function does not share the import list of the parent function. If the import list is needed in a MATLAB function or script and in any local functions, you must call the import function for each function.
For unit tests though, I would argue that it is probably best to use the fully-qualified function name every time (rather than relying on import) so that it's clear to the user what you're testing.
result = folder1.file1(testdata.input)
Currently import statements in MATLAB have function scope as mentioned in the answer by Suever.
However, I often use local functions as a workaround to mimic a file level import:
classdef file1_test < matlab.unittest.TestCase
properties
path
end
methods(TestMethodSetup)
function setunittestdatapath(testCase)
p = mfilename('fullpath');
[directory,~,~]=fileparts(p);
testCase.path = fullfile(directory,'unittest_data');
end
end
methods (Test)
function file1_input(testCase)
%import folder1.file1
testdata = load(fullfile(testCase.path),'file1_testdata.mat');
result = file1(testdata.input);
testCase.verifyThat(result, IsEqualTo(testdata.output));
end
end
end
% Include file level "import" functions below
function f = file1(varargin)
f = folder1.file1(varargin{:});
end
function c = IsEqualTo(varargin)
c = matlab.unittest.constraints.IsEqualTo(varargin{:});
end
Note in this example I "imported" both your source code as well as some of the test framework source code in order to use the literate form of verifyEqual using verifyThat. Note this is the same functional behavior, but in general there exists more functionality with the constraints than with the qualification methods so this may be helpful to you at some point.

Macro to evaluate expression and create import

This may seem odd and is perhaps impossible but I was wondering if there's a way to create a macro that evaluates the expression passed and performs an import.
I can get it to work easily enough if a string literal is the expression:
import macros
macro createImport(ex: expr): stmt =
result = newNimNode(nnkImportStmt)
result.add(ex)
createImport("strutils")
let a = ["foo", "bar", "baz"]
echo a.join("---") # using `join()` from the `strutils` module
But if a variable is passed, this of course will fail.
var s = "strutils"
createImport(s)
(Note that the import could be a string path do a module.)
I've attempted many adjustments to the macro and scoured the docs and source but I just can't find a way to get the actual value of the ex: expr to be useful in the import.
I can get the macro to create an echo call that reveals the string passed but any attempt to use it with the import ends up using the variable name itself.
I guess it makes since since it would seem that the value may not be available when the macro itself is evaluated. Is it possible to do this and if so, how?
I'm not quite sure why you need such a helper macro and whether it's a good idea, but the simplest way to achieve what you need is the following:
template my_import(x: static[string]) = import x
const x = "strutils"
my_import x

Using LuaJ with Scala

I am attempting to use LuaJ with Scala. Most things work (actually all things work if you do them correctly!) but the simple task of setting object values has become incredibly complicated thanks to Scala's setter implementation.
Scala:
class TestObject {
var x: Int = 0
}
Lua:
function myTestFunction(testObject)
testObject.x = 3
end
If I execute the script or line containing this Lua function and pass a coerced instance of TestObject to myTestFunction this causes an error in LuaJ. LuaJ is trying to direct-write the value, and Scala requires you to go through the implicitly-defined setter (with the horrible name x_=, which is not valid Lua so even attempting to call that as a function makes your Lua not parse).
As I said, there are workarounds for this, such as defining your own setter or using the #BeanProperty markup. They just make code that should be easy to write much more complicated:
Lua:
function myTestFunction(testObject)
testObject.setX(testObject, 3)
end
Does anybody know of a way to get luaj to implicitly call the setter for such assignments? Or where I might look in the luaj source code to perhaps implement such a thing?
Thanks!
I must admit that I'm not too familiar with LuaJ, but the first thing that comes to my mind regarding your issue is to wrap the objects within proxy tables to ease interaction with the API. Depending upon what sort of needs you have, this solution may or may not be the best, but it could be a good temporary fix.
local mt = {}
function mt:__index(k)
return self.o[k] -- Define how your getters work here.
end
function mt:__newindex(k, v)
return self.o[k .. '_='](v) -- "object.k_=(v)"
end
local function proxy(o)
return setmetatable({o = o}, mt)
end
-- ...
function myTestFunction(testObject)
testObject = proxy(testObject)
testObject.x = 3
end
I believe this may be the least invasive way to solve your problem. As for modifying LuaJ's source code to better suit your needs, I had a quick look through the documentation and source code and found this, this, and this. My best guess says that line 71 of JavaInstance.java is where you'll find what you need to change, if Scala requires a different way of setting values.
f.set(m_instance, CoerceLuaToJava.coerce(value, f.getType()));
Perhaps you should use the method syntax:
testObject:setX(3)
Note the colon ':' instead of the dot '.' which can be hard to distinguish in some editors.
This has the same effect as the function call:
testObject.setX(testObject, 3)
but is more readable.
It can also be used to call static methods on classes:
luajava.bindClass("java.net.InetAddress"):getLocalHost():getHostName()
The part to the left of the ':' is evaluated once, so a statement such as
x = abc[d+e+f]:foo()
will be evaluated as if it were
local tmp = abc[d+e+f]
x = tmp.foo(tmp)

MATLAB: modify import list of other scopes dynamically?

So, is there a way in MATLAB to modify the import list of a scope different from the current one? That is, I would like to be able to do this:
function import_mypackage()
evalin('caller', 'import mypackage.*');
end
This doesn't work. No error is produced when calling import_mypackage, but the namespace contained in mypackage is not imported, i.e:
function foo()
import_mypackage;
g(); % Wanted mypackage.g() but got: Undefined function or variable 'g()'
end
I know that you can modify dynamically the import list of the current scope either using eval or by passing a variable to import(). However, I cannot find any way to modify the import list of other scopes. Is there any way?
EDIT: Rody Oldenhuis found in his answer a strange behavior of function import. He suggested that evalin actually modifies the import list of the caller but that such list is cleared once you return from import_mypackage. However, I think that what is happening is that import expressions always evaluate in the current worspace. See:
function import_mypackage()
evalin('caller', 'L = import(''mypackage.foo'');');
foo; % It works! So the import happened in this workspace
end
Modified from Rody's response:
function foo()
import mypackage.f;
import_mypackage;
L
import
end
will print:
L =
'mypackage.foo'
ans =
'mypackage.f'
indicating the L was set to the import list of import_mypackage scope but that it never really cleared the import list of foo().
EDIT: #RodyOldenhuis
The reason why I want to mess around with the import list of the caller scope is that I want to define an "aliased" version of import(). Such alias_import() would allow the user to define package aliases so that:
alias_import my_toolbox
may be equivalent to:
import my_toolbox_v1.*
or to:
import my_toolbox_v2.*
that is, I want to be able to maintain several versions of a toolbox and control dynamically the version that is being imported. This is useful for comparing results between different my_toolbox versions or whenever you want to ensure that certain my_toolbox version will be used. All without having to go to the code and manually change import directives in hundreds of functions whenever I am upgrading to a new version of my_toolbox. Of course there is the alternative of making this in an indirect way, like:
import(alias_import('my_toolbox'))
so that alias_import will not perform the actual importing but simply will produce the input to the built-in import. This is perfectly fine but a bit more verbose and that is why I would have liked alias_import to modify the caller's import list. But after seeing the weird behavior of evalin() I think I rather leave things like they are now.
It seems you have stumbled upon some odd behavior (I'm not using the workd "bug" until I'm sure this is not what Mathworks intended :).
It seems that
function import_mypackage()
evalin('caller', 'import mypackage.*');
end
function foo()
import_mypackage;
g();
end
does not work, but
function import_mypackage()
evalin('caller', 'L = import mypackage.*');
end
function foo()
import_mypackage;
L
import
end
shows
L =
'mypackage.*'
ans =
Empty cell array: 0-by-1
which implies that the import list in the caller (foo) is cleared when the function import_mypackage goes out of scope.
I'd say this is at least unwanted behaviour, and I'd say this is a case for a bug report.
As a work-around, use something like
function L = import_mypackage()
L = import('mypackage.*');
end
function foo()
L = import_mypackage;
import(L{:});
% do stuff with pacakge contents
...
end
which I think is advisable over evalin anyway.

Is self-reference possible in MATLAB?

As noted here, functions in packages, as well as static methods in classes, still need to use a packagename.functionname syntax or import packagename.* for each function (since the imports are part of the function workspace and not global). This means that changing the package/class name later on can become a tedious nuisance.
Is there any way to do something like import this.*, i.e. a package/class name agnostic method to access all functions/static methods in the same package/class?
So... doesn't this require importthis to also be imported? Or is importthis a function you always have in your path?
It seems hardly more complex to just paste an "import this" block with this at the top of each function, and then you don't have to worry about importthis being in your path. I tend to feel that reliance on path is dangerous.
"Import This" block
%% Import own package
[~, pkgdir] = fileparts(fileparts(mfilename('fullpath')));
import([pkgdir(2:end) '.*']);
You can even put it in a try/catch block to make sure it's in a package directory, and decide what to do if it's not.
%% Import own package
try
[~, pkgdir] = fileparts(fileparts(mfilename('fullpath')));
import([pkgdir(2:end)'.*']);
catch err
if ~strcmp(err.identifier,'MATLAB:UndefinedFunction'), rethrow(err); end
end
I recently ran into a similar problem and found the following solution for packages. However it is VERY hacky.
You create a function called import this with an optional argument.
function to_eval = importthis(exclude_list)
if nargin == 0
exclude_list = [];
end
var_name = genvarname('A', exclude_list); %avoid shadowing
to_eval = ['[~,'...
, var_name...
, ']=fileparts(fileparts(mfilename(''fullpath'')));'... %get containing dir
, 'eval([''import '','...
, var_name...
, '(2:end),''.*'']);'... %remove '+'
, 'clear '... %clean up
, var_name
];
end
This function returns a string which can then be evaled that imports the "this" package. So in your package functions you would put the following near the top:
function B = myfunc(A)
eval(importthis);
%function body
end
You can also pass who to importhis, leaving your function's namespace clean.
function B = myfunc(A)
eval(importthis(who));
%function body
end
I can't decide whether I should feel proud or discusted by what I did.
This probably is not a bounty worthy answer but as you do not have any answers I thought I would post it anyway! You can invoke static methods via an instance of the class which you would only need to define once. You can invoke functions via a function handle but this would require one handle per function.
Using these techniques you could define all your static method and function references in one place. Then you would use these references throughout your package. Then if you decided to change the package name at a later point you would only need to update these references which are all stored in one place.
See:
Calling Static Methods
You can also invoke static methods using an instance of the class,
like any method:
obj = MyClass;
value = obj.pi(.001);
function_handle (#)
The following example creates a function handle for the humps function
and assigns it to the variable fhandle.
fhandle = #humps;