Is there an equivalent to __MODULE__ for named functions in Elixir/ Erlang? - erlang

Is there an equivalent for retrieving the name of a function just like like __MODULE__ retrieves the name of a Module in Elixir/Erlang?
Example:
defmodule Demo do
def home_menu do
module_name = __MODULE__
func_name = :home_menu
# is there a __FUNCTION__
end
End
EDITED
The selected answer works,
but calling the returned function name with apply/3 yields this error:
[error] %UndefinedFunctionError{arity: 4, exports: nil, function: :public_home, module: Demo, reason: nil}
I have a function :
defp public_home(u, m, msg, reset) do
end
The function in question will strictly be called within its module.
Is there a way to dynamically call a private function by name within its own module?

▶ defmodule M, do: def m, do: __ENV__.function
▶ M.m
#⇒ {:m, 0}
Essentially, __ENV__ structure contains everything you might need.

Yes, there is. In Erlang there are several predefined macros that should be able to provide the information you need:
% The name of the current function
?FUNCTION_NAME
% The arity of the current function (remember name alone isn't enough to identify a function in Erlang/Elixir)
?FUNCTION_ARITY
% The file name of the current module
?FILE
% The line number of the current line
?LINE
Source: http://erlang.org/doc/reference_manual/macros.html#id85926

To add to Aleksei's answer, here is an example of a macro, f_name(), that returns just the name of the function.
So if you use it inside a function, like this:
def my_very_important_function() do
Logger.info("#{f_name()}: about to do important things")
Logger.info("#{f_name()}: important things, all done")
end
you will get a log statement similar to this:
my_very_important_function: about to do important things
my_very_important_function: important things, all done
Details:
Here is the definition of the macro:
defmodule Helper do
defmacro f_name() do
elem(__CALLER__.function, 0)
end
end
(__CALLER__ is just like __ENV__, but it's the environment of the caller.)
And here is how the macro can be used in a module:
defmodule ImportantCodes do
require Logger
import Helper, only: [f_name: 0]
def my_very_important_function() do
Logger.info("#{f_name()}: doing very important things here")
end
end

Related

Rspec: Checking the content of a system call

I have a Rake task in my Rails project which executes openssl through a system call.
The code looks like this:
system('bash', '-c', 'openssl cms -verify...')
I need to run the command in bash rather than dash (which is default on Ubuntu) to use process substitution in the command.
I need to create a test with rspec which checks that, in this case, the argument verify was passed as expected.
I have tried the following:
expect(Kernel).to receive(:system) do |args|
expect(args[2]).to match(/verify/)
end
However, this only gives me the third letter in the first string sent to system - i.e. the letter s from bash - rather than the third argument sent in the system call.
What am I doing wrong here? Any suggestions would be much appreciated.
Args are being passed to the block as sequential arguments, so if you want to treat them as an array, you need a splat operator in do |*args|:
expect(Kernel).to receive(:system) do |*args|
expect(args[2]).to match(/verify/)
end
Just to take a step back, it's important to understand how block arguments work, since they are different from methods. For example:
def my_fn(*args)
yield(*args)
end
my_fn(1,2,3) { |args| print args }
# => 1
my_fn(1,2,3) { |a, b, c| print [a,b,c] }
# => [1,2,3]
my_fn(1,2,3) { |*args| print args }
# => [1,2,3]
So if you did do |args| (without the splat), you are assigning the args variable to the first argument passed to the block ("bash") and ignoring the other arguments.

Is there an easy way to unpack two arrays/varargs in Lua?

Lets take a look at this pseudo code example:
-- Wraps a function with given parameters inside a callback
-- Usefull for sending class methods as callbacks.
-- E.g. callback(object.method, object)
local function callback(func, ...)
return function(...)
func(..., ...)
end
end
How would I go about this?
I know there is unpack, but it would get swallowed by the second vararg:
local function callback(func, ...)
local args = { ... }
return function(...)
func(table.unpack(args), ...)
end
end
callback(print, "First", "Second")("Third") --> prints First Third
The only option I found so far, is to concat those together and then unpack it:
local function callback(func, ...)
local args1 = { ... }
return function(...)
local args2 = { ... }
local args = { }
for _, value in ipairs(args1) do
table.insert(args, value)
end
for _, value in ipairs(args2) do
table.insert(args, value)
end
func(table.unpack(args))
end
end
Is this the only solution, or could I do better?
What I would like to have is either a function, that concats two arrays together (which should be faster than those two for loops) and then use table.unpack on it, or make those varargs concat.
From the Lua 5.4 Reference Manual: 3.4 Expressions
If an expression is used as the last (or the only) element of a list
of expressions, then no adjustment is made (unless the expression is
enclosed in parentheses). In all other contexts, Lua adjusts the
result list to one element, either discarding all values except the
first one or adding a single nil if there are no values.
So the only way is to manually combine both lists to a single one befor you use them.
There are several ways to do this.
for i,v in ipairs(list2) do
table.insert(list1, v)
end
for i,v in ipairs(list2) do
list1[#list1+i] = v
end
table.move(list2, 1, #list2, #list1 + 1, list1)
I'm not sure what kind of problem you're actually trying to solve here.
If you want to access your object from its methods use self.
-- Wraps a function with given parameters inside a callback
-- Usefull for sending class methods as callbacks.
-- E.g. callback(object.method, object)
Usually you would do something like this:
local callback = function(params) object:method(params) end
callback(params)
Instead of
callback(print, "First", "Second")("Third")
You could do this
local callback = function (...) print("First", "Second", ...) end
callback("Third")
Edit ( opinonated )
My main goal is to use member functions as callbacks. However, I'd
like to keep it general. The advantage of a callback function is to
omit the function and end keyword. It's shorter and looks closer to
what it would look like, if there would be no need for a self
argument. So this: object.event = function(...) return
self:method(...) end would become to this: object.event =
callback(self.method, self) what would be even nicer, is this (sadly
not possible in lua) object.event = self:method
So instead of
RegisterCallback(function() obj:method() end)
You say it is easier to do this, so you don't have to write function end?
local function callback(func, ...)
local args1 = { ... }
return function(...)
local args2 = { ... }
local args = { }
for _, value in ipairs(args1) do
table.insert(args, value)
end
for _, value in ipairs(args2) do
table.insert(args, value)
end
func(table.unpack(args))
end
end
RegisterCallback(callback(obj.method, obj)())
Your approach is not going to work if any of the arguments is nil to begin with. And there is not a single advantage. You're just typing other words while increasing the chance of running into errors.
You can control the param order to optimize your function.
local function callback(func, ...)
local args = {...}
return function(...)
func(..., table.unpack(args))
end
end
callback(print, "second", "third")("first") -- prints first second third

How or Can I pass a function with argument as a parameter to a function in lua?

I am not running straight lua but the CC-Tweaks ComputerCraft version. This is an example of what I am trying to accomplish. It does not work as is.
*edited. I got a function to pass, but not one with arguments of its own.
function helloworld(arg)
print(arg)
end
function frepeat(command)
for i=1,10 do
command()
end
end
frepeat(helloworld("hello"))
frepeat(helloworld("hello"))
will not pass the helloworld function like frepeat(helloworld) does, because it always means what it looks like: call helloworld once, then pass that result to frepeat.
You need to define a function doing what you want to pass that function. But an easy way to do that for a single-use function is a function expression:
frepeat( function () helloworld("hello") end )
Here the expression function () helloworld("hello") end results in a function with no name, whose body says to pass "hello" to helloworld each time the function is called.
Try this code:
function helloworld(arg)
print(arg)
end
function frepeat(command,arg)
for i=1,10 do
command(arg)
end
end
frepeat(helloworld,"hello")
If you need multiple arguments, use ... instead of arg.
"repeat" is reserved word in lua. Try this:
function helloworld()
print("hello world")
end
function frepeat(command)
for i=1,10 do
command()
end
end
frepeat(helloworld)

Lua (require) invoke an not intended print of required file name

When require is called in testt.lua which is one of two files the return is movee and movee.lua.
movee are for the most part a class to be required, but should be able to accept to be called direct with parameter.
movee.lua
local lib = {} --this is class array
function lib.moveAround( ... )
for i,direction in ipairs(arg) do
print(direction)
end
end
function lib.hello()
print("Hello water jump")
end
lib.moveAround(...)
return lib
testt.la
local move = require("movee")
Expected result is not to call lib.moveAround or print of file name when require is called.
Your expectations are incorrect. Lua, and most scripting languages for that matter, does not recognize much of a distinction between including a module and executing the Lua file which provides that module. Every function statement is a statement whose execution creates a function object. Until those statements are executed, those functions don't exist. Same goes for your local lib = {}. And so on.
Now, if you want to make a distinction between when a user tries to require your script as a module and when a user tries to execute your script on the command line (or via just loadfile or similar), then I would suggest doing the following.
Check the number of arguments the script was given. If no arguments were given, then your script was probably required, so don't do the stuff you don't want to do when the user requires your script:
local nargs = select("#", ...)
if(nargs > 0) then
lib.moveAround(...)
end
Solved by replacing
lib.moveAround(...)
with
local argument = {...}
if argument[1] ~= "movee" and argument[2] ~= "movee" then
lib.moveAround(...)
end
require("movee")
will execute the code within movee.lua
lib.moveAround(...)
is part of that code. Hence if you require "movee" you call lib.moveAround
If the expected result is not to call it, remove that line from your code or don't require that file.

Function overlapping specs

I have a simple function like this:
def extract_text({_, _, [text]}) when is_binary(text), do: text
def extract_text(_), do: nil
and the spec I added for it was:
#spec extract_text(any) :: nil
#spec extract_text({any, any, [text]}) :: text when text: String.t
but when I run dializer, I get the following error:
lib/foo/bar.ex:1: Overloaded contract for
'Elixir.Foo.Bar':extract_text/1 has overlapping domains;
such contracts are currently unsupported and are simply ignored
I think I understand the reason for it but I can't really come up with a solution. What would be the right spec for this function?
You should be aware of that, even if you define multiple functions of the same arity (accept the same number of arguments), from outside world this is considered only one function. That means, you need to define function signature, and only this one should have type spec defined.
Try the following:
#spec extract_text(any) :: String.t | nil
def extract_text(arg)
def extract_text({_, _, [text]}) when is_binary(text), do: text
def extract_text(_), do: nil

Resources