/* MonkeyTalk - a cross-platform functional testing tool
Copyright (C) 2012 Gorilla Logic, Inc.
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>. */
package com.gorillalogic.monkeytalk.api.doc;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.util.List;
import com.gorillalogic.monkeytalk.api.meta.API;
import com.gorillalogic.monkeytalk.api.meta.Action;
import com.gorillalogic.monkeytalk.api.meta.Arg;
import com.gorillalogic.monkeytalk.api.meta.Component;
import com.gorillalogic.monkeytalk.api.meta.Property;
/**
* Generate html doc for the API.
*/
public class APIDocGenerator {
private static String printAPIDoc(String version) {
String title = "MonkeyTalk API Docs" + (version != null ? " v" + version : "");
return "<!DOCTYPE html>\n<html>\n<head>\n<title>" + title + "</title>\n" + CSS
+ "</head>\n" + "<body>\n<h1>" + title + "</h1>\n" + printIndex()
+ printComponents() + JS + "</body>\n</html>";
}
private static String CSS = "<style type=\"text/css\">\n"
+ "ul#components { padding:0 0 8px 0; margin:0 0 0 8px; list-style:none; }\n"
+ "div#idx { float:right; }\n"
+ "div#idx ul { margin-right:12px; background-color:#ccc; padding:8px; list-style:none; }\n"
+ "div#idx ul li a { color:#333; text-decoration:none; }\n"
+ "div#idx ul li a:hover { color:#666; text-decoration:underline; }\n"
+ "h3 { padding:0; margin:16px 0 0 0; }\n"
+ ".desc { color:#333; padding:4px 0 6px 0; margin:0; }\n" + ".idxlbl { }\n"
+ ".idxchk { margin-right:6px; }\n" + ".flex { display:none; }\n" + "</style>\n";
private static String JS = "<script>\n" + "if (!document.getElementsByClassName) {\n"
+ " document.getElementsByClassName = function(cn) {\n"
+ " var allT = document.getElementsByTagName('*'), allCN=[], i=0, a;\n"
+ " while(a=allT[i++]) {\n" + " a.className==cn?allCN[allCN.length]=a:null;\n"
+ " }\n" + " return allCN;\n" + " }\n" + "}\n" + "function showIt(cn) {\n"
+ " chk = document.getElementById(cn + 'chk');\n"
+ " elems = document.getElementsByClassName(cn);\n"
+ " for (var i=0; i<elems.length; i++) {\n" + " var e = elems[i];\n"
+ " e.style.display = (chk.checked ? 'block' : 'none');\n" + " }\n" + "}\n"
+ "</script>\n";
private static String IDX = "<ul>\n"
+ " <li>Show:</li>\n"
+ " <li><label class=\"idxlbl\" for=\"ioschk\"><input id=\"ioschk\" class=\"idxchk\" name=\"ioschk\" type=\"checkbox\" checked=\"checked\" disabled=\"disabled\">iOS</label></li>\n"
+ " <li><label class=\"idxlbl\" for=\"androidchk\"><input id=\"androidchk\" class=\"idxchk\" name=\"androidchk\" type=\"checkbox\" checked=\"checked\" disabled=\"disabled\">Android</label></li>\n"
+ " <li><label class=\"idxlbl\" for=\"flexchk\"><input id=\"flexchk\" class=\"idxchk\" name=\"flexchk\" type=\"checkbox\" onclick=\"showIt('flex');\">Flex</label></li>\n"
+ "</ul>\n";
// Checks to see if a class is a child of a class that eventually extends the given class.
// ex. Grid -> ItemSelector -> IndexedSelector -> View
// checkForEventualSuperClass(Grid, View) would return true.
private static boolean checkForEventualSuperClass(Component c, String klass) {
if (c.getSuper() != null) {
if (c.getSuper().getName().equalsIgnoreCase(klass)) {
return true;
} else
return checkForEventualSuperClass(c.getSuper(), klass);
}
return false;
}
private static String printComponents() {
StringBuilder sb = new StringBuilder();
List<String> viewActions = API.getComponent("view").getActionNames();
List<String> verifyActions = API.getComponent("verifiable").getActionNames();
viewActions.removeAll(verifyActions);
for (Component c : API.getComponents()) {
System.out.println(c.getName()
+ (c.getSuper() != null ? " : " + c.getSuper().getName() : "")
+ " eventually part of View = " + checkForEventualSuperClass(c, "view"));
String n = c.getName();
String klass = (n.startsWith("Flex") || n.startsWith("Spark") ? "flex" : null);
sb.append(" ").append(printLi(n, klass)).append(printAnchor(n))
.append(printDesc(c.getDescription())).append("<ul>\n");
for (Action a : c.getActions()) {
if (("view".equalsIgnoreCase(n) && !verifyActions.contains(a.getName()))
|| ("verifiable".equalsIgnoreCase(n) || (!viewActions.contains(a.getName()) && !verifyActions
.contains(a.getName())))) {
sb.append(" <li>").append(printAction(c, a)).append("</li>\n");
}
}
if (c.getSuper() != null && checkForEventualSuperClass(c, "verifiable")) {
if (!c.getName().equalsIgnoreCase("view"))
sb.append(" <li><a href=\"#View\">more actions inherited from View</a></li>\n");
sb.append(" <li><a href=\"#Verifiable\">verify actions inherited from Verifiable</a></li>\n");
}
if (c.getProperties().size() > 0) {
sb.append(" <li><i>Properties:</i><ul>\n");
for (Property p : c.getProperties()) {
sb.append(printProperty(p)).append('\n');
}
sb.deleteCharAt(sb.length() - 1);
sb.append("</ul></li>\n");
}
sb.deleteCharAt(sb.length() - 1);
sb.append("</ul></li>\n");
}
return "<ul id=\"components\">\n" + sb.toString() + "</ul>\n";
}
private static String printIndex() {
StringBuilder sb = new StringBuilder();
sb.append("<div id=\"idx\">\n");
sb.append(API.IGNORE_FLEX ? "" : IDX);
sb.append("<ul>\n");
for (Component c : API.getComponents()) {
String n = c.getName();
String klass = (n.startsWith("Flex") || n.startsWith("Spark") ? "flex" : "");
sb.append(" ").append(printLi(null, klass)).append("<a href=\"#").append(n)
.append("\">").append(n).append("</a></li>\n");
}
sb.append("</ul>\n");
sb.append("</div>\n");
return sb.toString();
}
private static String printDesc(String desc) {
return "<p class=\"desc\">" + desc + "</p>";
}
private static String printAction(Component c, Action a) {
StringBuilder sb = new StringBuilder();
StringBuilder args = new StringBuilder();
for (Arg arg : a.getArgs()) {
sb.append(sb.length() > 0 ? ", " : "").append(arg.toString(false));
args.append(args.length() > 0 ? "\n" : "").append(printArg(arg));
}
return "<b><a name=\"" + c.getName() + "." + a.getName() + "\"></a>" + a.getName() + "("
+ sb.toString() + ")" + (a.getReturnType() != null ? ":" + a.getReturnType() : "")
+ "</b>" + (a.getDescription() != null ? " - " + a.getDescription() : "")
+ (args.length() > 0 ? "<ul>\n" + args + "</ul>" : "");
}
private static String printArg(Arg a) {
return " <li><i>" + a.getName() + "</i>"
+ (a.getDescription() != null ? " - " + a.getDescription() : "") + "</li>";
}
private static String printAnchor(String name) {
return "<a name=\"" + name + "\"></a><h3>" + name + "</h3>";
}
private static String printLi(String id, String klass) {
return "<li" + (id != null ? " id=\"" + id + "\"" : "")
+ (klass != null ? " class=\"" + klass + "\"" : "") + ">";
}
private static String printProperty(Property p) {
return " <li><b>"
+ p.getName()
+ "</b>"
+ (p.getArgs() != null && p.getArgs().length() > 0 ? "(" + p.getArgs() + ")" : "")
+ (p.getDescription() != null && p.getDescription().length() > 0 ? " - "
+ p.getDescription() : "") + "</li>";
}
public static void main(String[] args) {
if (args.length < 1 || args.length > 2) {
System.err.println("Usage: java APIDocGenerator <output> [version]");
System.exit(1);
}
File out = new File(args[0]);
String doc = printAPIDoc(args.length == 2 ? args[1] : null);
try {
writeFile(out, doc);
} catch (IOException ex) {
ex.printStackTrace();
System.exit(1);
}
}
private static void writeFile(File f, String contents) throws IOException {
BufferedWriter out = new BufferedWriter(new FileWriter(f));
out.write(contents);
out.close();
}
}