`
lggege
  • 浏览: 372836 次
  • 性别: Icon_minigender_1
  • 来自: 上海
社区版块
存档分类
最新评论

Groovy 与 DSL

阅读更多

 

一:DSL 概念

    指的是用于一个特定领域的语言(功能领域、业务领域)。在这个给出的概念中有 3个重点:

 

  1. 只用于一个特定领域,而非所有通用领域,比如 Java / C++就是用于通用领域,而不可被称为 DSL,同样也不可把 Groovy称为 DSL
  2. 语言,必须经过编写后才可发挥它的功能。比如:五线谱编写后成乐谱; ANT编写用于编译; SVN命令编写后可对资源库进行操作; Shell编程; SQL编程; PL-SQL编程等等。
  3. 忽略具体的运行环境(媒介),可以是纸、 XML文件、命令行、 Shell、数据库等。

二:Groovy对 DSL的支持

     Groovy不是 DSL,而是通用的编程语言。但 Groovy却对编写出一个全新的 DSL提供了良好的支持,这些支持都来自于 Groovy自身语法的特性,比如:

  1. 不需要 class定义,直接执行脚本
  2. Groovy语法的简洁
  3. Groovy提供了更多通俗易懂的方法
  4. 省略()和;等
  5. 等等

    Groovy自身不是 DSL Groovy官方已经发布了较多基于 Groovy书写的 DSL,比如 GANT GORM XMLBuilder HtmlBuilder等等。

 

三:我们的目标

     实现一种使用 Groovy语法书写、用于构建 HTML的(其实就是 HtmlBuilder)的简单 DSL,如下:

 

html {
    head {
        meta {
            
        }
    }
    body {
        table (style:'margin:5px;') {
            tr ('class':'trClass', style:'padding:5px;') {
                td {'Cell1'}
                td {'Cell2'}
                td {'Cell3'}
            }
        }
    }
}

 

     这段代码比较容易让人懂,很容易让人将 HTML与之对应起来。具体怎么实现能够通过这一段 DSL代码输出原始的 HTML呢?主要基于 Groovy的以下几个特性:

 

  1. Groovy脚本,不用定义 class
  2. Groovy invokeMethod方法
  3. 方法可不书写()
  4. 语句末尾省略;分号
  5. 不书写 return

四:代码分析

 

meta {
}

这段代码的含义为:调用 meta方法,参数为一个闭包,闭包不执行任何代码。

 

table (style:'margin:5px;') {
}

这段代码的含义为:调用 table方法,第一个参数为 Map,第二个参数为闭包。

tr ('class':'trClass', style:'padding:5px;') {
                td {'Cell1'}
                td {'Cell2'}
                td {'Cell3'}
}

这段代码的含义为:

调用 tr方法,第一个参数为 Map,第二个参数为闭包。

闭包中,调用了 3 td方法,参数都为一个闭包;闭包中直接返回了一个字符串。

 

五:代码实现

    将代码解读了以后,再结合 invokeMethod就很容易实现了,具体代码如下:

def invokeMethod(String name, args) {
    print "<${name}"
    args.each { arg ->
        if (arg instanceof Map) {
            arg.each {
                print " ${it.key} ='${it.value}' "
            }
        } else if (arg instanceof Closure) {
            print '>'
            arg.delegate = this
            def value = arg.call()
            if (value) {
                print "${value}"
            }
        }
    }

    println "</${name}>"
}

html {
    head {
        meta {
            
        }
    }
    body {
        table (style:'margin:5px;') {
            tr ('class':'trClass', style:'padding:5px;') {
                td {'Cell1'}
                td {'Cell2'}
                td {'Cell3'}
            }
        }
    }
}

 

六:运行

<html><head><meta></meta>
</head>
<body><table style ='margin:5px;' ><tr class ='trClass'  style ='padding:5px;' ><td>Cell1</td>
<td>Cell2</td>
<td>Cell3</td>
</tr>
</table>
</body>
</html>

 

七:结论

   基于Groovy自身的语法简洁和众多特性,实现一个专属的DSL还是蛮简单的。

 

分享到:
评论
5 楼 zk1878 2014-01-16  
不错的文章
4 楼 lggege 2009-12-18  
@lcllcl987 

对的,确实已被Groovy实现了,我一直以来是使用GANT的,是知晓有MarkupBuilder这个功能的。

我在这里是提出一个实现,以及DSL的自己的理解,具体DSL映射到我们可以用代码实现的话,又会是怎么一个情况。具体是为了说明这个。
3 楼 lcllcl987 2009-12-15  
老兄对html写的DSL,貌似就已经是groovy的MarkupBuilder支持的语法了:

def sw = new StringWriter()
def html = new groovy.xml.MarkupBuilder(sw)
html.html{
  head{
    title("Links")
  }
  body{
    h1("Here are my HTML bookmarks")
    table(border:1){
      tr{
        th("what")
        th("where")
      }
      tr{
        td("Groovy Articles")
        td{
          a(href:"http://ibm.com/developerworks", "DeveloperWorks")
        }
      }
    }
  }
}

def f = new File("index.html")
f.write(sw.toString())

//output:
<html>
  <head>
    <title>Links</title>
  </head>
  <body>
    <h1>Here are my HTML bookmarks</h1>
    <table border='1'>
      <tr>
        <th>what</th>
        <th>where</th>
      </tr>
      <tr>
        <td>Groovy Articles</td>
        <td>
          <a href='http://ibm.com/developerworks'>DeveloperWorks</a>
        </td>
      </tr>
    </table>
  </body>
</html>
2 楼 helian 2009-12-14  
设计DSL才是最难的啊。技术反而再其次了。不过groovy确实方便实现DSL
1 楼 lggege 2009-12-07  
这是我自己对于DSL的理解,具体请查看英文原版Wiki。

相关推荐

Global site tag (gtag.js) - Google Analytics