Groovydocを使用したGroovyの文書化

Groovydocは、JavadocがJavaに提供するものをGroovyに提供するために2007年に導入されました。Groovydocは、Groovy言語を構成するGroovyクラスとJavaクラスのAPIドキュメントを生成するために使用されます。この投稿では、コマンドラインとGroovyが提供するカスタムAntタスクを介してGroovydocを呼び出す方法について説明します。

Groovydoc / Javadocコメント付きのGroovyおよびJavaソースコード

Groovydocのデモを行うために、ブログ投稿Easy Groovy Logger Injection and LogGuardingで最初に紹介されたGroovyスクリプトとクラスの適応バージョンを使用します。メインのGroovyスクリプトとその投稿のGroovyクラスが変更され、Groovydocの動作をより適切に示すためにJavadocスタイルのコメントが追加されました。改訂されたスクリプトと関連するクラスは、次のコードリストに示されています。

demoGroovyLogTransformation.groovy

#!/usr/bin/env groovy /** * demoGroovyLogTransformation.groovy * * Grab SLF4J, Log4j, and Apache Commons Logging dependencies using @Grab and * demonstrate Groovy 1.8's injected logging handles. * * //marxsoftware.blogspot.com/2011/05/easy-groovy-logger-injection-an... */ // No need to "grab" java.util.logging: it's part of the JDK! /* * Specifying 'slf4j-simple' rather than 'slf4j-api' to avoid the error * "Failed to load class "org.slf4j.impl.StaticLoggerBinder" that is caused by * specifying no or more than one of the actual logging binding libraries to * be used (see //www.slf4j.org/codes.html#StaticLoggerBinder). One should * be selected from 'slf4j-nop', 'slf4j-simple', 'slf4j-log4j12.jar', * 'slf4j-jdk14', or 'logback-classic'. An example of specifying the SLF4J * dependency via @Grab is available at * //mvnrepository.com/artifact/org.slf4j/slf4j-api/1.6.1. */ @Grab(group='org.slf4j', module="slf4j-simple", version="1.6.1") /* * An example of specifying the Log4j dependency via @Grab is at * //mvnrepository.com/artifact/log4j/log4j/1.2.16. */ @Grab(group='log4j', module="log4j", version="1.2.16") /* * An example of specifying the Apache Commons Logging dependency via @Grab is at * //mvnrepository.com/artifact/commons-logging/commons-logging-api/1..... */ @Grab(group='commons-logging', module="commons-logging-api", version="1.1") /* * Run the tests... */ int headerSize = 79 printHeader("java.util.logger", headerSize) def javaUtilLogger = new JavaUtilLoggerClass() printHeader("Log4j", headerSize) def log4jLogger = new Log4jLoggerClass() printHeader("SLF4j", headerSize) def slf4jLogger = new Slf4jLoggerClass() printHeader("Apache Commons", headerSize) def commonsLogger = new ApacheCommonsLoggerClass() /** * Print header with provided text. * * @param textForHeader Text to be included in the header. * @param sizeOfHeader Number of characters in each row of header. */ def printHeader(final String textForHeader, final int sizeOfHeader) { println "=".multiply(sizeOfHeader) println "= ${textForHeader}${' '.multiply(sizeOfHeader-textForHeader.size()-4)}=".multiply(sizeOfHeader) } 

JavaUtilLoggerClass.groovy

import groovy.util.logging.Log /** * Sample Groovy class using {@code @Log} to inject java.util.logging logger * into the class. */ @Log class JavaUtilLoggerClass { /** * Constructor. */ public JavaUtilLoggerClass() { println "\njava.util.logging (${log.name}: ${log.class}):" log.info "${this.printAndReturnValue(1)}" log.finer "${this.printAndReturnValue(2)}" } /** * Print provided value and then return it as part of String indicating part * of JDK's java.util.logging. * * @param newValue Value to be printed and included in return String. * @return String indicating newValue and JDK for java.util.logging. */ public String printAndReturnValue(int newValue) { println "JDK: Print method invoked for ${newValue}" return "JDK: ${newValue}" } } 

Log4jLoggerClass.groovy

