daily pastebin goal
5%
SHARE
TWEET

Untitled

a guest Apr 21st, 2018 62 Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. package net.harnly.aaron.options
  2.  
  3. import scala.collection.mutable.{ListBuffer}
  4.  
  5. // Base class for options.
  6. // These are things that get listed when we ask for help,
  7. // and optionally can accept string arguments & perform some kind of action,
  8. // usually mutating a var.
  9. case class OptionDefinition(
  10.    canBeInvoked: Boolean,
  11.    shortopt: String,
  12.    longopt: String,
  13.    description: String,
  14.    action: String => Unit,
  15.    gobbleNextArgument: Boolean
  16. )
  17.  
  18. // ----- Some standard option types ---------
  19. class SeparatorDefinition(
  20.    description: String
  21. ) extends OptionDefinition(false,null,null,description, {a: String => {}}, false)
  22.  
  23. class ArgOptionDefinition(
  24.    shortopt: String,
  25.    longopt: String,
  26.    description: String,
  27.    action: String => Unit
  28. ) extends OptionDefinition(true,shortopt, longopt, description, action, true)
  29.  
  30. class IntArgOptionDefinition(
  31.    shortopt: String,
  32.    longopt: String,
  33.    description: String,
  34.    action: Int => Unit
  35. ) extends OptionDefinition(true,shortopt, longopt, description, {a: String => action(a.toInt)}, true)
  36.  
  37. class DoubleArgOptionDefinition(
  38.    shortopt: String,
  39.    longopt: String,
  40.    description: String,
  41.    action: Double => Unit
  42. ) extends OptionDefinition(true,shortopt, longopt, description, {a: String => action(a.toDouble)}, true)
  43.  
  44. class BooleanArgOptionDefinition(
  45.    shortopt: String,
  46.    longopt: String,
  47.    description: String,
  48.    action: Boolean => Unit
  49. ) extends OptionDefinition(true,shortopt, longopt, description, { a: String =>
  50.    val boolValue = a.toLowerCase match {
  51.       case "true" => true
  52.       case "false" => false
  53.       case "yes" => true
  54.       case "no" => false
  55.       case "1" => true
  56.       case "0" => false
  57.       case _ => throw new IllegalArgumentException("Expected a string I can interpret as a boolean")
  58.    }
  59.    action(boolValue)}, true)
  60.  
  61. class FlagOptionDefinition(
  62.    shortopt: String,
  63.    longopt: String,
  64.    description: String,
  65.    action: => Unit
  66. )
  67. extends OptionDefinition(true,shortopt, longopt, description, { a: String => action }, false)
  68.  
  69.  
  70. // OptionParser is instantiated within your object,
  71. // set up by an (ordered) sequence of invocations of #on,
  72. // and then handed the command-line arguments.
  73. case class OptionParser(warnOnUnknownArgument: Boolean){
  74.    def this() = this(true)
  75.    
  76.    val options = new ListBuffer[OptionDefinition]
  77.    
  78.    // -------- Defining options ---------------
  79.    def add(option: OptionDefinition){
  80.      options += option
  81.    }
  82.    
  83.    def on(shortopt: String, longopt: String, description: String, action: String => Unit) =
  84.       add(new ArgOptionDefinition(shortopt, longopt, description, action))
  85.  
  86.    def on(shortopt: String, longopt: String, description: String, action: => Unit) =
  87.       add(new FlagOptionDefinition(shortopt, longopt, description, action))
  88.  
  89.    def separator(description: String) =
  90.       add(new SeparatorDefinition(description))
  91.  
  92.    def help(shortopt: String, longopt: String) =
  93.       add(new FlagOptionDefinition(shortopt, longopt, "Show this help", { this.showUsage; exit }))
  94.  
  95.    // we have to give these typed options separate names, because of &^@$! type erasure
  96.    def onInt(shortopt: String, longopt: String, description: String, action: Int => Unit) =
  97.       add(new IntArgOptionDefinition(shortopt, longopt, description, action))
  98.  
  99.    def onDouble(shortopt: String, longopt: String, description: String, action: Double => Unit) =
  100.       add(new DoubleArgOptionDefinition(shortopt, longopt, description, action))
  101.  
  102.    def onBoolean(shortopt: String, longopt: String, description: String, action: Boolean => Unit) =
  103.       add(new BooleanArgOptionDefinition(shortopt, longopt, description, action))
  104.    
  105.    // -------- Getting usage information ---------------
  106.    def descriptions: Seq[String] = options.map( opt => opt match {
  107.          case x if ! x.canBeInvoked => x.description
  108.          case x if x.gobbleNextArgument => x.shortopt + " <value> or " + x.longopt + " <value>: " + x.description
  109.          case _ => opt.shortopt + " or " + opt.longopt + ": " + opt.description
  110.       })
  111.    
  112.    def usage: String = descriptions.mkString("\n")
  113.    
  114.    def showUsage = Console.err.println(usage)
  115.      
  116.    // -------- Parsing ---------------
  117.    def parse(args: Seq[String]){
  118.       var i = 0
  119.       while (i < args.length) {
  120.          val arg = args(i)
  121.          val matchingOption = options.find( opt =>
  122.             opt.canBeInvoked
  123.             && (arg == opt.shortopt || arg == opt.longopt)
  124.          )
  125.          matchingOption match {
  126.             case None => if (warnOnUnknownArgument) System.err.println("WARNING: Unknown argument '" + arg + "'")
  127.             case Some(option) =>
  128.                val argToPass = if (option.gobbleNextArgument) {
  129.                   i += 1; args(i)                                      
  130.                } else
  131.                   ""
  132.                option.action.apply(argToPass)
  133.          }
  134.          i += 1
  135.       }
  136.    }
  137. }
RAW Paste Data
Top