Exported Variables not work outside zsh functions - zsh

I try to set function in zshrc file and call it when I need specific variables. But when I invoke this function there are no variables that I can use:
.zshrc file:
# .zshrc file
function c() {
(
export TEST=/tmp/just.log
)
}
So when I invoke c() inside shell there is no TEST var.
how do I enable this functionality?

Remove the brackets and it should work.
The brackets create a subshell which prevent your variable from being visible.
see https://zsh.sourceforge.io/Doc/Release/Shell-Grammar.html and search for subshell
# .zshrc file
function c() {
export TEST=/tmp/just.log
}

Related

How can I access the current value of an environment variable in a zsh prexec function?

I have a simple function like
function clearit() {
REM=$(($LINENO % $LINES))
DIV=$(($LINENO / $LINES))
if [[ $DIV -gt 0 && $REM -lt 3 && $DIV ]]; then
clear
fi
echo $LINENO, $LINES
}
add-zsh-hook preexec clearit
In the above function a static value of $LINE and $LINES is added to the prehook function. I want to get the current value when the prexec is executed. How can I do that ?
For normal shell variables, you will get the current value:
% x=1
% function test_hook() { echo $x; }
% add-zsh-hook preexec test_hook
% true
1
% x=2
1
% true
2
However, $LINENO is a very special variable. From the documentation:
LINENO <S>
The line number of the current line within the current script, sourced file, or shell function being executed, whichever was started most recently. Note that in the case of shell functions the line number refers to the function as it appeared in the original definition, not necessarily as displayed by the functions builtin.
When your hook function is executing, it is by definition the most recently started shell function, script or sourced file. So $LINENO always gives you the current line within your hook function. There is no way to access the $LINENO for the outer scope.
However, even if you could access the outer $LINENO in your hook, it would lead to very strange behaviour in my opinion. Let's say your terminal is 30 lines high ($LINES is 30), it would clear the terminal before executing the 30th, 31st and 32nd command, then nothing for the next 27 commands, then again clearing before the 60th, 61st and 62nd, and so on. I don't think this is remotely what you are trying to achieve...

R: How to test a function that relies on an external program using testthat?

I have a function bowtieIndex(bowtieBuildLocation, filename) that calls bowtie2-build. It's parameters are the bowtie2-build location on my system and the output filename.
How do I write a test for this function without hard-coding the bowtie2-build location?
If all you are doing inside the function is calling an external program, then you can't test if that works directly. Without the code itself, this is hard to answer specifically, but if, for example, bowtieIndex is calling system to run an external program, you can mock what system will do, pretending that it worked, or failed. Look at the documentation for testthat::with_mock.
Three examples follow. The first parameter is the new code that will be executed instead of the real system function. The parameters that the system function was called with are available as normal in a function definition, if you want to do very specific things. I find it easier to test repeatedly rather than write a complex replacement function. Everything inside the second parameter, a code block { }, is executed with a context that see only the replacement system function, including all nested function calls. After this code block, the with_mock function exits and the real base::system is back in scope automatically. There are some limits to what functions can be mocked, but a surprising number of base functions can be over-ridden.
# Pretend that the system call exited with a specific error
with_mock(
`base::system`= function(...) {
stop("It didn't work");
}, {
expect_error( bowtieIndex( bowtieBuildLocation, filename ),
"It didn't work"
)
})
# Pretend that the system call exited with a specific return value
with_mock(
`base::system`= function(...) {
return(127);
}, {
expect_error( bowtieIndex( bowtieBuildLocation, filename ),
"Error from your function on bad return value." )
expect_false( file.exists( "someNotGeneratedFile" ))
})
# Pretend that the system call worked in a specific way
with_mock(
`base::system`= function(...) {
file.create("someGeneratedFile")
return(0);
}, {
# No error
expect_error( got <- bowtieIndex(bowtieBuildLocation, filename), NA )
# File was created
expect_true( file.exists( "someGeneratedFile" ))
})
# got variable holding results is actually available here, outside
# with_mock, so don't need to test everything within the function.
test_equal( got, c( "I", "was", "returned" ))

Use main function in R

