001/*license*\ 002 Codelet: Copyright (C) 2014, Jeff Epstein (aliteralmind __DASH__ github __AT__ yahoo __DOT__ com) 003 004 This software is dual-licensed under the: 005 - Lesser General Public License (LGPL) version 3.0 or, at your option, any later version; 006 - Apache Software License (ASL) version 2.0. 007 008 Either license may be applied at your discretion. More information may be found at 009 - http://en.wikipedia.org/wiki/Multi-licensing. 010 011 The text of both licenses is available in the root directory of this project, under the names "LICENSE_lgpl-3.0.txt" and "LICENSE_asl-2.0.txt". The latest copies may be downloaded at: 012 - LGPL 3.0: https://www.gnu.org/licenses/lgpl-3.0.txt 013 - ASL 2.0: http://www.apache.org/licenses/LICENSE-2.0.txt 014\*license*/ 015package com.github.aliteralmind.codelet; 016 import com.github.xbn.lang.CrashIfObject; 017 import com.github.xbn.lang.reflect.ReflectRtxUtil; 018 import static com.github.aliteralmind.codelet.CodeletBaseConfig.*; 019 import static com.github.xbn.lang.XbnConstants.*; 020/** 021 <P>Extract and transform elements from the taglet text.</P> 022 023 @since 0.1.0 024 @author Copyright (C) 2014, Jeff Epstein ({@code aliteralmind __DASH__ github __AT__ yahoo __DOT__ com}), dual-licensed under the LGPL (version 3.0 or later) or the ASL (version 2.0). See source code for details. <A HREF="http://codelet.aliteralmind.com">{@code http://codelet.aliteralmind.com}</A>, <A HREF="https://github.com/aliteralmind/codelet">{@code https://github.com/aliteralmind/codelet}</A> 025 **/ 026public class TagletTextUtil { 027// private static final CodeletBaseConfig CONFIG = CodeletBaseConfig.INSTANCE; 028 /** 029 <P>Get the example code's package name.</P> 030 031 @return <CODE>{@link java.lang.Class Class}.{@link java.lang.Class#forName(String) forName}({@link #getExampleClassFQName(CodeletInstance) getExampleClassFQName}(instance)).{@link java.lang.Class#getPackage() getPackage}().{@link java.lang.reflect.Package#getName() getName}() 032 </CODE> 033 **/ 034 public static final String getExamplePackageName(CodeletInstance instance) throws CodeletFormatException { 035 return ReflectRtxUtil.getClassForName(getExampleClassFQName(instance), "getExampleClassFQName(instance)"). 036 getPackage().getName(); 037 } 038 /** 039 <P>Get the example code's non-fully-qualified class name.</P> 040 041 @return <CODE>{@link java.lang.Class Class}.{@link java.lang.Class#forName(String) forName}({@link #getExampleClassFQName(CodeletInstance) getExampleClassFQName}(instance)).{@link java.lang.Class#getSimpleName() getSimpleName}()</CODE> 042 **/ 043 public static final String getExampleSimpleClassName(CodeletInstance instance) throws CodeletFormatException { 044 return ReflectRtxUtil.getClassForName(getExampleClassFQName(instance), "getExampleClassFQName(instance)"). 045 getSimpleName(); 046 } 047 /** 048 <P>The example code's fully-qualified class name.</P> 049 050 @return If this is a<OL> 051 <LI>{@link com.github.aliteralmind.codelet.CodeletType#CONSOLE_OUT {@.codelet.out}} or {@link com.github.aliteralmind.codelet.CodeletType#SOURCE_AND_OUT {@.codelet.and.out}} taglet, and command-line parameters<OL> 052 <LI>are specified: The {@linkplain #getExampleClassOrFilePortionFromTagletText(CodeletInstance) class-portion} of the {@linkplain CodeletInstance#getText() taglet text} before the open parenthesis ({@code '('}). Example:<OL> 053 <LI>Class-portion: {@code fully.qualified.examples.AnExample("param1", true, 3)}</LI> 054 <LI>Output: {@code fully.qualified.examples.AnExample}</LI> 055 </OL></LI> 056 <LI>are not specified: The entire class-portion.</LI> 057 </OL></LI> 058 <LI>{@link com.github.aliteralmind.codelet.CodeletType#SOURCE_CODE {@.codelet}} or {@link com.github.aliteralmind.codelet.CodeletType#FILE_TEXT {@.codelet.out}} taglet: The entire class-portion</LI> 059 </OL> 060 @see #getExampleCommandLineParams(CodeletInstance) 061 **/ 062 public static final String getExampleClassFQName(CodeletInstance instance) throws CodeletFormatException { 063 String clsTxt = getExampleClassOrFilePortionFromTagletText(instance); 064 int openParenIdx = clsTxt.indexOf("("); 065 return ((openParenIdx != -1) 066 ? clsTxt.substring(0, openParenIdx) 067 : clsTxt); 068 } 069 /** 070 <P>The example code's command-line parameters, as used by {@link com.github.aliteralmind.codelet.CodeletType#CONSOLE_OUT {@.codelet.out}} and {@link com.github.aliteralmind.codelet.CodeletType#SOURCE_AND_OUT {@.codelet.and.out}} taglets.</P> 071 072 @return If this is a {@link com.github.aliteralmind.codelet.CodeletType#CONSOLE_OUT {@.codelet.out}} or {@link com.github.aliteralmind.codelet.CodeletType#SOURCE_AND_OUT {@.codelet.and.out}} taglet, and command-line parameters<OL> 073 <LI>are specified: The {@linkplain #getExampleClassOrFilePortionFromTagletText(CodeletInstance) class-portion} of the {@linkplain CodeletInstance#getText() taglet text} inside--but not including--the parentheses ({@code '('} and {@code ')'}). Example:<OL> 074 <LI>Class-portion: {@code fully.qualified.examples.AnExample("param1", true, 3)}</LI> 075 <LI>Output: {@code "param1", true, 3}</LI> 076 </OL></LI> 077 <LI>are not specified: {@code ""}.</LI> 078 </OL> 079 @see #getExampleClassFQName(CodeletInstance) 080 **/ 081 public static final String getExampleCommandLineParams(CodeletInstance instance) throws CodeletFormatException { 082 String clsTxt = getExampleClassOrFilePortionFromTagletText(instance); 083 int openParenIdx = clsTxt.indexOf("("); 084 if(openParenIdx == -1) { 085 return ""; 086 } 087 return clsTxt.substring((openParenIdx + 1), (clsTxt.length() - 1)); 088 } 089 /** 090 <P>The full path to the plain-text file.</P> 091 092 @return <CODE>{@link #getExampleClassOrFilePortionFromTagletText(CodeletInstance instance) getExampleClassOrFilePortionFromTagletText}(instance)</CODE> 093 @see #getFileNameWithExtension(CodeletInstance) 094 @see #getFileNameWithoutExtension(CodeletInstance) 095 **/ 096 public static final String getFilePath(CodeletInstance instance) { 097 return getExampleClassOrFilePortionFromTagletText(instance); 098 } 099 /** 100 <P>The plain-text file name, including its dot-extension (such as {@code ".txt"}), if any.</P> 101 102 @see #getFileNameWithoutExtension(CodeletInstance) 103 **/ 104 public static final String getFileNameWithExtension(CodeletInstance instance) { 105 String filePortion = getExampleClassOrFilePortionFromTagletText(instance); 106 int idxFileSep = filePortion.indexOf(FILE_SEP); 107 return ((idxFileSep == -1) ? filePortion 108 : filePortion.substring(idxFileSep + 1)); 109 } 110 /** 111 <P>The plain-text file name, excluding its dot-extension (such as {@code ".txt"}).</P> 112 113 @see #getFileNameWithExtension(CodeletInstance) 114 **/ 115 public static final String getFileNameWithoutExtension(CodeletInstance instance) { 116 String fileWExt = getFileNameWithExtension(instance); 117 int idxDot = fileWExt.indexOf(FILE_SEP); 118 return ((idxDot == -1) ? fileWExt 119 : fileWExt.substring(0, idxDot)); 120 } 121 /** 122 <P>The full on-disk path to the example code's source file.</P> 123 124 <P>Example input<OL> 125 <LI>{@linkplain #getExampleClassFQName(CodeletInstance) fully-qualified class name}: {@code "fully.qualified.examples.AnExample"}</LI> 126 <LI>{@linkplain CodeletBaseConfig#getExampleSourceBaseDir() Base-directory}: {@code "C:\java_code\"}</LI> 127 </OL></P> 128 129 <P>Output</P> 130 131 <P>{@code "C:\java_code\fully\qualified\examples\AnExample.java"}</P> 132 133 @return <CODE>{@link com.github.aliteralmind.codelet.CodeletBaseConfig}.{@link com.github.aliteralmind.codelet.CodeletBaseConfig#getExampleSourceBaseDir() getExampleSourceBaseDir}() + 134 <BR> {@link #getExampleClassFQName(CodeletInstance) getExampleClassFQName}(instance).{@link java.lang.String#replace(CharSequence, CharSequence) replace}(".", {@link com.github.xbn.lang.XbnConstants#FILE_SEP FILE_SEP}*) + 135 <BR> ".java"</CODE> 136 **/ 137 public static final String getJavaSourceFilePath(CodeletInstance instance) { 138 return getExampleSourceBaseDir() + 139 getExampleClassFQName(instance).replace(".", FILE_SEP) + 140 ".java"; 141 } 142 /** 143 <P>The absolute url to the example code's source file, <A HREF="http://docs.oracle.com/javase/1.5.0/docs/tooldocs/windows/javadoc.html#linksource">as created by</A> JavaDoc (in <A HREF="{@docRoot}/src-html/">{@code {@docRoot}/src-html/}</A>).</P> 144 145 <P>Example input:<OL> 146 <LI>Example code's {@linkplain #getExampleClassFQName(CodeletInstance) fully-qualified class name}: {@code "fully.qualified.examples.AnExample"}</LI> 147 </OL></P> 148 149 <P>Output:</P> 150 151 <P>{@code "{@docRoot}/src-html/fully/qualified/examples/AnExample.html"}</P> 152 153 <P>Gap is {@linkplain CodeletGap#getFillText(CodeletInstance) filled} with</P> 154 155 <P><CODE>{@link #getJavaDocSourceUrl(CodeletInstance) getJavaDocSourceUrl}(<I>[the-instance]</I>)</CODE></P> 156 157 @return <CODE>"{@docRoot}/src-html/" + 158 <BR> {@link #getExampleClassFQName(CodeletInstance) getExampleClassFQName}(instance).{@link java.lang.String#replace(CharSequence, CharSequence) replace}(".", "/") + 159 <BR> ".html"</CODE> 160 @see #getJavaDocExampleUrl(CodeletInstance) 161 **/ 162 public static final String getJavaDocSourceUrl(CodeletInstance instance) { 163 return "{@docRoot}/src-html/" + 164 getExampleClassFQName(instance).replace(".", "/") + 165 ".html"; 166 } 167 public static final String getJavaDocUrl(CodeletInstance instance) { 168 return "{@docRoot}" + 169 getExampleClassFQName(instance).replace(".", "/") + 170 ".html"; 171 } 172 /** 173 <P>The absolute url to the example code's source file, as created by JavaDoc (in {@code {@docRoot}/src-html/}).</P> 174 175 <P>Example input:<OL> 176 <LI>Example code's {@linkplain #getExampleClassFQName(CodeletInstance) fully-qualified class name}: {@code "fully.qualified.examples.AnExample"}</LI> 177 </OL></P> 178 179 <P>Output:</P> 180 181 <P>{@code "{@docRoot}/src-html/fully/qualified/examples/AnExample.html"}</P> 182 183 <P>Gap is {@linkplain CodeletGap#getFillText(CodeletInstance) filled} with</P> 184 185 <P><CODE>{@link #getJavaDocSourceUrl(CodeletInstance) getJavaDocSourceUrl}(<I>[the-instance]</I>)</CODE></P> 186 187 @return <CODE>"{@docRoot}" + 188 <BR> {@link #getExampleClassFQName(CodeletInstance) getExampleClassFQName}(instance).{@link java.lang.String#replace(CharSequence, CharSequence) replace}(".", "/") + 189 <BR> ".html"</CODE> 190 @see #getJavaDocSourceUrl(CodeletInstance) 191 **/ 192 public static final String getJavaDocExampleUrl(CodeletInstance instance) { 193 return "{@docRoot}" + 194 getExampleClassFQName(instance).replace(".", "/") + 195 ".html"; 196 } 197 /** 198 <P>The example-class or plain-text-file portion of the taglet text.</P> 199 200 @return <CODE>{@link #getTagletTextSplitOnLineProcDelim(CodeletInstance) getTagletTextSplitOnLineProcDelim}(instance)[0]</CODE> 201 **/ 202 public static final String getExampleClassOrFilePortionFromTagletText(CodeletInstance instance) throws CodeletFormatException { 203 return getTagletTextSplitOnLineProcDelim(instance)[0]; 204 } 205 /** 206 <P>The class-or-plain-text-file portion of the taglet text, split on the customizer delimiter character.</P> 207 208 @param instance May not be {@code null} 209 @return If there is no line-proc (no delimiter char): A one element string array containing the class/file portion. Otherwise a two-element array, where element index one is the customizer portion. 210 @exception CodeletFormatException If<OL> 211 <LI>More than one customizer character is found. For including literal delimiters in string parameters, use <CODE>{@link com.github.aliteralmind.codelet.CodeletInstance CodeletInstance}.{@link com.github.aliteralmind.codelet.CodeletInstance CodeletInstance#ESCAPED_CUSTOMIZER_PREFIX_CHAR ESCAPED_CUSTOMIZER_PREFIX_CHAR}</CODE>.</LI> 212 <LI>Either portion (class/file or line-proc) contains no characters.</LI> 213 </OL> 214 @see com.github.aliteralmind.codelet.CodeletInstance#getText() 215 @see #getExampleClassOrFilePortionFromTagletText(CodeletInstance) 216 @see com.github.aliteralmind.codelet.CodeletInstance#CUSTOMIZER_PREFIX_CHAR CodeletInstance#CUSTOMIZER_PREFIX_CHAR 217 **/ 218 public static final String[] getTagletTextSplitOnLineProcDelim(CodeletInstance instance) throws CodeletFormatException { 219 String[] rawObjectProcStrs = null; 220 try { 221 rawObjectProcStrs = instance.getText().split((new Character(CodeletInstance.CUSTOMIZER_PREFIX_CHAR)).toString()); 222 } catch(RuntimeException rx) { 223 throw CrashIfObject.nullOrReturnCause(instance, "instance", null, rx); 224 } 225 226 if(rawObjectProcStrs.length > 2) { 227 throw new CodeletFormatException(instance, "More than one customizer delimiter ('" + CodeletInstance.CUSTOMIZER_PREFIX_CHAR + "') found. For including literal delimiters in string parameters, use \"" + CodeletInstance.ESCAPED_CUSTOMIZER_PREFIX_CHAR + "\""); 228 } 229 230 if(rawObjectProcStrs[0].length() == 0) { 231 throw new CodeletFormatException(instance, "Class/file portion (or the entire taglet!) has no characters"); 232 } 233 if(rawObjectProcStrs.length == 2) { 234 if(!rawObjectProcStrs[1].equals("()") && 235 (rawObjectProcStrs[1].length() < 3 || 236 rawObjectProcStrs[1].charAt(rawObjectProcStrs[1].length() - 1) != ')')) { 237 throw new CodeletFormatException(instance, "Customizer portion (\"" + rawObjectProcStrs[1] + "\") is invalid. Must be either the \":()\" shortcut (meaning equal to \"()\"), or a valid Java function-name followed by parentheses with zero or more parameters: \"funcName(...)\". The last character must be the close parenthesis (')')."); 238 } 239 } 240 241 return rawObjectProcStrs; 242 } 243 private TagletTextUtil() { 244 throw new IllegalStateException("Do not instantiate."); 245 } 246}