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