Created
May 22, 2014 05:14
-
-
Save DavidGamba/b3287d40b019e498982c to your computer and use it in GitHub Desktop.
Scala OptionParser that doesn't worry about descriptions (we write man pages for that)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
def main(args: Array[String]) { | |
// Required positional arguments by key in options | |
val required = List('arg1, 'arg2) | |
// Options with value | |
val optional = Map("--option|-o" -> 'option, "-t|--test" -> 'test) | |
// Flags | |
val flags = Map("--flag1|-f" -> 'flag1, "--flag2" -> 'flag2) | |
// Default options that are passed in | |
var defaultOptions = Map[Symbol, String]( 'test -> "hello world!") | |
// Parse options based on the command line args | |
val options = parseOptions(args.toList, required, optional, flags, defaultOptions) | |
println(options) | |
} | |
implicit class OptionMapImprovements(val m: Map[String, Symbol]) { | |
def match_key(opt: String): String = { | |
m.keys.find(_.matches(s""".*$opt(\\|.*)?""")).getOrElse("") | |
} | |
def match_get(opt: String): Option[Symbol] = { | |
m.get(m.match_key(opt)) | |
} | |
def match_apply(opt: String): Symbol = { | |
m(m.match_key(opt)) | |
} | |
} | |
type OptionMap = Map[Symbol, String] | |
type OptionMapBuilder = Map[String, Symbol] | |
def parseOptions(args: List[String], | |
required: List[Symbol], | |
optional: OptionMapBuilder, | |
flags: OptionMapBuilder, | |
options: OptionMap = Map[Symbol, String](), | |
strict: Boolean = false | |
): OptionMap = { | |
args match { | |
// Empty list | |
case Nil => options | |
// Options with values | |
case key :: value :: tail if optional.match_get(key) != None => | |
parseOptions(tail, required, optional, flags, options ++ Map(optional.match_apply(key) -> value)) | |
// Flags | |
case key :: tail if flags.match_get(key) != None => | |
parseOptions(tail, required, optional, flags, options ++ Map(flags.match_apply(key) -> "true")) | |
// Positional arguments | |
case value :: tail if required != Nil => | |
parseOptions(tail, required.tail, optional, flags, options ++ Map(required.head -> value)) | |
// Generate symbols out of remaining arguments | |
case value :: tail if !strict => parseOptions(tail, required, optional, flags, options ++ Map(Symbol(value) -> value)) | |
case _ if strict => | |
printf("Unknown argument(s): %s\n", args.mkString(", ")) | |
sys.exit(1) | |
} | |
} |
Hi David,
Thanks very much for your contribution. In parseOptions
the recursive call to itself must also pass the strict parameter:
def parseOptions(args: List[String],
required: List[Symbol],
optional: OptionMapBuilder,
flags: OptionMapBuilder,
defaultOptions: OptionMap = Map[Symbol, String](),
strict: Boolean = false
): OptionMap = {
args match {
// Empty list
case Nil => defaultOptions
// Options with values
case key :: value :: tail if optional.match_get(key).isDefined =>
parseOptions(tail, required, optional, flags, defaultOptions ++ Map(optional.match_apply(key) -> value), strict)
// Flags
case key :: tail if flags.match_get(key).isDefined =>
parseOptions(tail, required, optional, flags, defaultOptions ++ Map(flags.match_apply(key) -> "true"), strict)
// Positional arguments
case value :: tail if required != Nil =>
parseOptions(tail, required.tail, optional, flags, defaultOptions ++ Map(required.head -> value), strict)
// Generate symbols out of remaining arguments
case value :: tail if !strict => parseOptions(tail, required, optional, flags, defaultOptions ++ Map(Symbol(value) -> value), strict)
case _ if strict =>
printf("UNKNOWN ARGUMENT(s): %s\n", args.mkString(", "))
sys.exit(1)
}
}
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Based on this: http://stackoverflow.com/a/19056645/1601989
Changes:
-t|--test
.