haskell学习笔记:从Python源代码生成类图(继承关系图)
我想搞一个通过reST直接写论文的东东,想法如下:
![digraph name{
node[shape=box]
reST -> latex -> pdf
}](../../../_images/graphviz-0ff3b609d8e14a7a3e18489a96103668889b2ad4.png)
而现状是: 从latex到pdf有了 模板 ,而Sphinx或者直接docutils都可以生成pdf, 但还不能直接生成模板所需要的那个样子(主要是表格和插图引用有问题),所以想系统的学习下docutils的源代码好hack,找了一个旧版本的 Presentation ,把代码也从 sf.net 下面搞到本地了,然后搞明白其关键的数据结构是 文档树 也就是 nodes.py所定义的数据结构。
说了半天还没没有到正题,nodes.py有2205行,132个类定义,我想搞一个UML类图反映继承关系,正好用用这几天刚学的haskell来测试下。哦, 忘了提一个附加背景知识了, plantuml 利用 graphviz 可以通过文本 转换UML图,那么我的问题就分解为如何利用haskell来生成plantuml所需要的输入文本。
代码如下:
import Text.Regex
import Data.List(dropWhileEnd,isPrefixOf)
pytouml :: String -> String
pytouml = removeEmptyLines. unlines . map transform . (filter isclassdef) . lines where
removeEmptyLines = unlines. ( filter ("" /= ) ) . lines
isclassdef = ( "class " `isPrefixOf` )
transform = \line ->
let (classname, parents) = getClassNameAndParents line
in unlines $ map ( ( \x -> x ++ " <|-- " ++ myQuote classname ) . myQuote )
parents where
myQuote s = "\"" ++ s ++ "\""
getClassNameAndParents :: String -> (String, [String])
getClassNameAndParents s = let idpattern = "([a-zA-Z_][a-zA-Z0-9_]*)" in
let reclassname = mkRegex $ "^ *class +" ++ idpattern
in let m1 = matchRegexAll reclassname s in case m1 of
Nothing -> ("", [])
Just (_,_,after,m:_) ->
let classname = m
remaining = after
reparents = mkRegex " *(\\(.+\\))? *:" in
let m2 = matchRegex reparents remaining in case m2 of
Nothing -> ("", [])
Just [[]] -> (classname,[])
Just (m3:_) ->
let parents = splitRegex (mkRegex " *, *" ) .
dropWhileEnd (' ' ==) .
dropWhile (' ' == ) .init.tail $ m3
in (classname, parents)
利用GHCi生成output.txt:
*Main Text.Regex Data.List> :l ~/haskell/pytouml.hs
[1 of 1] Compiling Main ( /home/somebody/hasell/pytouml.hs, interpreted )
Ok, modules loaded: Main.
*Main Text.Regex Data.List> s <- readFile "nodes.py"
*Main Text.Regex Data.List> writeFile "out.txt" $ pytouml s
生成的UML效果图