-- <<<- ------------------------------------------------------------------------ ------------------------------------------------------------------------ -- Make a cross indexed HTML web of all classes and generics. -- Don Hopkins, Kaleida Labs ------------------------------------------------------------------------ ------------------------------------------------------------------------ -- Subdue the garbage collector. -- Set phasers on stun. setGCIncrement 3 ------------------------------------------------------------------------ ------------------------------------------------------------------------ -- Setup the Web module. open TitleContainer \ dir: theScriptDir \ path: "web.sxl" in module Web ------------------------------------------------------------------------ ------------------------------------------------------------------------ -- Initialize globals. -- This is the directory where all the html files will be written. global outDir := spawn theScriptDir "sxmap" -- This is a hash table mapping from objects to their URL's, for which -- we're going to make corresponding web pages. We must give all objects -- meaningless identification numbers so their names fit in 8.3 filenames. global theURL := new HashTable -- Start the object id counter at big number with lots of zeros. global objectID := 10000 -- This is a sorted array of classes, that we're going to map. -- Ignore the meta classes, since there's one for every class, -- so they aren't very interesting. global theClasses := new SortedArray ( local allClasses := allinstances Behavior for cl in allClasses do ( if (not (isAKindOf cl MetaClass)) do ( append theClasses cl ) ) ) -- Assign a unique URL to each class. forEach theClasses (cl xxx -> theURL[cl as NameClass] := "c" + (objectID as String) + ".html" objectID := objectID + 1 ) ok -- This is a sorted array of generics, that we're going to map. global theGenerics := (allinstances Generic | SortedArray) -- Reset the object id counter, which is ok because the "c" and "g" -- prefixes make the URL's unique. We just do this to get a count of the -- number of classes and generics mapped. objectID := 10000 -- Assign a unique URL to each generic. forEach theGenerics (gen xxx -> theURL[gen as NameClass] := "g" + (objectID as String) + ".html" objectID := objectID + 1 ) ok ------------------------------------------------------------------------ -- This is a web page that describes and links to the class and generic indexes. global theIndexLegend := object (WebPage) title: "ScriptX Index Legend" contents object (WebHeading) level: 1 contents "ScriptX Index Legend" end "See also: " object (WebList) contents object (WebLink) url: "classes.html" -- Link to class index. contents "ScriptX Class Index" end object (WebLink) url: "generics.html" -- Link to generic index. contents "ScriptX Generic Index" end end object (WebParagraph) end -- Paragraph break. object (WebGroup) contents "This is a cross-indexed web of ScriptX classes and generics. " "There is an index of " object (WebLink) url: "classes.html" -- Link to class index. contents "every class" end " and " object (WebLink) url: "generics.html" -- Link to generic index. contents "every generic" end "." "There is a web page for each class, and for each generic. " "For example, here is a link to the " object (WebLink) url: theURL[@RootObject] -- Link to RootObject URL. contents "RootObject" end " class, and here is a link to the " object (WebLink) url: theURL["init()" as NameClass] -- Link to init() URL. contents "init()" end " generic. " object (WebParagraph) end -- Paragraph break. "This index contains a total of " (size theClasses) as String " classes and " (size theGenerics) as String " generics, including the ScriptX core classes and the " object (WebLink) url: theURL[@WebElement] -- Link to WebElement URL. contents "WebElement" end " classes used to render these web pages. " object (WebParagraph) end -- Paragraph break. "On the class pages, the names of direct superclasses and " "direct generics are displayed as " object (WebBold) contents "bold" end " text. " "Other indirectly inherited names are are displayed as " "normal text. " end end -- This is a web page that makes an index of classes. global theClassIndex := object (WebPage) title: "ScriptX Class Index" contents object (WebHeading) level: 1 contents "ScriptX Class Index" end "See also: " object (WebList) contents object (WebLink) url: "index.html" -- Link to index legend. contents "ScriptX Index Legend" end object (WebLink) url: "generics.html" -- Link to generic index. contents "ScriptX Generic Index" end end object (WebParagraph) end -- Paragraph break. -- This is a macro that dynamically expands into an index of -- theClasses, by returning a list of links. object (WebMacro) func: (self stream props -> -- Make a list of links to each class. for theClass in theClasses collect as WebList ( local className := theClass as NameClass -- Make a link to the class's URL. object (WebLink) url: theURL[className] -- Link to class URL. contents className -- Link from class name. end ) ) end end ------------------------------------------------------------------------ -- This is a web page that makes an index of generics. global theGenericIndex := object (WebPage) title: "ScriptX Generic Index" contents object (WebHeading) level: 1 contents "ScriptX Generic Index" end "See also: " object (WebList) contents object (WebLink) url: "index.html" -- Link to index legend. contents "ScriptX Index Legend" end object (WebLink) url: "classes.html" -- Link to class index. contents "ScriptX Class Index" end end object (WebParagraph) end -- Paragraph break. -- This is a macro that dynamically expands into an index of -- theGenerics, by returning a list of links. object (WebMacro) func: (self stream props -> -- Make a list of links to each class. for gen in theGenerics collect as WebList ( local genericName := (gen as String) as NameClass -- Make a link to the generic's URL. object (WebLink) url: theURL[genericName] -- Link to generic URL. contents genericName -- Link from generic name. end ) ) end end ------------------------------------------------------------------------ -- This is a web page that makes a map of a class, which must be passed in -- to printHTML as props[@class]. global theClassPage := object (WebPage) -- The title is a macro that dynamically contains the class name. title: object (WebMacro) func: (self stream props -> self[1] + (props[@class] as String) ) contents "ScriptX Class " end contents object (WebHeading) level: 1 contents -- The heading dynamically contains the class name, too. object (WebMacro) func: (self stream props -> "ScriptX Class " + (props[@class] as String) ) end end -- Link back up to the indexes. "See also: " object (WebList) contents object (WebLink) url: "index.html" -- Link to index legend. contents "ScriptX Index Legend" end object (WebLink) url: "classes.html" -- Link to class index. contents "ScriptX Class Index" end object (WebLink) url: "generics.html" -- Link to generic index. contents "ScriptX Generic Index" end end object (WebHeading) level: 2 contents "Superclasses" end -- This is a macro that dynamically expands into a list of all -- superclasses of and including the class, passed in as props[@class]. -- The direct superclasses are displayed in bold. If the superclass -- is being mapped, then its name is linked to its URL. object (WebMacro) func: (self stream props -> local cl := props[@class] -- Class to map. local supers := getSupers cl -- Array of all superclasses. prepend supers cl -- Add cl at end. local direct := getDirectSupers cl -- Array of direct supers. local classList := new WebList -- Make a list of superclasses. -- Loop backwards over superclasses, from RootObject to cl, -- and add them to the list in that order. forEachBackwards supers (sup xxx -> local supName := sup as NameClass local result := supName -- Make direct superclasses bold. if (isMember direct sup) do ( -- Tuck the result inside a bold group. result := object (WebBold) contents result end ) -- If the superclass is being mapped, then link to it. local url := theURL[supName] if (url != empty) do ( -- Tuck the result inside a link to the superclass's URL. result := object (WebLink) url: url contents result end ) -- Add the superclass to the class list. append classList result ) ok classList ) end object (WebHeading) level: 2 contents "Subclasses" end -- This is a macro that dynamically expands into a list of all -- direct subclasses of the class, passed in as props[@class]. -- If the subclass is being mapped, then its name is linked to its URL. object (WebMacro) func: (self stream props -> local cl := props[@class] -- Class to map. local subs := (getDirectSubs cl) | SortedArray -- Sorted subs. -- Make a list of each direct subclass. for subclass in subs collect as WebList ( local className := subclass as NameClass local result := className -- If the subclass is being mapped, then link to its URL. local url := theURL[className] if (url != empty) do ( -- Wrap the result up in a link. result := object (WebLink) url: url -- Link to class URL. contents result -- Link from class name. end ) -- Return the result to collecting loop, -- which adds it to the list. result ) ) end object (WebHeading) level: 2 contents "Generics" end -- This is a macro that dynamically expands into a list of all -- generics of the class, passed in as props[@class]. -- The direct generics are displayed in bold. If the generic -- is being mapped, then its name is linked to its URL. object (WebMacro) func: (self stream props -> local cl := props[@class] -- Class to map. local supers := getSupers cl -- Array of all superclasses. prepend supers cl -- Add cl at end. local gens := (getAllGenerics cl) | SortedArray -- All generics. local direct := getDirectGenerics cl -- Direct generics. -- Make a bulleted list of all generics, with directly defined -- generics in bold. Each generic is followed by a list of -- the superclasses in which it's defined. The list is -- returned as the macro expansion. for gen in gens collect as WebBulletedList ( local classList := new WebList -- List of defining classes. local genName := (gen as String) as NameClass local result := genName -- If the generic is directly defined in cl, then display -- the result in bold. if (isMember direct gen) do ( result := object (WebBold) contents result end ) -- Make a list of superclasses of and including cl that -- define this generic. for super in supers do ( if ((methodBinding super gen) != undefined) do ( -- Link to the superclass defining this generic. local superName := super as NameClass local superLink := object (WebLink) url: theURL[superName] contents superName end -- Add it to the list of defining classes. append classList superLink ) ) -- Make a group for each bullet of the list of generics. object (WebGroup) contents -- Make a link to the generic's URL. object (WebLink) url: theURL[genName] contents result -- The possibly bold generic name. end " defined in " classList -- The list of defining superclasses. end ) ) end end ------------------------------------------------------------------------ -- This is a web page that makes a map of a generic, which must be passed in -- to printHTML as props[@generic]. global theGenericPage := object (WebPage) -- The title is a macro that dynamically contains the generic name. title: object (WebMacro) func: (self stream props -> self[1] + (props[@generic] as String) ) contents "ScriptX Generic " end contents object (WebHeading) level: 1 contents -- The heading dynamically contains the generic name, too. object (WebMacro) func: (self stream props -> "ScriptX Generic " + (props[@generic] as String) ) end end -- Link back up to the indexes. "See also: " object (WebList) contents object (WebLink) url: "index.html" -- Link to index legend. contents "ScriptX Index Legend" end object (WebLink) url: "classes.html" -- Link to class index. contents "ScriptX Class Index" end object (WebLink) url: "generics.html" -- Link to generic index. contents "ScriptX Generic Index" end end object (WebHeading) level: 2 contents "Defining Classes" end -- This is a macro that dynamically expands to a list of every -- class that defines this generic, linking to that class's URL -- if it's being mapped. object (WebMacro) func: (self stream props -> local gen := props[@generic] -- Generic to map. local genName := (gen as String) as NameClass local classList := new WebList -- List of defining classes. -- Loop over every class, and for each one that defines this -- generic, make a link to the class's URL. for cl in theClasses do ( if ((methodBinding cl gen) != undefined) do ( local className := cl as NameClass local url := theURL[className] -- Make a link to the class's URL, if it's being mapped. if (url != empty) do ( local classLink := object (WebLink) url: url -- Link to class URL. contents className -- Link from class name. end -- Add the link to the list of defining classes. append classList classLink ) ) ) -- Return the list of defining classes as the macro expansion. classList ) end end ------------------------------------------------------------------------ ------------------------------------------------------------------------ -- Utilities -- Render a web page as a string of html, create a new file, -- and write the html onto disk. function writePage page dir fileName props -> ( print #("Rendering", fileName, getClass page, props) local html := new String printHTML page html props -- Stomp on any old files. if (isFile dir fileName) do ( delete dir fileName ) createFile dir fileName @text -- Write the string of html out to the file. local str := getStream dir fileName @writable writeString str html plug str ) ------------------------------------------------------------------------ ------------------------------------------------------------------------ -- Processing. if false do ( -- Render and save the index legend. writePage theIndexLegend outDir "index.html" #(:) -- Render and save the index of classes. writePage theClassIndex outDir "classes.html" #(:) -- Render and save the index of generics. writePage theGenericIndex outDir "generics.html" #(:) -- Render and save each class map. for cl in theClasses do ( writePage theClassPage outDir theURL[cl as NameClass] #(@class: cl) ) ) -- Render and save each generic map. for gen in theGenerics do ( writePage theGenericPage outDir theURL[gen as NameClass] #(@generic: gen) ) ------------------------------------------------------------------------ ------------------------------------------------------------------------ -- We're all done! Now browse "sxmap/classes.html" and "sxmap/generics.html"! -- Be careful, there are a LOT of files in the sxmap directory. ok -- >>>