Consolidated - originally posted on 2011/01/21.
Trying to simulate the way options are passed to unix commands via '-'.
The idea is to define a set of applicable flags and an - operator. The end result is being able to write this beauty:
rm -r -f apply "gigi.file"
Without further ado, here's the sample code:
package razie.learn.dsl.fs1
case class Flag (val c:Char)
object r extends Flag('r')
object f extends Flag('f')
class Cmd_rm (var flags:List[Flag]) {
def - (f:Flag) = { flags = f :: flags; this }
def apply (s:String) = "removing " + s
}
trait Commands {
def rm = new Cmd_rm (Nil)
}
object CmdOptions extends Application with Commands {
rm -r -f apply "gigi.file"
(((rm) - r) - f) apply "gigi.file"
rm.-(r).-(f).apply("gigi.file")
}
Try it right now here bit.ly/hb93sH.
We're limiting the flags and making this type-safe with the Flag case class. If you had more types of commands, you could limit the actual flags for each of them with custom Flag classes (like RmFlag, CpFlag etc).
The main idea is counting on scala's infix notation. The different flags accumulate in sequence and in the end, the resulting command (now with flags) is applied.
The magic of the infix notation is revealed by this equivalent form:
rm.-(r).-(f).apply("gigi.file")
Further things to consider:
This sample is available here and I wrote it while playing with a unix-looking scala shell for file management: github.com/razie/scalafs.
The power of DSL only comes alive if the users are guided via content assist, so for instance, if I type rm -
the content assist options should include all the flags applicable to rm specifically, not all options - always pay attention to that when designing DSL.
Have fun!