Reputation: 1009
I want to write an API that allows me to easily create hierarchical keys like
/ foo / bar / baz
For this I've created the following classes:
sealed trait Key {
def path: String
def /(key: String): Node = Node(this, key)
}
case object Root extends Key {
override def path: String = ""
}
final case class Node(parent: Key, key: String) extends Key {
override def path: String = s"${parent.path}/$key"
}
And it works perfectly fine:
Root / "foo" / "bar"
Now, I also want to be able to include 'placeholders' like so:
Root / "foo" / %
And this shall then return something, that when a string gets applied returns a Key
object with the given value replaced, i.e.
(Root / "foo" / %)("bar") == Root / "foo" / "bar"
Keep in mind that this should work on n-levels, like so:
Root / % / "foo" / % / "bar"
Upvotes: 0
Views: 34
Reputation: 5315
This is probably not very efficient, but it does what you asked for.
Note that, answering my own comment, I decided that
(Root / % / "foo" / % / "bar")("baz") == (Root / % / "foo" / "baz" / "bar")
but there's not much to change to have a different outcome.
object % // only for nicer API
trait Slashable[T <: Slashable[T]] {
def /(key: String): T
def /(p: %.type): PlaceHeld[T] = PlaceHeld[T](str => /(str))
}
case object Root extends Key {
override def path: String = ""
}
sealed trait Key extends Slashable[Key] {
def path: String
def /(key: String): Node = Node(this, key)
}
final case class Node(parent: Key, key: String) extends Key {
override def path: String = s"${parent.path}/$key"
}
case class PlaceHeld[T <: Slashable[T]](replace: String => T) extends Slashable[PlaceHeld[T]]{
def /(key: String) = PlaceHeld(str => replace(str)./(key))
def apply(key: String) = replace(key)
}
EDIT
You might want to replace your base type (without placeholders) by a simple (wrapped) Seq
:
case class Key(pathSeq: Seq[String]) extends Slashable[Key] {
def path = pathSeq.mkString("/")
def /(key: String) = Key(pathSeq :+ key)
}
object Root extends Slashable[Root] {
def path = "" //this is because we cannot do
def /(key: String) = Key(Seq(key)) //Root extends Key(Seq())
}
Upvotes: 2