Mendokumentasikan Groovy dengan Groovydoc

Groovydoc diperkenalkan pada tahun 2007 untuk menyediakan Groovy apa yang disediakan Javadoc untuk Java. Groovydoc digunakan untuk menghasilkan dokumentasi API untuk kelas Groovy dan Java yang menyusun bahasa Groovy. Dalam posting ini, saya melihat pemanggilan Groovydoc melalui baris perintah dan melalui tugas Ant kustom yang disediakan Groovy.

Kode Sumber Groovy dan Java dengan Komentar Groovydoc / Javadoc

Saya akan menggunakan versi adaptasi dari skrip Groovy dan kelas yang pertama kali diperkenalkan di posting blog saya Injeksi Logger Groovy Mudah dan Penjaga Log untuk mendemonstrasikan Groovydoc. Skrip Groovy utama dan kelas Groovy dari posting itu telah dimodifikasi untuk menyertakan lebih banyak komentar bergaya Javadoc untuk mendemonstrasikan aksi Groovydoc dengan lebih baik. Skrip yang direvisi dan kelas terkait ditampilkan dalam daftar kode berikutnya.

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}" } } 

Selain skrip dan kelas Groovy di atas, saya juga menggunakan kelas Java baru di sini untuk mengilustrasikan bahwa Groovydoc berfungsi pada kelas Java serta kelas Groovy. Kelas Java tidak melakukan banyak hal selain menyediakan komentar Javadoc untuk diproses oleh Groovydoc.

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!"; } } 

Menjalankan Groovydoc di Command Line

Dengan skrip Groovy, kelas Groovy, dan kelas Java yang ditunjukkan di atas siap digunakan, sekarang saatnya mengalihkan perhatian untuk menjalankan Groovydoc pada kelas dan skrip ini. Seperti halnya dengan Javadoc, Groovydoc dapat dijalankan dari baris perintah. Perintah untuk menjalankan Groovydoc terhadap kelas dan skrip di atas (dengan asumsi semuanya ada di direktori yang sama tempat perintah dijalankan) terlihat seperti ini:

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 

Perintah di atas semua dijalankan dalam satu baris. Namun, untuk meningkatkan keterbacaan, saya telah menambahkan jeda baris untuk memecah perintah.

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 

Parameter perintah groovydoc terlihat familier bagi siapa saja yang telah menggunakan javadoc dari baris perintah. Bagian terakhir dari perintah tersebut menetapkan bahwa groovydoc harus dijalankan terhadap kode Groovy dan Java.

Menjalankan Groovydoc dari Ant

Groovydoc juga dapat dengan mudah diakses melalui tugas Ant kustom seperti yang dijelaskan di Panduan Pengguna Groovy. Sangat mudah untuk menerapkan tugas Ant groovydoc dengan terlebih dahulu menyiapkan taskdef yang sesuai dan kemudian dengan menggunakan tag yang ditentukan itu. Ini ditunjukkan dalam potongan XML berikut dari build.xmlfile yang relevan .

Bagian dari File Ant build.xml Mendemonstrasikan Tugas groovydoc


    
    

Porsi Semut yang build.xmlditunjukkan di atas kira-kira sama dengan yang digunakan pada baris perintah. Memiliki Groovydoc yang tersedia melalui Ant itu penting karena memudahkan integrasi pembuatan dokumentasi Groovy dari sistem build berbasis Ant.

Dokumentasi yang Dihasilkan Groovydoc

Karena setiap pendekatan untuk menghasilkan dokumentasi Groovy melalui Groovydoc (baris perintah atau berbasis Ant) berfungsi hampir sama dengan yang lain, sekarang saya akan fokus pada keluaran HTML yang dapat berasal dari kedua pendekatan tersebut. Rangkaian snapshot layar berikutnya menunjukkan dokumentasi yang dihasilkan dimulai dengan halaman utama, diikuti oleh halaman DefaultPackage (saya dengan malas meninggalkan skrip, kelas Groovy, dan kelas Java di direktori saat ini dan tanpa deklarasi paket apa pun), diikuti masing-masing oleh keluaran untuk skrip Groovy, untuk contoh kelas Groovy, dan untuk kelas Java yang dibuat-buat. Tiga gambar terakhir membantu membedakan antara output untuk Groovy Script versus class Groovy versus class Java.

Contoh Halaman Utama Groovydoc

Output Groovydoc untuk Paket Contoh (DefaultPackage)

Output Groovydoc untuk Contoh Skrip Groovy

Output Groovydoc untuk Contoh Kelas Groovy

Output Groovydoc untuk Contoh Kelas Java

Beberapa pengamatan dapat dilakukan dari keluaran Groovydoc yang ditunjukkan di atas. Pertama, dokumentasi yang dihasilkan untuk skrip Groovy hanya mendokumentasikan metode yang ditentukan dalam skrip (termasuk mainmetode implisit ). Apa yang tidak begitu jelas dari gambar statis di atas adalah bahwa, pada kenyataannya, tidak ada keluaran Groovydoc yang dibuat untuk skrip sama sekali kecuali setidaknya satu metode didefinisikan secara eksplisit dalam skrip. Jika satu metode ditentukan dalam skrip, maka keluaran Groovydoc dihasilkan untuk metode yang ditentukan dan untuk metode utama implisit. Opsi -nomainforscriptsini dapat diteruskan ke Groovydoc agar Groovydoc tidak dibuat untuk mainmetode implisit . Keluaran dari penambahan opsi ini ditampilkan berikutnya (perhatikan bahwa maindokumentasi tidak lagi ditampilkan).

The -nommainforscriptspilihan adalah bagus karena kita sering tidak ingin mainfungsi untuk secara implisit didokumentasikan untuk script kami. Memang, mainfungsi tersebut biasanya "tersembunyi" dari kita sebagai penulis dan pengelola skrip.

Pengamatan kedua dari melihat keluaran yang dihasilkan Groovydoc adalah bahwa keluaran yang dihasilkan membedakan antara kode sumber Groovy dan Java. Skrip dan kelas Groovy diberi label "[Groovy]" dan kelas Java diberi label "[Java]." Ini juga terbukti dalam dokumentasi Groovy API yang dihasilkan Groovydoc di mana fitur ini memudahkan untuk mengidentifikasi bahwa groovy.sql.Sql dan AntBuilder adalah kelas Java sedangkan JmxBuilder dan SwingBuilder adalah kelas Groovy.