Created
March 15, 2012 22:41
-
-
Save bmc/2047420 to your computer and use it in GitHub Desktop.
Argot: New DSL possibility
This file contains hidden or 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
package ThinkingAboutThisApproach { | |
object Types { | |
type Converter[T] = (String, ArgSpec) => Either[String, T] | |
} | |
import Types._ | |
class ArgOption[T](val name: String, val desc: String, val cvt: Converter[T]) { | |
override def toString = "ArgOption<%s>" format name | |
override def hashCode = name.hashCode | |
override def equals(other: Any): Boolean = { | |
other match { | |
case that: ArgOption[_] => that.name == this.name | |
case _ => false | |
} | |
} | |
def get(p: ParsedParameters): Option[Either[String, T]] = { | |
p.options.get(this).map(e => e match { | |
case Right(v) => Right[String, T](v.asInstanceOf[T]) | |
case Left(msg) => Left[String, T](msg) | |
}) | |
} | |
} | |
object ArgOption { | |
def apply[T](name: String, desc: String) | |
(implicit cvt: Converter[T]): ArgOption[T] = { | |
new ArgOption[T](name, desc, cvt) | |
} | |
} | |
class Parameter[T](val name: String, val desc: String, val cvt: Converter[T]) { | |
override def toString = "Parameter<%s>" format name | |
override def hashCode = name.hashCode | |
override def equals(other: Any): Boolean = { | |
other match { | |
case that: Parameter[_] => that.name == this.name | |
case _ => false | |
} | |
} | |
def get(p: ParsedParameters): Option[Either[String, T]] = { | |
p.parameters.get(this).map(e => e match { | |
case Right(v) => Right[String, T](v.asInstanceOf[T]) | |
case Left(msg) => Left[String, T](msg) | |
}) | |
} | |
} | |
object Parameter { | |
def apply[T](name: String, desc: String) | |
(implicit cvt: Converter[T]): Parameter[T] = { | |
new Parameter[T](name, desc, cvt) | |
} | |
} | |
object Converters { | |
implicit def xToInt(s: String, a: ArgSpec): Either[String, Int] = { | |
try { | |
Right(s.toInt) | |
} | |
catch { | |
case e: NumberFormatException => | |
Left(e.getClass.getName + " " + e.getMessage) | |
} | |
} | |
implicit def xToString(s: String, a: ArgSpec): Either[String, String] = | |
Right(s) | |
} | |
import scala.collection.immutable.{ListMap, ListSet} | |
class ArgSpec(val options: Seq[ArgOption[_]], val parameters: Seq[Parameter[_]]) { | |
private val optionMap = Map(options.map(opt => opt.name -> opt): _*) | |
private val paramMap = ListMap(parameters.map(p => p.name -> p): _*) | |
override def toString = { | |
val sb = new StringBuilder | |
sb append " options=" | |
sb append options.toString | |
sb append " parameters=" | |
sb append parameters.toString | |
sb.toString | |
} | |
} | |
case class ParsedParameters(options: Map[ArgOption[_], Either[String, _]], | |
parameters: Map[Parameter[_], Either[String, _]]) { | |
} | |
class ArgParser(val program: String, val spec: ArgSpec) { | |
def parse(argv: Array[String]): ParsedParameters = { | |
val opts = scala.collection.mutable.Map.empty[ArgOption[_], Either[String, _]] | |
spec.options.foreach(o => opts += (o -> o.cvt("1.0", spec))) | |
val params = scala.collection.mutable.Map.empty[Parameter[_], Either[String, _]] | |
spec.parameters.foreach(p => params += (p -> p.cvt("1", spec))) | |
new ParsedParameters(opts.toMap, params.toMap) | |
} | |
} | |
object ArgParser { | |
def apply(prog: String, spec: ArgSpec) = { | |
new ArgParser(prog, spec) | |
} | |
} | |
object Test { | |
def main(args: Array[String]): Unit = { | |
import Converters._ | |
import java.io.File | |
val a = ArgOption[String]("-a", "string") | |
val i = ArgOption[Int]("-i", "int") | |
val f = ArgOption[Float]("-f", "float") { | |
(s, spec) => | |
try { | |
Right(s.toFloat) | |
} | |
catch { | |
case e: NumberFormatException => Left(e.getMessage) | |
} | |
} | |
val p1 = Parameter[File]("input", "input_file") { | |
(s, spec) => Right(new File(s)) | |
} | |
val p2 = Parameter[String]("foo", "foo thingie") | |
val spec = new ArgSpec(Seq(a, i, f), Seq(p1, p2)) | |
val parsed = ArgParser("test", spec).parse(args) | |
for (opt <- Seq(a, i, f)) { | |
opt.get(parsed).foreach(_ match { | |
case Right(v) => | |
println(opt.name + ": " + v + " (" + v.getClass.getName + ")") | |
case Left(msg) => | |
println(opt.name + " (ERROR) " + msg) | |
}) | |
} | |
for (p <- Seq(p1, p2)) { | |
p.get(parsed).foreach(_ match { | |
case Right(v) => | |
println(p.name + ": " + v + " (" + v.getClass.getName + ")") | |
case Left(msg) => | |
println(p.name + " (ERROR) " + msg) | |
}) | |
} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment