Skip to content

Commit

Permalink
implemented option that does not have short option
Browse files Browse the repository at this point in the history
  • Loading branch information
eed3si9n committed Sep 3, 2010
1 parent 8931013 commit 9ac4723
Show file tree
Hide file tree
Showing 3 changed files with 111 additions and 45 deletions.
9 changes: 4 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ Create an *OptionParser* and customise it with the options you need, passing in
val parser = new OptionParser("scopt") {
intOpt("f", "foo", "foo is an integer property", {v: Int => config.foo = v})
opt("o", "output", "<file>", "output is a string property", {v: String => config.bar = v})
booleanOpt("x", "xyz", "xyz is a boolean property", {v: Boolean => config.xyz = v})
booleanOpt("xyz", "xyz is a boolean property", {v: Boolean => config.xyz = v})
keyValueOpt("l", "lib", "<libname>", "<filename>", "load library <libname>",
{(key: String, value: String) => { config.libname = key; config.libfile = value } })
arg("<singlefile>", "<singlefile> is an argument", {v: String => config.whatnot = v})
Expand All @@ -39,7 +39,7 @@ The above generates the following usage text:
foo is an integer property
-o <file> | --output <file>
output is a string property
-x <value> | --xyz <value>
--xyz <value>
xyz is a boolean property
-l:<libname>=<filename> | --lib:<libname>=<filename>
load library <libname>
Expand All @@ -61,11 +61,10 @@ Changes
-------

* added -x:key=value option
* updated usage text style
* updated sbt build to build against 2.8.0.Beta1
* updated usage text style
* added maven and sbt builds
* added ScalaTest test cases
* added arguments which then are displayed in help
* minor refactoring of names; opt and arg for options and args
* updated sbt and maven to build against Scala 2.8.0

* added option that does not have short option
138 changes: 102 additions & 36 deletions src/main/scala/org/github/scopt/Options.scala
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import collection.mutable.ListBuffer
// usually mutating a var.
case class OptionDefinition(
canBeInvoked: Boolean,
shortopt: String,
shortopt: Option[String],
longopt: String,
keyName: String,
valueName: String,
Expand Down Expand Up @@ -37,7 +37,7 @@ class Argument(
}

class ArgOptionDefinition(
shortopt: String,
shortopt: Option[String],
longopt: String,
valueName: String,
description: String,
Expand All @@ -46,7 +46,7 @@ class ArgOptionDefinition(
description, action, true, false)

class IntArgOptionDefinition(
shortopt: String,
shortopt: Option[String],
longopt: String,
valueName: String,
description: String,
Expand All @@ -55,7 +55,7 @@ class IntArgOptionDefinition(
description, {a: String => action(a.toInt)}, true, false)

class DoubleArgOptionDefinition(
shortopt: String,
shortopt: Option[String],
longopt: String,
valueName: String,
description: String,
Expand All @@ -64,7 +64,7 @@ class DoubleArgOptionDefinition(
description, {a: String => action(a.toDouble)}, true, false)

class BooleanArgOptionDefinition(
shortopt: String,
shortopt: Option[String],
longopt: String,
valueName: String,
description: String,
Expand All @@ -85,7 +85,7 @@ class BooleanArgOptionDefinition(
true, false)

class KeyValueArgOptionDefinition(
shortopt: String,
shortopt: Option[String],
longopt: String,
keyName: String,
valueName: String,
Expand All @@ -100,7 +100,7 @@ class KeyValueArgOptionDefinition(
false, true)

class KeyIntValueArgOptionDefinition(
shortopt: String,
shortopt: Option[String],
longopt: String,
keyName: String,
valueName: String,
Expand All @@ -115,7 +115,7 @@ class KeyIntValueArgOptionDefinition(
false, true)

class KeyDoubleValueArgOptionDefinition(
shortopt: String,
shortopt: Option[String],
longopt: String,
keyName: String,
valueName: String,
Expand All @@ -130,7 +130,7 @@ class KeyDoubleValueArgOptionDefinition(
false, true)

class KeyBooleanValueArgOptionDefinition(
shortopt: String,
shortopt: Option[String],
longopt: String,
keyName: String,
valueName: String,
Expand All @@ -156,7 +156,7 @@ class KeyBooleanValueArgOptionDefinition(
false, true)

class FlagOptionDefinition(
shortopt: String,
shortopt: Option[String],
longopt: String,
description: String,
action: => Unit
Expand Down Expand Up @@ -201,68 +201,130 @@ case class OptionParser(

// setup options (which require -char or --string to invoke
def opt(shortopt: String, longopt: String, description: String, action: String => Unit) =
add(new ArgOptionDefinition(shortopt, longopt, defaultValueName, description, action))
add(new ArgOptionDefinition(Some(shortopt), longopt, defaultValueName, description, action))

def opt(longopt: String, description: String, action: String => Unit) =
add(new ArgOptionDefinition(None, longopt, defaultValueName, description, action))

def opt(shortopt: String, longopt: String, valueName: String,
description: String, action: String => Unit) =
add(new ArgOptionDefinition(Some(shortopt), longopt, valueName, description, action))

def opt(shortopt: Option[String], longopt: String, valueName: String,
description: String, action: String => Unit) =
add(new ArgOptionDefinition(shortopt, longopt, valueName, description, action))

def opt(shortopt: String, longopt: String, description: String, action: => Unit) =
add(new FlagOptionDefinition(shortopt, longopt, description, action))
add(new FlagOptionDefinition(Some(shortopt), longopt, description, action))

def opt(longopt: String, description: String, action: => Unit) =
add(new FlagOptionDefinition(None, longopt, description, action))

// we have to give these typed options separate names, because of &^@$! type erasure
def intOpt(shortopt: String, longopt: String, description: String, action: Int => Unit) =
add(new IntArgOptionDefinition(shortopt, longopt, defaultValueName, description, action))
add(new IntArgOptionDefinition(Some(shortopt), longopt, defaultValueName, description, action))

def intOpt(longopt: String, description: String, action: Int => Unit) =
add(new IntArgOptionDefinition(None, longopt, defaultValueName, description, action))

def intOpt(shortopt: String, longopt: String, valueName: String,
description: String, action: Int => Unit) =
add(new IntArgOptionDefinition(Some(shortopt), longopt, valueName, description, action))

def intOpt(shortopt: Option[String], longopt: String, valueName: String,
description: String, action: Int => Unit) =
add(new IntArgOptionDefinition(shortopt, longopt, valueName, description, action))

def doubleOpt(shortopt: String, longopt: String, description: String, action: Double => Unit) =
add(new DoubleArgOptionDefinition(shortopt, longopt, defaultValueName, description, action))
add(new DoubleArgOptionDefinition(Some(shortopt), longopt, defaultValueName, description, action))

def doubleOpt(longopt: String, description: String, action: Double => Unit) =
add(new DoubleArgOptionDefinition(None, longopt, defaultValueName, description, action))

def doubleOpt(shortopt: String, longopt: String, valueName: String,
description: String, action: Double => Unit) =
add(new DoubleArgOptionDefinition(Some(shortopt), longopt, valueName, description, action))

def doubleOpt(shortopt: Option[String], longopt: String, valueName: String,
description: String, action: Double => Unit) =
add(new DoubleArgOptionDefinition(shortopt, longopt, valueName, description, action))

def booleanOpt(shortopt: String, longopt: String, description: String, action: Boolean => Unit) =
add(new BooleanArgOptionDefinition(shortopt, longopt, defaultValueName, description, action))
add(new BooleanArgOptionDefinition(Some(shortopt), longopt, defaultValueName, description, action))

def booleanOpt(longopt: String, description: String, action: Boolean => Unit) =
add(new BooleanArgOptionDefinition(None, longopt, defaultValueName, description, action))

def booleanOpt(shortopt: String, longopt: String, valueName: String,
description: String, action: Boolean => Unit) =
add(new BooleanArgOptionDefinition(shortopt, longopt, valueName, description, action))
add(new BooleanArgOptionDefinition(Some(shortopt), longopt, valueName, description, action))

def booleanOpt(shortopt: Option[String], longopt: String, valueName: String,
description: String, action: Boolean => Unit) =
add(new BooleanArgOptionDefinition(shortopt, longopt, valueName, description, action))

def keyValueOpt(shortopt: String, longopt: String, description: String, action: (String, String) => Unit) =
add(new KeyValueArgOptionDefinition(shortopt, longopt, defaultKeyName, defaultValueName, description, action))

add(new KeyValueArgOptionDefinition(Some(shortopt), longopt, defaultKeyName, defaultValueName, description, action))

def keyValueOpt(longopt: String, description: String, action: (String, String) => Unit) =
add(new KeyValueArgOptionDefinition(None, longopt, defaultKeyName, defaultValueName, description, action))

def keyValueOpt(shortopt: String, longopt: String, keyName: String, valueName: String,
description: String, action: (String, String) => Unit) =
add(new KeyValueArgOptionDefinition(shortopt, longopt, keyName, valueName, description, action))
add(new KeyValueArgOptionDefinition(Some(shortopt), longopt, keyName, valueName, description, action))

def keyValueOpt(shortopt: Option[String], longopt: String, keyName: String, valueName: String,
description: String, action: (String, String) => Unit) =
add(new KeyValueArgOptionDefinition(shortopt, longopt, keyName, valueName, description, action))

def keyIntValueOpt(shortopt: String, longopt: String, description: String, action: (String, Int) => Unit) =
add(new KeyIntValueArgOptionDefinition(shortopt, longopt, defaultKeyName, defaultValueName, description, action))
add(new KeyIntValueArgOptionDefinition(Some(shortopt), longopt, defaultKeyName, defaultValueName, description, action))

def keyIntValueOpt(longopt: String, description: String, action: (String, Int) => Unit) =
add(new KeyIntValueArgOptionDefinition(None, longopt, defaultKeyName, defaultValueName, description, action))

def keyIntValueOpt(shortopt: String, longopt: String, keyName: String, valueName: String,
description: String, action: (String, Int) => Unit) =
add(new KeyIntValueArgOptionDefinition(shortopt, longopt, keyName, valueName, description, action))
add(new KeyIntValueArgOptionDefinition(Some(shortopt), longopt, keyName, valueName, description, action))

def keyIntValueOpt(shortopt: Option[String], longopt: String, keyName: String, valueName: String,
description: String, action: (String, Int) => Unit) =
add(new KeyIntValueArgOptionDefinition(shortopt, longopt, keyName, valueName, description, action))

def keyDoubleValueOpt(shortopt: String, longopt: String, description: String, action: (String, Double) => Unit) =
add(new KeyDoubleValueArgOptionDefinition(shortopt, longopt, defaultKeyName, defaultValueName, description, action))
add(new KeyDoubleValueArgOptionDefinition(Some(shortopt), longopt, defaultKeyName, defaultValueName, description, action))

def keyDoubleValueOpt(longopt: String, description: String, action: (String, Double) => Unit) =
add(new KeyDoubleValueArgOptionDefinition(None, longopt, defaultKeyName, defaultValueName, description, action))

def keyDoubleValueOpt(shortopt: String, longopt: String, keyName: String, valueName: String,
description: String, action: (String, Double) => Unit) =
add(new KeyDoubleValueArgOptionDefinition(Some(shortopt), longopt, keyName, valueName, description, action))

def keyDoubleValueOpt(shortopt: Option[String], longopt: String, keyName: String, valueName: String,
description: String, action: (String, Double) => Unit) =
add(new KeyDoubleValueArgOptionDefinition(shortopt, longopt, keyName, valueName, description, action))

def keyBooleanValueOpt(shortopt: String, longopt: String, description: String, action: (String, Boolean) => Unit) =
add(new KeyBooleanValueArgOptionDefinition(shortopt, longopt, defaultKeyName, defaultValueName, description, action))
add(new KeyBooleanValueArgOptionDefinition(Some(shortopt), longopt, defaultKeyName, defaultValueName, description, action))

def keyBooleanValueOpt(longopt: String, description: String, action: (String, Boolean) => Unit) =
add(new KeyBooleanValueArgOptionDefinition(None, longopt, defaultKeyName, defaultValueName, description, action))

def keyBooleanValueOpt(shortopt: String, longopt: String, keyName: String, valueName: String,
description: String, action: (String, Boolean) => Unit) =
add(new KeyBooleanValueArgOptionDefinition(Some(shortopt), longopt, keyName, valueName, description, action))

def keyBooleanValueOpt(shortopt: Option[String], longopt: String, keyName: String, valueName: String,
description: String, action: (String, Boolean) => Unit) =
add(new KeyBooleanValueArgOptionDefinition(shortopt, longopt, keyName, valueName, description, action))

def help(shortopt: String, longopt: String, description: String = "show this help message") =
add(new FlagOptionDefinition(shortopt, longopt, description, {this.showUsage; exit}))
add(new FlagOptionDefinition(Some(shortopt), longopt, description, {this.showUsage; exit}))

def help(shortopt: Option[String], longopt: String, description: String) =
add(new FlagOptionDefinition(shortopt, longopt, description, {this.showUsage; exit}))

def separator(description: String) =
add(new SeparatorDefinition(description))

Expand All @@ -279,13 +341,13 @@ case class OptionParser(
//case x: Argument => x.longopt + " :" + NLTB + opt.description
case x if !x.canBeInvoked => x.description
case x if x.keyValueArgument =>
"-" + x.shortopt + ":" + x.keyName + "=" + x.valueName + " | " +
(x.shortopt map { o => "-" + o + ":" + x.keyName + "=" + x.valueName + " | " } getOrElse { "" }) +
"--" + x.longopt + ":" + x.keyName + "=" + x.valueName + NLTB + x.description
case x if x.gobbleNextArgument =>
"-" + x.shortopt + " " + x.valueName + " | " +
(x.shortopt map { o => "-" + o + " " + x.valueName + " | " } getOrElse { "" }) +
"--" + x.longopt + " " + x.valueName + NLTB + x.description
case _ =>
"-" + opt.shortopt + " | " +
(opt.shortopt map { o => "-" + o + " | " } getOrElse { "" }) +
"--" + opt.longopt + NLTB + opt.description
}) ++= (argList match {
case Some(x: Argument) => List(x.valueName + NLTB + x.description)
Expand Down Expand Up @@ -336,9 +398,11 @@ case class OptionParser(
val matchingOption = options.find(opt =>
opt.canBeInvoked &&
((!opt.keyValueArgument &&
(arg == "-" + opt.shortopt || arg == "--" + opt.longopt)) ||
(arg == "--" + opt.longopt ||
(opt.shortopt map { o => arg == "-" + o } getOrElse { false }))) ||
(opt.keyValueArgument &&
(arg.startsWith("-" + opt.shortopt + ":") || arg.startsWith("--" + opt.longopt + ":"))))
(arg.startsWith("--" + opt.longopt + ":") ||
(opt.shortopt map { o => arg.startsWith("-" + o + ":") } getOrElse { false }))))
)

matchingOption match {
Expand Down Expand Up @@ -371,9 +435,11 @@ case class OptionParser(
val argToPass = if (option.gobbleNextArgument) {
i += 1;
args(i)
} else if (option.keyValueArgument && arg.startsWith("-" + option.shortopt + ":")) {
arg.drop(("-" + option.shortopt + ":").length)
} else if (option.keyValueArgument && arg.startsWith("--" + option.longopt + ":")) {
} else if (option.keyValueArgument &&
(option.shortopt map { o => arg.startsWith("-" + o + ":") } getOrElse { false })) {
arg.drop(("-" + option.shortopt.get + ":").length)
} else if (option.keyValueArgument &&
arg.startsWith("--" + option.longopt + ":")) {
arg.drop(("--" + option.longopt + ":").length)
} else
""
Expand Down
9 changes: 5 additions & 4 deletions src/test/scala/org/github/scopt/OptionsTest.scala
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,10 @@ class OptionsTest extends FunSuite {
val parser1 = new OptionParser("scopt") {
intOpt("f", "foo", "foo is an integer property", {v: Int => config.foo = v})
opt("o", "output", "<file>", "output is a string property", {v: String => config.bar = v})
booleanOpt("x", "xyz", "xyz is a boolean property", {v: Boolean => config.xyz = v})
booleanOpt("xyz", "xyz is a boolean property", {v: Boolean => config.xyz = v})
keyValueOpt("l", "lib", "<libname>", "<filename>", "load library <libname>",
{(key: String, value: String) => { config.libname = key; config.libfile = value } })
keyIntValueOpt("m", "max", "<libname>", "<max>", "maximum count for <libname>",
keyIntValueOpt(None, "max", "<libname>", "<max>", "maximum count for <libname>",
{(key: String, value: Int) => { config.maxlibname = key; config.maxcount = value } })
arg("<file>", "some argument", {v: String => config.whatnot = v})
}
Expand All @@ -42,7 +42,8 @@ class OptionsTest extends FunSuite {
validArguments(parser1, Config(foo = 22, bar = "beer", whatnot = "drink"), "-o", "beer", "-f", "22", "drink")
validArguments(parser1, Config(foo = 22, bar = "beer", whatnot = "drink"), "-f", "22", "--output", "beer", "drink")
validArguments(parser1, Config(libname = "key", libfile = "value", whatnot = "drink"), "--lib:key=value", "drink")
validArguments(parser1, Config(maxlibname = "key", maxcount = 5, whatnot = "drink"), "-m:key=5", "drink")
validArguments(parser1, Config(maxlibname = "key", maxcount = 5, whatnot = "drink"), "--max:key=5", "drink")
validArguments(parser1, Config(xyz = true, whatnot = "drink"), "--xyz", "true", "drink")
}

test("invalid arguments fail") {
Expand All @@ -58,7 +59,7 @@ class OptionsTest extends FunSuite {
}

test("bad booleans fail to parse nicely") {
invalidArguments(parser1, "-x", "shouldBeBoolean", "blah")
invalidArguments(parser1, "--xyz", "shouldBeBoolean", "blah")
}

val parser2 = new OptionParser("scopt") {
Expand Down

0 comments on commit 9ac4723

Please sign in to comment.