Permalink
Browse files

Better contains, get, and apply methods on Arguments.

  • Loading branch information...
1 parent eb3f58d commit 36a1478ec06baaffd5ef779263c21d148ea32020 @davegurnell committed Apr 14, 2012
@@ -0,0 +1,78 @@
+package tipi.core
+
+import util.parsing.input.Positional
+
+trait Argument[T] extends Positional {
+ val name: Id
+ val value: T
+ val valueManifest: Manifest[T]
+ override def toString = "%s=%s".format(name.name, value)
+}
+
+object Argument {
+ def unapply[T](arg: Argument[T]): Option[T] = {
+ Some(arg.value)
+ }
+}
+
+case class IdArgument(val name: Id, val value: Id) extends Argument[Id] {
+ val valueManifest = manifest[Id]
+}
+
+case class StringArgument(val name: Id, val value: String) extends Argument[String] {
+ val valueManifest = manifest[String]
+}
+
+case class IntArgument(val name: Id, val value: Int) extends Argument[Int] {
+ val valueManifest = manifest[Int]
+}
+
+case class DoubleArgument(val name: Id, val value: Double) extends Argument[Double] {
+ val valueManifest = manifest[Double]
+}
+
+case class BooleanArgument(val name: Id, val value: Boolean) extends Argument[Boolean] {
+ val valueManifest = manifest[Boolean]
+}
+
+case class UnitArgument(val name: Id) extends Argument[Unit] {
+ val value = ()
+ val valueManifest = manifest[Unit]
+ override def toString = name.name
+}
+
+case class ArgumentNotFoundException(val id: Id) extends Exception("Argument not found: " + id.name)
+
+case class ArgumentTypeException(val id: Id, val expected: String) extends Exception("Argument is not of type %s: %s".format(expected, id.name))
+
+case class Arguments(arguments: List[Argument[_]]) {
+ def contains[T : Manifest](name: Id): Boolean = {
+ get[T](name).isDefined
+ }
+
+ def apply[T : Manifest](name: Id): T = {
+ arguments.find(_.name == name) match {
+ case Some(arg) =>
+ if(arg.valueManifest <:< manifest[T]) {
+ arg.value.asInstanceOf[T]
+ } else {
+ throw new ArgumentTypeException(name, manifest[T].erasure.getSimpleName)
+ }
+ case _ =>
+ throw new ArgumentNotFoundException(name)
+ }
+ }
+
+ def get[T : Manifest](name: Id): Option[T] = {
+ arguments.find(_.name == name).flatMap {
+ case arg: Argument[_] if arg.valueManifest <:< manifest[T] => Some(arg.value.asInstanceOf[T])
+ case _ => None
+ }
+ }
+
+ def toList = arguments
+}
+
+object Arguments {
+ val Empty = Arguments(Nil)
+}
@@ -7,57 +7,15 @@ trait Doc extends Positional
case class Block(val name: Id, val args: Arguments = Arguments.Empty, val body: Range = Range.Empty) extends Doc {
override def toString = "Block(%s,Args(%s),%s)".format(name.name, args.toList.mkString(", "), body)
}
+
case class Range(val children: List[Doc]) extends Doc {
override def toString = "Range(%s)".format(children.mkString(", "))
}
+
object Range {
val Empty = Range(Nil)
}
-case class Text(val value: String) extends Doc
-
-trait Argument[T] extends Positional {
- val name: Id
- val value: T
- override def toString = "%s=%s".format(name.name, value)
-}
-case class IdArgument(val name: Id, val value: Id) extends Argument[Id]
-case class StringArgument(val name: Id, val value: String) extends Argument[String]
-case class IntArgument(val name: Id, val value: Int) extends Argument[Int]
-case class DoubleArgument(val name: Id, val value: Double) extends Argument[Double]
-case class BooleanArgument(val name: Id, val value: Boolean) extends Argument[Boolean]
-case class UnitArgument(val name: Id) extends Argument[Unit] {
- val value = ()
- override def toString = name.name
-}
-
-object Argument {
- def unapply[T](arg: Argument[T]): Option[T] = {
- Some(arg.value)
- }
-}
-case class Arguments(arguments: List[Argument[_]]) {
- def get[T : Manifest](name: Id): Option[T] = {
- arguments.find(_.name == name).flatMap {
- case arg: Argument[_] if ClassManifest.fromClass(arg.value.getClass) >:> manifest[T] => Some(arg.value.asInstanceOf[T])
- case _ => None
- }
- }
-
- def contains[T : Manifest](name: Id): Boolean = {
- get[T](name).isDefined
- }
-
- def toList = arguments
-}
-
-object Arguments {
- val Empty = Arguments(Nil)
-}
-
-trait Tag extends Positional { val name: Id }
-case class SimpleTag(val name: Id, val args: List[Argument[_]]) extends Tag
-case class OpenTag(val name: Id, val args: List[Argument[_]]) extends Tag
-case class CloseTag(val name: Id) extends Tag
+case class Text(val value: String) extends Doc
case class Id(val name: String)
@@ -3,12 +3,21 @@ package tipi.core
import scala.util.parsing.combinator._
import scala.util.parsing.input._
+object Parser {
+ trait Tag extends Positional { val name: Id }
+ case class SimpleTag(val name: Id, val args: List[Argument[_]]) extends Tag
+ case class OpenTag(val name: Id, val args: List[Argument[_]]) extends Tag
+ case class CloseTag(val name: Id) extends Tag
+}
+
case class Parser(
val simpleTagStart: String = "{{",
val simpleTagEnd: String = "}}",
val blockStart: String = "#",
val blockEnd: String = "/"
) extends RegexParsers {
+ import tipi.core.Parser._
+
override val skipWhitespace = false
def openBlockStart = simpleTagStart + blockStart
@@ -0,0 +1,56 @@
+package tipi.core
+
+import org.scalatest._
+
+class ArgumentSuite extends FunSuite with Implicits {
+ val args = Arguments(List(
+ UnitArgument("unit"),
+ StringArgument("string", "foo"),
+ IntArgument("int", 123)
+ ))
+
+ test("contains") {
+ assert(args.contains[Any]("unit") === true)
+ assert(args.contains[Unit]("unit") === true)
+ assert(args.contains[String]("unit") === false)
+ assert(args.contains[Int]("unit") === false)
+ assert(args.contains[Any]("string") === true)
+ assert(args.contains[Unit]("string") === false)
+ assert(args.contains[String]("string") === true)
+ assert(args.contains[Int]("string") === false)
+ assert(args.contains[Any]("int") === true)
+ assert(args.contains[Unit]("int") === false)
+ assert(args.contains[String]("int") === false)
+ assert(args.contains[Int]("int") === true)
+ assert(args.contains[Any]("missing") === false)
+ }
+
+ test("apply") {
+ assert(args[Unit]("unit") === ())
+ intercept[ArgumentTypeException]{ args[String]("unit") }
+ intercept[ArgumentTypeException]{ args[Int]("unit") }
+ intercept[ArgumentTypeException]{ args[Unit]("string") }
+ assert(args[String]("string") === "foo")
+ intercept[ArgumentTypeException]{ args[Int]("string") }
+ intercept[ArgumentTypeException]{ args[Unit]("int") }
+ intercept[ArgumentTypeException]{ args[String]("int") }
+ assert(args[Int]("int") === 123)
+ intercept[ArgumentNotFoundException]{ args[Any]("missing") }
+ }
+
+ test("get") {
+ assert(args.get[Any]("unit") === Some(()))
+ assert(args.get[Unit]("unit") === Some(()))
+ assert(args.get[String]("unit") === None)
+ assert(args.get[Int]("unit") === None)
+ assert(args.get[Any]("string") === Some("foo"))
+ assert(args.get[Unit]("string") === None)
+ assert(args.get[String]("string") === Some("foo"))
+ assert(args.get[Int]("string") === None)
+ assert(args.get[Any]("int") === Some(123))
+ assert(args.get[Unit]("int") === None)
+ assert(args.get[String]("int") === None)
+ assert(args.get[Int]("int") === Some(123))
+ assert(args.get[Any]("missing") === None)
+ }
+}
@@ -4,6 +4,8 @@ import org.scalatest._
import scala.util.parsing.combinator._
class ParserSuite extends FunSuite {
+ import tipi.core.Parser._
+
trait ParserTest {
self: RegexParsers =>
def runRule[T](rule: Parser[T], input: String): Option[T] = {

0 comments on commit 36a1478

Please sign in to comment.