import groovy.util.logging.Log4j import org.apache.log4j.Level /** * Sample Groovy class using {@code @Log4j} to inject Log4j logger * into the class. */ @Log4j class Log4jLoggerClass { /** * Constructor. */ Log4jLoggerClass() { // It is necessary to set logging level here because default is FATAL and // we are not using a Log4j external configuration file in this example log.setLevel(Level.INFO) println "\nLog4j Logging (${log.name}: ${log.class}):" log.info "${this.printAndReturnValue(1)}" log.debug "${this.printAndReturnValue(2)}" } /** * Print provided value and then return it as part of String indicating part * of Log4j. * * @param newValue Value to be printed and included in return String. * @return String indicating newValue and Log4j. */ public String printAndReturnValue(int newValue) { println "Log4j: Print method invoked for ${newValue}" return "Log4j: ${newValue}" } } 

Slf4jLoggerClass.groovy

import groovy.util.logging.Slf4j /** * Sample Groovy class using {@code @Slf4j} to inject Simple Logging Facade for * Java (SLF4J) logger into the class. */ @Slf4j class Slf4jLoggerClass { /** * Constructor. */ public Slf4jLoggerClass() { println "\nSLF4J Logging (${log.name}: ${log.class}):" log.info "${this.printAndReturnValue(1)}" log.debug "${this.printAndReturnValue(2)}" } /** * Print provided value and then return it as part of String indicating part * of SLF4J logging. * * @param newValue Value to be printed and included in return String. * @return String indicating newValue and SLF4J. */ public String printAndReturnValue(int newValue) { println "SLF4J: Print method invoked for ${newValue}" return "SLF4J: ${newValue}" } } 

ApacheCommonsLoggerClass.groovy

import groovy.util.logging.Commons /** * Sample Groovy class using {@code @Commons} to inject Apache Commons logger * into the class. */ @Commons class ApacheCommonsLoggerClass { /** * Constructor. */ public ApacheCommonsLoggerClass() { println "\nApache Commons Logging (${log.name}: ${log.class}):" log.info "${this.printAndReturnValue(1)}" log.debug "${this.printAndReturnValue(2)}" } /** * Print provided value and then return it as part of String indicating part * of Apache Commons Logging. * * @param newValue Value to be printed and included in return String. * @return String indicating newValue and Apache Commons Logging. */ public String printAndReturnValue(int newValue) { println "Commons: Print method invoked for ${newValue}" return "Commons: ${newValue}" } } 

上記のGroovyスクリプトとクラスに加えて、ここでは新しいJavaクラスを使用して、GroovydocがGroovyクラスだけでなくJavaクラスでも機能することを示しています。Javaクラスは、Groovydocによって処理されるJavadocコメントを提供する以外にはあまり機能しません。

DoNothingClass.java

/** * Class that does not do anything, but is here to be a Java class run through * groovydoc. */ public class DoNothingClass { /** * Simple method that returns literal "Hello _addressee_!" string where * _addressee_ is the name provided to this method. * * @param addressee Name for returned salutation to be addressed to. * @return "Hello!" */ public String sayHello(final String addressee) { return "Hello, " + addressee; } /** * Main executable function. */ public static void main(final String[] arguments) { final DoNothingClass me = new DoNothingClass(); me.sayHello("Dustin"); } /** * Provide String representation of this object. * * @return String representation of me. */ @Override public String toString() { return "Hello!"; } } 

コマンドラインでGroovydocを実行する

上記のGroovyスクリプト、Groovyクラス、およびJavaクラスの準備ができたら、これらのクラスとスクリプトに対してGroovydocを実行することに注意を向けるときが来ました。Javadocの場合と同様に、Groovydocはコマンドラインから実行できます。上記のクラスおよびスクリプトに対してGroovydocを実行するためのコマンド(コマンドが実行されるのと同じディレクトリにすべてあると仮定)は、次のようになります。

groovydoc -classpath C:\groovy-1.8.0\lib\ -d output -windowtitle "Groovy 1.8 Logging Example" -header "Groovy 1.8 Logging (Inspired by Actual Events)" -footer "Inspired by Actual Events: Logging in Groovy 1.8" -doctitle "Logging in Groovy 1.8 Demonstrated" *.groovy *.java 

上記のコマンドはすべて1行で実行されます。ただし、読みやすさを向上させるために、コマンドを分解するために改行を追加しました。

groovydoc -classpath C:\groovy-1.8.0\lib\ -d output -windowtitle "Groovy 1.8 Logging Example" -header "Groovy 1.8 Logging (Inspired by Actual Events)" -footer "Inspired by Actual Events: Logging in Groovy 1.8" -doctitle "Logging in Groovy 1.8 Demonstrated" *.groovy *.java 

groovydocコマンドのパラメーターは、コマンドラインからjavadocを使用したことのある人なら誰でも知っているように見えます。コマンドの最後の部分は、groovydocをGroovyおよびJavaコードに対して実行する必要があることを指定しています。

AntからGroovydocを実行する

Groovydocは、Groovyユーザーガイドで説明されているように、カスタムAntタスクを介して簡単にアクセスすることもできます。最初に適切なtaskdefを設定し、次にその定義されたタグを使用することで、groovydocAntタスクを適用するのはかなり簡単です。これは、関連build.xmlファイルからの次のXMLスニペットに示されています。

groovydocタスクを示すAntbuild.xmlファイルの一部


    
    

build.xml上記のAntの部分は、コマンドラインで使用される部分とほぼ同じです。Antを介してGroovydocを利用できるようにすることは、AntベースのビルドシステムからのGroovyドキュメントのビルドを簡単に統合できるため重要です。

Groovydocで生成されたドキュメント

Groovydoc(コマンドラインまたはAntベース)を介してGroovyドキュメントを生成する各アプローチは、他のアプローチとほぼ同じように機能するため、ここでは、どちらのアプローチからも得られるHTML出力に焦点を当てます。次の一連の画面スナップショットは、生成されたドキュメントをメインページで始まり、DefaultPackageページ(現在のディレクトリにスクリプト、Groovyクラス、Javaクラスを怠惰に残し、パッケージ宣言なしで)、それぞれ出力を示しています。 Groovyスクリプト、Groovyクラスの例、および考案されたJavaクラスの場合。最後の3つの画像は、GroovyスクリプトとGroovyクラスとJavaクラスの出力を区別するのに役立ちます。

Groovydocメインページの例

サンプルパッケージのGroovydoc出力(DefaultPackage)

Groovyスクリプトの例のGroovydoc出力

Groovyクラスの例のGroovydoc出力

サンプルJavaクラスのGroovydoc出力

上記のGroovydocの出力からいくつかの観察を行うことができます。まず、Groovyスクリプト用に生成されたドキュメントには、スクリプトで定義されたメソッド(暗黙的なmainメソッドを含む)のみがドキュメント化されていました。上記の静止画像からそれほど明らかではないのは、実際には、少なくとも1つのメソッドがスクリプトで明示的に定義されていない限り、Groovydoc出力はスクリプトに対してまったく作成されないということです。スクリプトで1つのメソッドが定義されている場合、Groovydoc出力は、定義されたメソッドと暗黙のmainメソッドに対して生成されます。このオプション-nomainforscriptsをGroovydocに渡して、暗黙的なmainメソッド用にGroovydocを生成しないようにすることができます。このオプションを追加した結果を次に示します(mainのドキュメントは表示されなくなったことに注意してください)。

スクリプトの関数を暗黙的に文書化し-nommainforscriptsたくない場合が多いため、このオプションは便利ですmain。実際、このmain関数は通常、スクリプトの作成者および保守者としての私たちから「隠されています」。

Groovydocで生成された出力を見ると、2つ目の観察結果は、生成された出力がGroovyとJavaのソースコードを区別していることです。Groovyスクリプトとクラスには「[Groovy]」というラベルが付けられ、Javaクラスには「[Java]」というラベルが付けられています。これは、Groovydocで生成されたGroovy APIドキュメントでも明らかです。この機能により、groovy.sql.SqlとAntBuilderがJavaクラスであり、JmxBuilderとSwingBuilderがGroovyクラスであることが簡単に識別できます。