合并 JDK 与 Groovy 的 API 文档

对于 Groovy 用户而言,每次查找 JavaDoc 都很麻烦,因为 Groovy  本身带了三种不同的 JavaDoc,分别在三个目录下,再加上原本的 JDK API,每次都要在四个文档中都搜索一遍。为了解决这个问题,这里提供一个脚本来对这四个文档进行合并。

大体的使用场景如下:比如要查 java.util.Date 这个类,  那么在搜索栏里输入 Date,则列表中出现所有类名为 Date 的类(还包括 java.sql.Date,如果勾选了 Fuzzy 选项,那么所有以 Date 开头的类都会列出)。在列表中选择 java.util.Date,点击按钮,则系统将自动打开合并后的页面。在这里,我们可以从页面顶部的目录看到 Date 类在 JDK 和 Groovy-JDK 中均有出现。

   1: #!/bin/env groovy
   2: import groovy.swing.*
   3: import javax.swing.*
   4:  
   5: class JavaDoc {
   6:     // 获取环境变量
   7:     // 使用环境变量来定位文档目录是根据我的文档目录位置而决定的
   8:     // 对于其它情况,可以简单的手动修改 folders 的内容
   9:     static env(name) { System.getenv().get(name) } 
  10:     static final SEP = File.separator
  11:     static folders = ['J2SE API Specification': "${env('JAVA_HOME')}${SEP}docs${SEP}api"]
  12:     static String css = new File("${folders.'J2SE API Specification'}${SEP}stylesheet.css").toURL()
  13:     static String pic = new File("${folders.'J2SE API Specification'}${SEP}/resources/inherit.gif").toURL()
  14:     static {        
  15:         ['JavaDoc for Java classes': 'api',
  16:          'GroovyDoc for Groovy and Java classes': 'gapi',
  17:          'Groovy JDK API Specification': 'groovy-jdk'].each { folder, path ->
  18:             folders.put(folder, "${env('GROOVY_HOME')}${SEP}html${SEP}$path")
  19:         }        
  20:         folders.each { type, folder ->
  21:             new File(folder).eachFileRecurse { file ->
  22:                 if(file.name.matches(~/[A-Z].*/.html/) && !file.parent.endsWith('class-use')) {
  23:                     docs << new JavaDoc(type, file)
  24:                 }
  25:             }        
  26:         }
  27:     }    
  28:       
  29:     static docs = [] //脚本将一次性扫描所有文件,并将结果存入该列表  
  30:           
  31:     // 根据SimpleName查找并返回其(完整)类名列表
  32:     // fuzzy: 是否模糊查找(返回所有keyword开头的类)
  33:     // 注意这里闭包的用法很帅
  34:     static String[] search(String keyword, fuzzy = false) {
  35:         def cls = fuzzy ? { it.startsWith(keyword) } : { it == keyword }         
  36:         docs.findAll { cls(it.simpleName) }.collect { it.name }.unique()
  37:     } 
  38:     
  39:     static final HEAD = """text/css" HREF="$css" TITLE="Style">""
  40:     " TYPE="
  41:     ">">${it.type}"
  42:     "
  43:     static final END = '' 
  44:     
  45:     static String getHtml(String name) {
  46:         def docs = docs.findAll { it.name == name }
  47:         if(!docs) return ''
  48:         final tableOfContents = docs.collect { """"" }.join('
'
)
  49:         "$HEAD$tableOfContents${docs.collect{ it.classData }.join('/n')}$END"    
  50:     } 
  51:     
  52:     final type, file, name, simpleName 
  53:     def JavaDoc(type, file) {    
  54:         this.type = type
  55:         this.file = file
  56:         simpleName = file.name - '.html'
  57:         name = (file.absolutePath - "${folders.get(type)}$SEP" - '.html').replace(SEP, '.')
  58:     }
  59:     
  60:     String getTypeId() { type.replaceAll(' ', '') }
  61:     
  62:     String getClassData() {
  63:         final text = file.text.replaceAll(~/".*//inherit/.gif"/,
  64:             ")
  65:         final start = text.indexOf('START OF CLASS DATA')
  66:         final end = text.indexOf('END OF CLASS DATA')
  67:         final html = text.substring(start, end)
  68:         """
    
    

">$type

">(Back to top) "
""
  69:     }    
  70: }
  71:  
  72: m = new DefaultListModel()
  73: desktop = java.awt.Desktop.getDesktop()
  74: browser = {
  75:     if(docList.selectedIndex != -1) {
  76:         def f = File.createTempFile('ApiDocBuster', '.html')
  77:         f.write(JavaDoc.getHtml(docList.selectedValue))
  78:         desktop.open(f)
  79:     }
  80: }
  81:  
  82: search = {
  83:     def keyword = keywordField.text
  84:     if(keyword.size() > 1) { // 检查了下,类名最少两个字符
  85:         m.clear()
  86:         JavaDoc.search(keywordField.text, cb.selected).each { m << it }
  87:     }    
  88: }
  89:  
  90: w = 300
  91: new SwingBuilder().edt {
  92:     frame(title: 'API Doc Buster', size:[w, 240], show: true, locationRelativeTo: null) {
  93:         lookAndFeel('system')
  94:         vbox {
  95:             scrollPane { docList = list(model: m) }
  96:             panel(maximumSize: [w, 24]) {
  97:                 boxLayout()
  98:                 cb = checkBox(text: 'Fuzzy')
  99:                 keywordField = textField(caretUpdate: search)
 100:                 button(text: 'browser', actionPerformed: browser)
 101:             }
 102:         }
 103:     }
 104: }

一百多行的代码就搞定了。换成纯粹的 Java 代码可能连 Swing 界面都写不完微笑。SwingBuilder 的强大完美的诠释了 Groovy 的强大。

PS. 如果你在运行这个脚本的时候发生初始化错误,很可能是你的文档路径和我不同,这样的话可以去修改 folders 的内容,直接写死也没什么问题的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值