1 // a class for autogenerating help files from source markup
2 // a special multiline comment is used: /*@@*/
3 // plus some other conventions
4 // After class name you can write
6 shortDesc: description of the method
10 testvar: a name of a instance var
11 classtestvar: a name of a class var
12 instDesc: the name of the instance methods section
13 longInstDesc: a comment related to the instance methods section
16 // After each method you can write
18 desc: a description of the method
19 argName: for each arg. Default value is added automatically
22 // started after 04/11/07
27 var class, path, parser, classDoc, cmDict, imDict ;
28 var shortDesc, longDesc, seeAlso, issues, instDesc, longInstDesc ;
30 var doctype, head, preface, examples ;
32 *new { arg undocumentedClass, path ;
33 ^super.new.initClassHelper( undocumentedClass, path )
36 initClassHelper { arg aClass, aPath ;
38 parser = DocParser.new(class) ;
39 classDoc = parser.getDocs[0] ;
40 cmDict = parser.getDocs[1] ;
41 imDict = parser.getDocs[2] ;
42 varDict = IdentityDictionary.new ;
46 <meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\">
47 <meta http-equiv=\"Content-Style-Type\" content=\"text/css\">
49 <meta name=\"Generator\" content=\"Cocoa HTML Writer\">
50 <meta name=\"CocoaVersion\" content=\"824.42\">
51 <style type=\"text/css\">
52 p.p1 {margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px Helvetica}
53 p.p2 {margin: 0.0px 0.0px 0.0px 0.0px; font: 12.0px Helvetica; min-height: 14.0px}
54 p.p3 {margin: 0.0px 0.0px 0.0px 0.0px; font: 9.0px Monaco; min-height: 12.0px}
55 p.p4 {margin: 0.0px 0.0px 0.0px 0.0px; font: 14.0px Helvetica}
56 p.p5 {margin: 0.0px 0.0px 0.0px 57.0px; text-indent: -57.0px; font: 9.0px Monaco; min-height: 12.0px}
57 p.p6 {margin: 0.0px 0.0px 0.0px 57.0px; text-indent: -57.0px; font: 12.0px Helvetica}
58 p.p7 {margin: 0.0px 0.0px 0.0px 57.0px; text-indent: -57.0px; font: 12.0px Helvetica; min-height: 14.0px}
59 p.p8 {margin: 0.0px 0.0px 0.0px 85.0px; text-indent: -85.0px; font: 12.0px Helvetica}
60 p.p9 {margin: 0.0px 0.0px 0.0px 57.0px; text-indent: -57.0px; font: 9.0px Monaco; color: #d40000}
61 p.p10 {margin: 0.0px 0.0px 0.0px 57.0px; text-indent: -57.0px; font: 9.0px Monaco}
62 p.p11 {margin: 0.0px 0.0px 0.0px 57.0px; text-indent: -57.0px; font: 14.0px Helvetica}
63 p.p12 {margin: 0.0px 0.0px 0.0px 57.0px; text-indent: -57.0px; font: 14.0px Helvetica; min-height: 17.0px}
64 p.p13 {margin: 0.0px 0.0px 0.0px 85.0px; text-indent: -85.0px; font: 12.0px Helvetica; min-height: 14.0px}
65 p.p14 {margin: 0.0px 0.0px 0.0px 0.0px; font: 9.0px Monaco; color: #d40000}
66 p.p15 {margin: 0.0px 0.0px 0.0px 0.0px; font: 9.0px Monaco}
67 span.s1 {font: 18.0px Helvetica}
68 span.s2 {color: #1200c4}
69 span.s3 {color: #1200c4}
70 span.s4 {color: #000000}
71 span.s5 {color: #1200c4}
72 span.s6 {color: #d40000}
73 span.s7 {font: 12.0px Helvetica; color: #000000}
74 span.s8 {color: #0000ff}
75 span.s9 {color: #1200c4}
76 span.Apple-tab-span {white-space:pre}
81 <!DOCTYPE html PUBLIC \"-//W3C//DTD HTML 4.01//EN\" \"http://www.w3.org/TR/html4/strict.dtd\">
85 GUI.current.dialog.savePanel({ arg newPath ;
86 path = newPath ; {this.makeHelp}.defer })
87 }, { this.makeHelp }) ;
92 var title = class.name.asString ;
93 var preface = this.createPreface ;
94 var classMethodBlock = this.createClassMethodBlock ;
95 var getterSetter = this.createGetterSetterBlock ;
96 var instanceMethodBlock = this.createInstanceMethodBlock ;
98 // here we put together all the stuff
106 instanceMethodBlock +
113 // and reopen thru class.openHelpFile
114 // open works if the path is a place where SC looks for Help files
119 var superclasses, parents = "" ;
120 this.createClassDocBlock ;
121 // here only for the special case of Object
122 superclasses = if ( class == Object, { nil }, { class.superclasses.reverse }) ;
123 superclasses.do({arg item ; parents = parents+item+":" }) ;
125 <p class=\"p1\"><span class=\"s1\"><b>SomeClass<span class=\"Apple-tab-span\"> </span><span class=\"Apple-tab-span\"> </span><span class=\"Apple-tab-span\"> </span></b></span><b>shortDesc</b><span class=\"s1\"><b><span class=\"Apple-tab-span\"> </span></b></span></p>
126 <p class=\"p2\"><br></p>
127 <p class=\"p1\"><b>Inherits from: </b><b>Parents</b></p>
128 <p class=\"p3\"><br></p>
129 <p class=\"p1\">longDesc</p>
130 <p class=\"p2\"><br></p>
131 <p class=\"p1\"><b>See also:</b> seeAlso</p>
132 <p class=\"p2\"><br></p>
133 <p class=\"p4\"><b>Other Issues</b></p>
134 <p class=\"p2\"><br></p>
135 <p class=\"p1\">issues</a></p>
136 <p class=\"p2\"><br></p>
137 " .replace("SomeClass", class.name.asString)
138 .replace("Parents", parents[..parents.size-2])
139 .replace("shortDesc", shortDesc)
140 .replace("longDesc", longDesc)
141 .replace("issues", issues)
142 .replace("seeAlso", seeAlso)
146 createClassMethodBlock {
147 var isEx, methodTitle ;
149 <p class=\"p4\"><b>Creation / Class Methods</b></p>
150 <p class=\"p5\"><br></p>
152 var method, name, args, def, txt, ex, default ;
153 cmDict.keys.asArray.sort.do({ arg key ;
155 method = cmDict[key][0] ;
158 <p class=\"p6\"><b><span class=\"Apple-tab-span\"> </span>name</b></p>
159 " .replace("name", "*"++name+this.makeName(method)) ;
160 if ( cmDict[key][1] != "", {classMethods = classMethods + methodTitle }) ;
161 args = cmDict[key][1].split($\n).reject({|i| i.size < 2}) ;
162 args[..args.size-2].do({ arg line ;
163 case { line.contains("desc:") }
164 { def = line.split($:)[0] ;
165 txt = line.split($:)[1] ;
166 classMethods = classMethods + "
167 <p class=\"p6\"><b><span class=\"Apple-tab-span\"> </span><span class=\"Apple-tab-span\"> </span></b>desc</p>
168 " .replace("desc", txt)
170 { line.contains("ex:") }
172 def = line.split($:)[0] ;
173 txt = line.split($:)[1] ;
174 classMethods = classMethods +
176 <p class=\"p7\"><span class=\"Apple-tab-span\"> </span><span class=\"Apple-tab-span\"> </span></p>
177 <p class=\"p9\"><span class=\"s4\"><span class=\"Apple-tab-span\"> </span><span class=\"Apple-tab-span\"> </span></span>// Example</p>
178 <p class=\"p10\"><span class=\"Apple-tab-span\"> </span><span class=\"Apple-tab-span\"> </span>ex</p>
183 { line.contains("desc:").not && isEx }
184 { classMethods = classMethods +
185 "<p class=\"p10\"><span class=\"Apple-tab-span\"> </span><span class=\"Apple-tab-span\"> </span>ex</p>"
189 { line.contains("desc:").not }
191 def = line.split($:)[0] ;
192 default = this.getDefault(method, def) ;
193 txt = line.split($:)[1] ;
194 classMethods = classMethods +
196 <p class=\"p8\"><span class=\"Apple-tab-span\"> </span><span class=\"Apple-tab-span\"> </span><b>def </b>- txt. Default value is dfv.</p>
197 " .replace("def", def)
198 .replace("txt", txt).replace("dfv", default);
203 ^(classMethods+"<p class=\"p5\"><br></p>\n")
208 makeName { arg method ;
209 var name = method.argumentString.replace("this, ", "").split($,)
210 .collect({ arg i ; i.split($=)[0]}).asString ;
211 ^"("++name[2..name.size-3]++")"
215 getDefault { arg method, name ;
216 var mString = method.argumentString.replace(" ", "") ;
219 name = name.reject( { arg i; i.isAlphaNum.not } ) ;
220 pos = mString.find(name) ;
222 next = mString[pos+name.size] ;
223 if (next == $=, { mString = mString[pos+name.size..].split($=)[1] ;
224 ^mString = mString.split($,)[0] },
229 createInstanceMethodBlock {
230 var isEx, methodTitle ;
231 var instanceMethods = "<p class=\"p11\"><b>instDesc</b></p>
232 <p class=\"p12\"><br></p>
233 <p class=\"p6\">longInstDesc</p>
234 <p class=\"p7\"><span class=\"Apple-tab-span\"> </span></p>
235 " .replace("instDesc", instDesc)
236 .replace("longInstDesc", longInstDesc)
238 var method, name, args, def, txt, ex, default ;
239 imDict.keys.asArray.sort.do({ arg key ;
241 method = imDict[key][0] ;
243 methodTitle = "<p class=\"p5\"><br></p>\n"+
245 <p class=\"p6\"><b><span class=\"Apple-tab-span\"> </span>name</b></p>
246 " .replace("name", name++" "++this.makeName(method)) ;
247 if ( imDict[key][1] != "", { instanceMethods = instanceMethods + methodTitle }) ;
248 args = imDict[key][1].split($\n).reject({|i| i.size < 2}) ;
249 args[..args.size-2].do({ arg line ;
250 case { line.contains("desc:") }
251 { def = line.split($:)[0] ;
252 txt = line.split($:)[1] ;
253 instanceMethods = instanceMethods + "
254 <p class=\"p6\"><b><span class=\"Apple-tab-span\"> </span><span class=\"Apple-tab-span\"> </span></b>desc</p>
255 " .replace("desc", txt)
257 { line.contains("ex:") }
259 def = line.split($:)[0] ;
260 txt = line.split($:)[1] ;
261 instanceMethods = instanceMethods +
263 <p class=\"p7\"><span class=\"Apple-tab-span\"> </span><span class=\"Apple-tab-span\"> </span></p>
264 <p class=\"p9\"><span class=\"s4\"><span class=\"Apple-tab-span\"> </span><span class=\"Apple-tab-span\"> </span></span>// Example</p>
265 <p class=\"p10\"><span class=\"Apple-tab-span\"> </span><span class=\"Apple-tab-span\"> </span>ex</p>
270 { line.contains("desc:").not && isEx }
272 instanceMethods = instanceMethods +
273 "<p class=\"p10\"><span class=\"Apple-tab-span\"> </span><span class=\"Apple-tab-span\"> </span>ex</p>"
278 { line.contains("desc:").not }
279 { def = line.split($:)[0] ; default = this.getDefault(method, def) ;
280 txt = line.split($:)[1] ;
281 instanceMethods = instanceMethods +
283 <p class=\"p8\"><span class=\"Apple-tab-span\"> </span><span class=\"Apple-tab-span\"> </span><b>def </b>- txt. Default value is dfv.</p>
284 " .replace("def", def).replace("txt", txt).replace("dfv", default);
289 ^(instanceMethods+"<p class=\"p5\"><br></p>\n")
293 createClassDocBlock {
294 var args = classDoc.split($\n).reject({|i| i.size < 2}) ;
296 case { line.contains("shortDesc:") }
297 { shortDesc = line.split($:)[1] ; }
298 { line.contains("longDesc:") }
299 { longDesc = line.split($:)[1] ; }
300 { line.contains("seeAlso:") }
301 { seeAlso = line.split($:)[1] ; }
302 { line.contains("issues:") }
303 { issues = line.split($:)[1] ; }
304 { line.contains("instDesc:") }
305 { instDesc = line.split($:)[1] ; }
306 { line.contains("longInstDesc:") }
307 { longInstDesc = line.split($:)[1] ; }
308 // residual: allows to create the varDict
309 { line.contains("longInstDesc:").not }
310 { varDict.add( line.split($:)[0]
311 .select({|i| i.isAlphaNum })
313 -> line.split($:)[1] ); }
318 createGetterSetterBlock {
319 var getterSetterBlock = "
320 <p class=\"p11\"><b>Accessing Instance and Class Variables</b></p>
321 <p class=\"p7\"><span class=\"Apple-tab-span\"> </span></p>
323 var getters = parser.getters.collect(_.name) ;
324 var setters = parser.setters.collect(_.name) ;
325 var name, comment, line ;
326 varDict.keys.do({ arg key ;
327 comment = varDict[key] ;
329 line = if ( getters.includes(key), {
331 <p class=\"p6\"><b><span class=\"Apple-tab-span\"> </span>someVar</b></p>
332 " .replace("someVar", key.asString)
334 if ( setters.includes((key++"_").asSymbol), { line = line +
336 <p class=\"p6\"><b><span class=\"Apple-tab-span\"> </span>someVar_</b></p>
337 " .replace("someVar", key.asString)
339 if ( class.classVarNames.includes(key), { line = line +
341 <p class=\"p6\"><b><span class=\"Apple-tab-span\"> </span>someVar</b></p>
342 " .replace("someVar", key.asString)
345 getterSetterBlock = getterSetterBlock + line +
347 <p class=\"p7\"><b><span class=\"Apple-tab-span\"> </span></b><span class=\"Apple-tab-span\"> </span></p>
348 <p class=\"p6\"><span class=\"Apple-tab-span\"> </span><span class=\"Apple-tab-span\"> </span>"+comment+"</p>
349 <p class=\"p7\"><span class=\"Apple-tab-span\"> </span><span class=\"Apple-tab-span\"> </span><span class=\"Apple-tab-span\"> </span><span class=\"Apple-tab-span\"> </span></p>