Rspec: Checking the content of a system call - ruby-on-rails

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.

Related

xonsh: Is there a way to call a function as a command that takes optional arguments?

I have a function in Xonsh that I'm trying to use like a command (ie: without parens). The function should optionally take arguments, however whenever I call the function without arguments, I just get the function address. How do you call a function with optional parameters?
Here's the example:
def _up(args, stdin=None):
# go up any number of directories
if not args or len(args) < 1:
args[0] = 1
balloons = ('../' * int(args[0]))
# echo #(balloons)
cd #(balloons)
aliases['up'] = _up
When I call up with no parameters, I get <function __main__.up>. When I call it like this, it works: up 2.
I could do a function like this that works, but then I can't call it without using parentheses (ie: as a command) which is what I'd prefer:
def up(dirs=1):
# go up any number of directories
balloons = ('../' * dirs)
# echo #(balloons)
cd #(balloons)
Calling up() and up(2) both work this way, but is more cumbersome than just calling up or up 2. What's the right way to accomplish what I'm trying to do in Xonsh?
I'm not certain why you're getting the function repr when you aren't passing in an argument, but a tweaked version of your function works:
def _up(args): # don't need stdin
# go up any number of directories
if not args or len(args) < 1:
args = [1] # if args is None you can't index to it
balloons = ('../' * int(args[0]))
# echo #(balloons)
cd #(balloons)
aliases['up'] = _up
on current-ish main of xonsh # c2f862df this works to go up one level with just an up or you can specify many levels with up 3, etc.

How to execute a groovy share library with optional parameters

I'm developing a shared library to execute it from my Jenkinsfile. This library has a function with optional parameters and I want to be able to execute this function with any number of parameters by specifying my value. I've been googling a lot, but couldn't find a good answer, so maybe somebody here could help me.
Example:
The function looks this way:
def doRequest(def moduleName=env.MODULE_NAME, def environment=env.ENVIRONMENT, def repoName=env.REPO_NAME) {
<some code goes here>
}
If I execute it from my Jenkinsfile this way:
script {
sendDeploymentStatistics.doRequest service_name
}
the function puts "service_name" value to the moduleName, but how do I specify "repoName" parameter?
In Python you would do it somehow like:
function_name(moduleName=service_name, repoName=repo_name)
but in Groovy + Jenkinsfile I can't find the right way.
Can anybody please help me to find out the right syntax?
Thank you!
Groovy has the concept of Default Parameters. If you change the order of the parameters, such that the environment comes last:
def doRequest(def moduleName=env.MODULE_NAME, def repoName=env.REPO_NAME, def environment=env.ENVIRONMENT) {
<some code goes here>
}
Then your call to function_name will take the default value for environment:
function_name(moduleName=service_name, repoName=repo_name)
Groovy however also has some sort of support for Named Parameters. It is not as nice as Python but you can get it to work as follows:
env = [MODULE_NAME: 'foo', ENVIRONMENT: 'bar', REPO_NAME: 'baz']
def doRequest(Map args = [:]) {
defaultMap = [moduleName: env.MODULE_NAME, environment: env.ENVIRONMENT, repoName: env.REPO_NAME]
args = defaultMap << args
return "${args.moduleName} ${args.environment} ${args.repoName}"
}
assert 'foo bar baz' == doRequest()
assert 'foo bar qux' == doRequest(repoName: 'qux')
assert '1 2 3' == doRequest(repoName: '3', moduleName: '1', environment: '2')
For Named Parameters you need a parameter of type Map (with a default value of the empty map). Groovy will then map the arguments upon calling the function to entries in a Map.
To use default values you need to create a map with the default values, and merge that defaultMap with the passed-in arguments.

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.

Is there an equivalent to __MODULE__ for named functions in Elixir/ 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

How to save a variable in an rspec expect?

I have something along the following lines in one of my spec files:
expect(my_instance).to receive(:my_function).with(arg: instance_of(String))
I want to be able to capture the actual value of arg in a variable I can use in the spec. Is there a way to do that? I checked the rspec docs but didn't find anything like that.
You could declare the variable, say captured_arg before the expect (or allow, if you don't want it to fail if my_instance does not receive my_function). Then you can collect the arguments in a block and set captured_arg within that block.
captured_arg = nil
expect(my_instance).to receive(:my_function) { |arg| captured_arg = arg }
Edit: (Keyword Arguments)
If you are using keyword arguments, just modify the script above slightly, using arg as the keyword argument you'd like to capture:
captured_arg = nil
expect(my_instance).to receive(:my_function) { |args| captured_arg = args[:arg] }

Resources