Getting Scala Command Line Arguments

I have a large number of simple Scala command-line applications that share a fairly general structure. They all inherit from scala.App, which is just fine. I would like to reorganize the general structure of these command-line applications into a common feature, which I could then inherit in my (much simpler) classes of command-line applications. The problem is that some of the general structure includes parsing command line arguments.

object MyScript extends BaseScript with App{ //small bits of business logic using components defined in BaseScript } trait BaseScript extends App{ val configuration = loadConfiguration(args(0)) //setup a bezillion components, usable from any of the scripts, based on the configuration } 

This compiles, but does not work with NPE when it comes time to actually dereference args , apparently because the App flag has not yet been initialized. Changing character orders and changing the inheritance of an App in BaseScript as a self-supporting declaration do nothing, just like experimenting with DelayedInit. Declaring components as “lazy” in BaseScript will work, but I also need to use these components during initialization (for example, setting up log directories and loading JDBC driver classes based on configuration), so the benefits of laziness are lost. Is there something I can do to make the command line arguments visible and initialized in a BaseScript value?

+4
source share
3 answers

I think it's best to change your BaseScript into a class for two reasons. First, in comparison with classes, the initialization of attributes is performed in the reverse order . See this question about initialization behavior . Second, BaseScript semantically more of a superclass than additional behavior. I think you will find that this can simplify the situation.

When executing MyScript following code first initializes the BaseScript class. BaseScript depends on the attribute of the App in turn and forces it to initialize first.

 object MyScript extends BaseScript { //small bits of business logic using components defined in BaseScript println( "running" ) println( "arg(0): " + configuration ) } class BaseScript extends App { val configuration = loadConfiguration(args) //setup a bezillion components, usable from any of the scripts, based on the configuration def loadConfiguration( args: Array[String] ) = { println( "configuring" ) if ( args.length > 0 ) args(0) else null } } 
+4
source

Have you tried using lazy val (and not extending the App trait)?

 trait BaseScript { self : App => lazy val configuration = loadConfiguration(args(0)) //setup a bezillion components, usable from any of the scripts //based on the configuration } 
+3
source

Looking at the source of the App , it seems you can override main to do something with arguments before running your application code:

 trait AppUtil extends App { def myInit(args: Array[String]) { println("args " + args.size) } override def main(args: Array[String]) { myInit(args) super.main(args) } } 

I suspect that the source of the App may give you inspiration to rewrite your own App . The code is really not that long, and you will have more control over things, for example, what you do with args , what happens before and after your main run.

+1
source

Source: https://habr.com/ru/post/1384776/


All Articles