9

I would like R scripts to have a main() function that gets executed while in interactive mode. But the main() function should not be executed while sourcing the file.

There is already a question about this and a very good answer suggests using the interactive() function. However this doesn't work for me. I don't have enough reputation points to comment or answer in that question. So I ask the question here again.

I write this in script_1.r

if(interactive()){
  your main code here
}

If I use knitr to waive a html or pdf document, sourcing the script. This code under if(interactive()) won't be executed. This is good for me, that's what I want.

My problem is that if I source("script_1.r") from script_2.r in interactive mode, it will still run the code under this if(interactive()) part.

Community
  • 1
  • 1
Paul Rougieux
  • 10,289
  • 4
  • 68
  • 110

3 Answers3

7

The best way to get the kind of control you're looking for is to use options.

For instance, 'script.r' would look like this:

main <- function() {
    message('main!')
}

if (getOption('run.main', default=TRUE)) {
   main()
}

If you are sourcing the file in interactive mode and don't want main to execute, simply call options(run.main=FALSE) before you call source. If you are using the script with knitr and you want main to execute, don't set the option, and it will default to TRUE. Or if you don't want the main to run with knitr, call options(run.main=FALSE) before calling it.

Matthew Plourde
  • 43,932
  • 7
  • 96
  • 113
  • Thank you Matthew, I didn't know you could set options that way. It does what I want. – Paul Rougieux Jan 27 '14 at 16:24
  • I set the option to FALSE before sourcing the script and set it back to TRUE afterwards. options(run.load.main=FALSE) source("code/load.r") options(run.load.main=TRUE) – Paul Rougieux Jan 27 '14 at 16:54
1

As you’ve noticed, no, it’s not the same thing. if(interactive()) does exactly what the name says – it tests whether the code is run in an interactive shell. No more, no less.

There’s no direct equivalent of if __name__ == '__main__' from Python in R, since R has no concept of modules in the same way as Python, and source’d code is just executed directly.

You could write your own source command to replace the default one and perform the necessary check, however.

That said, the question you’ve linked does contain an answer which presents a workaround and essentially replicates Python’s functionality. However, this doesn’t seem to be what you want since it won’t work as you expect when invoked by Knitr.

Community
  • 1
  • 1
Konrad Rudolph
  • 530,221
  • 131
  • 937
  • 1,214
  • Thanks, if(interactive()) does what I want when invoked by Knitr, but not when invoked by another script in interactive mode. Maybe the last part of my question wasn't clear. – Paul Rougieux Jan 27 '14 at 16:02
  • @Paul4forest No, it was clear. But like I said, there’s no ready solution for that. – Konrad Rudolph Jan 27 '14 at 16:07
  • Since I asked this question, I have [learned to put my code in R packages](http://r-pkgs.had.co.nz/). The need to source files has mostly disappeared. I build and load my package instead. – Paul Rougieux Jan 29 '16 at 11:09
  • @PaulRougieux Funny, since answering this question [I’ve written a package, ‹modules›](https://github.com/klmr/modules), which serves to replace the cumbersome old-style R packages in favour of a more Pythonesque architecture. Of course I’m biased but I find modules vastly superior to packages in many aspects. Among other things, ‹modules› provides a direct equivalent to Python’s entry point, via the [‹sys› module](https://github.com/klmr/sys/). – Konrad Rudolph Jan 29 '16 at 14:06
1

Another way I have found that will work as you described without the need to use and change options 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

user897506
  • 21
  • 4