Open zhongl opened 11 years ago
我在yascli设计了编写命令行应用的DSL, 如:
import com.github.zhongl.yascli._
import com.github.zhongl.yascli.Converters._
object Example extends Command(name = "example", description = "a example of single command") with Application {
private val flag0 = flag("-f" :: "--flag" :: Nil, "enable flag")
private val singleValue = option[String]("--single-value" :: Nil, "set single value", "value")
private val param = parameter[String]("param", "set param")
override def run() {
if (flag0()) println("enable flag0.")
println(singleValue())
println(param())
}
}
最近想要改进, 但感觉自己的想象力有点枯竭, 故拿出来献丑, 求灵感!
我没写过DSL方面的东西,也是从PIS 书中了解到的 parser combinator。 发现scala语言已经内置了,并且提供的接口确实很方便,只要把语义规则想明白了,实现起来非常简洁,背后的算法我完全不用关注(除非要考虑性能)。这点最初很让我震惊,原本以为要很复杂的事情几行代码就可以解决了。
另外也感觉内置的这个parser combinator有些“鸡肋”,主要可能是因为性能问题,比如cobar里用于解析sql的parser,或fastjson里的parser都做了很大优化,稍微要求一点性能的情况下都不太适用。不过这根dsl无关,跑题了。
@hongjiang 说到Parser, 这里我推荐parboiled, 据说性能要优于内置的Parser. 不过我倾向于使用Internal DSL, 几乎没有使用它的场景.
内部DSL的流程控制该怎么实现呢,纠结
我最近写的一个 CSS Selector 的 DSL: https://github.com/henix/ssoup
jsoup 本来是外部 DSL ,即它需要解析一个字符串:
element.select("body > div#page > div#nav");
在看了 jsoup 的代码之后,我发现它实现 selector 效率偏低,每个 selector 都要遍历整个 DOM 树。故自己实现一个内部 DSL,一方面写起来容易,另一方面只访问部分 DOM 节点,效率提升。
val nav = select(body > "div#page" > "div#nav").headOption
这里的 >
是运算符。
另外还写过一个中文单元测试的 DSL http://www.douban.com/note/432612442/ ,其实就是把 ScalaTest 的 it should ... in ... 翻译成中文了。。。
赞啊
最早结识DSL, 还是因为看了Martin Flower的一篇文章叫FluentInterface, 它真正让我明白原来代码也可以这样美的.
以至于后来我爱上写单元测试, 很大程度要归功于mockito在DSL应用上的如火纯青.
在自己尝试着用Java写DSL的时候, 那永远摆脱不掉的
.
和()
, 总让我纠结不已, 当然, 这只是个人洁癖而已.Scala在实现DSL是很有优势的, 这在combinator.Parsers中已表明了这点, 而且在Programming Scala一书中, 作者专门用一个章节来讨论.
值得强调的是, 阻碍我们设计实现DSL的是我们自己的想象力, 而不应该是一门语言的表现力.
在此引出本文的目的: 大家来聊聊你用Scala写过的哪些DSL?