I've been using R for 4 months now, and I really hope there is a way to use main function as in other languages (C++, Python...)
The main reason I want to do this is that all the variables I use in a R script are global variables that can potentially pollute the namespace of the functions I defined in the same script:
f <- function(x) {
x + a
}
a <- 50
f(5)
For me, this is just a personal preference. I'm a sloppy programmer and I want to prevent myself from making silly mistakes.
I can surely define main <- function() {}, but I want to know if there is anything similar to this:
if __name__ == "__main__":
main()
(In this Python script, if the function name is main, then run main() to call the main function.)
So, it's not quite the same as __name__ == "__main__", but you might find the interactive function interesting here. Which returns TRUE if you are in an interactive mode.
So you can do something like this:
main <- function() {
....
}
if(!interactive()) {
main()
}
This is a bit different though because it will always run if it's required from a script.
but is there anything similar to
if __name__ == "__main__":
main()
in python?
There is indeed!
But you need to use the package ‘box’ instead of source/packages. Then, inside your module, you can write
if (is.null(box::name())) …
… which is equivalent to Python’s if __name__ == '__main__'.
Or you can even use the klmr/sys module. Then you can write the following:
box::use(klmr/sys)
f = function(x) {
x + a
}
sys$run({
a = 50
sys$print(f(5))
})
If you execute this script on the command line (via Rscript or R CMD BATCH), it will execute the main function specified by sys$run. Conversely, if you import this script as a module into another script, the main function won’t be executed, but f will still be defined and exported.
Answering your exact question (I'm not addressing whether it makes sense in the context of R. I'm only starting to dig deeper into R and finding it ill suited to write non-interactive programs so I'm blaming it on me). You can create a main function and pass to it the input arguments. However, note that for this work you don't call it via R. It seems that you need to use Rscript instead.
main <-function (argv)
{
if (length (argv) < 3)
{
cat ('usage error: requires at least 3 arguments\n',
file=stderr ());
return (1);
}
cat (sprintf ('This program was called with %d arguments\n',
length (argv)));
return (0);
}
if (identical (environment (), globalenv ()))
quit (status=main (commandArgs (trailingOnly = TRUE)));
Not sure what the point of your function is, but perhaps a solution is to use a default argument
f <- function(x, a = 45) {
x + a
}
a <- 50
f(5)
Then if you need to change the a term, change it within the function rather than rely on the context in which it is called.
The simplest solution that I have found that will work even when running source("..") from the interactive terminal (unlike Leif Andersen's solution) is:
if (sys.nframe() == 0) {
# ... do main stuff
}
sys.nframe() is equal to 0 when run from the interactive terminal or using Rscript.exe, in which case the main code will run. Otherwise when the code is sourced, sys.nframe() is equal to 4 (in my case, not sure how it works exactly) which will prevent the main code from running.
source
You can try the below... Place the below block in your R script as part of the global environment and it will invoke the main() method when the script is executed.
if(getOption("run.main", default=TRUE)) {
main()
}
Hope this fits in with your stated requirement
if __name__ == "__main__":
main()

Is there a way to jump to the end of a sourced script without killing entire execution in R?

Suppose I have a script Foo.r which looks like this.
source('Bar.r')
print("Hello World")
Now suppose further that in Bar.r, I want to return immediately if some condition is true, instead of executing the rest of the script.
if (DO_NOT_RUN_BAR) return; // What should return here be replaced with?
// Remainder of work in bar
In particular, if DO_NOT_RUN_BAR is set, I want Bar.r to return and Foo.r to continue execution, printing Hello World.
I realize that one way to do this is to invert the if statement in Bar.t and wrap the entire script inside an if statement that checks for the logical negation of DO_NOT_RUN_BAR, but I still want to know whether I can replace the return statement in the code above to skip execution of the rest of Bar.r when it is sourced.
By defintion , source parse a file until the end of the file.
So, I would split bar file in 2 parts :
source("bar1.R")
if (DO_RUN_BAR2) source("bar2.R")
print("Hello World")
This is safer than managing global variables with dangerous side effect.
In Bar.r you can do
if (DO_NOT_RUN_BAR) stop();
Then in Foo.r you call it like this
try(source("./bar.r"), silent=T)
Create your script with a multi-line expression with {...} enclosing it, and use stop in the middle:
{ print("test")
print("test")
print("test"); stop()
print("test")
print("test")
print("test") }
#[1] "test"
#[1] "test"
#[1] "test"
#Error:

Error: could not find function "nnn.R"

I sourced my function nnn.R using the line :
source("nnn.R")*
and did not get any errors, but when I try to run it, this is what I get:
Error: could not find function "nnn"*
this all what the function has inside
function (x) is.null(x)
nnn.R is a file, not a function. The file must contain a function, defined as:
nnn <- function(x) {
return (is.null(x))
}
Note that nnn.R may contain several function definitions. See for instance this tutorial.

Resources