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> &nbsp; &nbsp; {@link #getExampleClassFQName(CodeletInstance) getExampleClassFQName}(instance).{@link java.lang.String#replace(CharSequence, CharSequence) replace}(&quot;.&quot;, {@link com.github.xbn.lang.XbnConstants#FILE_SEP FILE_SEP}*) +
135      <BR> &nbsp; &nbsp; &quot;.java&quot;</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>&quot;{@docRoot}/src-html/&quot; +
158      <BR> &nbsp; &nbsp; {@link #getExampleClassFQName(CodeletInstance) getExampleClassFQName}(instance).{@link java.lang.String#replace(CharSequence, CharSequence) replace}(&quot;.&quot;, &quot;/&quot;) +
159      <BR> &nbsp; &nbsp; &quot;.html&quot;</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>&quot;{@docRoot}&quot; +
188      <BR> &nbsp; &nbsp; {@link #getExampleClassFQName(CodeletInstance) getExampleClassFQName}(instance).{@link java.lang.String#replace(CharSequence, CharSequence) replace}(&quot;.&quot;, &quot;/&quot;) +
189      <BR> &nbsp; &nbsp; &quot;.html&quot;</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}