Attachment 'uml2ascii-2004.py'

Download

   1 #format python
   2 """
   3    MoinMoin Processor to create Simple ASCII UML Diagrams 
   4    release 0.2.20040202
   5    Senya Basin, 1998-2004
   6 """
   7 import re,sys,string,pprint
   8 USAGE =""" UML2ASCII Usage:
   9    {{{#!uml2ascii [Options]
  10       Diagram DDL
  11    }}}
  12 ----------------------------------------------------------- 
  13    DDL Sample:
  14        [Box 1] -> [Box2] -(3,1)- [Box 3]
  15        [Box 4|...two liner...] -> --(2,)-- [Box 5.hvc=///]
  16 
  17    Box format:   [pos_x, pos_y, text, attr]
  18     pos_x      - column position of the box (optional, auto-incremented by default)
  19     pos_y      - row position of the box (optional, auto-incremented with new-line by default)
  20     text       - text to display in the box. Required. Use "|" for multi-line text. Use "|-|" for divider.
  21     attr       - Optional attributes:
  22                  hvc=... : use alternative characters: Horizontal, Vertical and Corner.
  23     Box samples: [Box1] [Class Point|-|int getX()|int getY()|void setX(int)|void setY(int)] [1,5,Box at cell 1:5]
  24 
  25    Link format:  START_CHAR -* FROM_TO -* END_CHAR
  26     START_CHAR - starting character. Required. 
  27     END_CHAR   - ending character. Required. 
  28     FROM_TO    - (id_from, id_to). Optional. From previous to next by default.
  29     id_from    - Box ID from which the links starts. Optional. Previous box by default.
  30     id_to      - Box ID to which the link goes. Optional. Next box by default.
  31     Link samples: -> <-> -- <> -(2,5)-> -(,7)->
  32 
  33    Options:
  34     fg:color   - diagram color
  35     dx:value   - minimum horizontal gap
  36     dy:value   - minimum vertical gap
  37     nn:        - print box IDs
  38 """
  39 H_CHAR = '-'
  40 V_CHAR = '|'
  41 C_CHAR = '+'
  42 class UMLAsciiDiagram:
  43     def __init__(self):
  44         self.pos_x  = 0
  45         self.pos_y  = 0
  46         self.obj_id = 0
  47         self.tab_nx = 0
  48         self.tab_ny = 0
  49         self.boxes       = {}
  50         self.links_from  = {}
  51         self.cols_width  = {}
  52         self.rows_height = {}
  53         self.cols_start  = []
  54         self.rows_start  = []
  55         self.DEBUG = 0
  56         self.fgcolor = 'black'
  57         self.DX = 5
  58         self.DY = 3
  59         self.NN = 0
  60 
  61     def parse_params(s, args):
  62         m = re.match('.*(fgcolor|fg):(\S+).*', args, re.I)
  63         if m:
  64             s.fgcolor = m.group(2)
  65         m = re.match('.*DY:(\d+)\s.*', args, re.I)
  66         if m:
  67             s.DY = int(m.group(1))
  68         m = re.match('.*DX:(\d+)\s.*', args, re.I)
  69         if m:
  70             s.DX = int(m.group(1))
  71         if re.match('.*NN:.*', args, re.I):
  72             s.NN = 1
  73         if re.match('.*DEBUG:.*', args, re.I):
  74             s.DEBUG = 1
  75 
  76     def pdebug(s, *args):
  77         if s.DEBUG: print 'DEBUG: ', args, '<br>'
  78 
  79     def parse_ddl(s, args):
  80         re_box  = re.compile(r'\[(\d*),?(\d*),?"?(.*?)\s*?"?,?(\w*?=.*?)?\]')
  81         re_link = re.compile(r'(\s?[<-])[-(]*(\d*),?(\d*)[-)]*([->])\s?')
  82 
  83         if re.match('^\s*$', args):
  84             return 0
  85 
  86         rc = 0
  87         s.pos_y += 1
  88         s.pos_x = 0
  89 
  90         for tok in re.findall('\[.*?\]|[<-].*?[->]\s', args):
  91            #s.pdebug("parsed TOKEN:", tok)
  92            if re.match('\[\]', tok):
  93                s.pos_x += 1
  94                continue
  95             
  96            m = re_box.match(tok)
  97            if m:
  98                (x,y,text,attr) = m.group(1,2,3,4)
  99                s.add_box(x, y, text, attr)
 100                rc = 1
 101             
 102            m = re_link.match(tok)
 103            if m:
 104                (fr,to,start,end) = m.group(2,3,1,4)
 105                s.add_link(fr, to, start.strip(), end.strip())
 106 
 107         return rc
 108 
 109     def add_box(s, x='', y='', text='', attr='', id=None):
 110 
 111         s.obj_id = parse_int(id, s.obj_id + 1)
 112         s.pos_x  = parse_int(x, s.pos_x + 1)
 113         s.pos_y  = parse_int(y, s.pos_y)
 114 
 115         hvc = ''
 116         if attr:
 117             m = re.match('hvc=(...)', attr)    
 118             if m: hvc = m.group(1)
 119             m = re.match('id=(\d+)', attr)    
 120             if m: s.obj_id = m.group(1)
 121         
 122         s.pdebug('BOX: x=', s.pos_x, '; y=', s.pos_y,
 123                  "; text='",text,"'; hvc=",hvc,"; id=",s.obj_id)
 124 
 125         (width, lines) = make_textbox(text, hvc)
 126         height = len(lines)
 127         s.boxes[s.obj_id] = (s.obj_id, s.pos_x, s.pos_y, text, attr, width, height, lines)
 128 
 129         if not s.cols_width.has_key(s.pos_x) or width > s.cols_width[s.pos_x]:
 130             s.cols_width[s.pos_x] = width
 131 
 132         if not s.rows_height.has_key(s.pos_y) or height > s.rows_height[s.pos_y]:
 133             s.rows_height[s.pos_y] = height
 134 
 135     def add_link(s, from_id='', to_id='', start=H_CHAR, end=H_CHAR, attr=None):
 136         from_id = parse_int(from_id, s.obj_id)
 137         to_id   = parse_int(to_id, s.obj_id + 1)
 138 
 139         if not s.links_from.has_key(from_id):
 140             s.links_from[from_id] = []
 141 
 142         links = s.links_from[from_id]
 143         links.append([from_id, to_id, start, end, attr])
 144         s.pdebug ("LINK: from=",from_id," to=",to_id," link=\""+start+end+"\" attr=",attr)
 145 
 146     def define_geometry(s):
 147         s.tab_nx = len(s.cols_width.keys())
 148         s.tab_ny = len(s.rows_height.keys())
 149 
 150         for i in range(s.tab_nx + 1):
 151             s.cols_start.append(0)
 152 
 153         for i in range(2, s.tab_nx + 1):
 154             s.cols_start[i] = s.cols_start[i-1] + s.cols_width[i-1] + s.DX;
 155 
 156         for i in range(s.tab_ny + 1):
 157             s.rows_start.append(0)
 158 
 159         for i in range(2, s.tab_ny + 1):
 160             s.rows_start[i] = s.rows_start[i-1] + s.rows_height[i-1] + s.DY;
 161 
 162         return s.tab_nx * s.tab_ny
 163 
 164     def draw_box(s, screen, box_id):
 165         (box_id, tx, ty, text, attr, width, height, lines) = s.boxes[box_id]
 166         for j in range(height):
 167             yy = s.rows_start[ty] + j
 168             for i in range(width):
 169                 xx = s.cols_start[tx] + i
 170                 screen[yy][xx] = lines[j][i]
 171         if s.NN:
 172             sid = repr(box_id)
 173             for i in range(len(sid)):
 174                 screen[s.rows_start[ty]][s.cols_start[tx] + i] = sid[i]
 175 
 176     def draw_hline (s, screen, x1, x2, y, c_start, c_end):
 177         for x in range(x1, x2):
 178             screen[y][x] = H_CHAR
 179             
 180         if c_start: screen[y][x1] = c_start
 181         if c_end: screen[y][x2-1] = c_end
 182 
 183     def draw_h2line (s, screen, x1, x2, y, c_start, c_end):
 184         s.draw_hline(screen, x1, x2+2, y+1, c_start, c_end)
 185         screen[y][x1]     = V_CHAR
 186         screen[y+1][x1]   = C_CHAR
 187         screen[y][x2+1]   = V_CHAR
 188         screen[y+1][x2+1] = C_CHAR
 189 
 190     def draw_vline (s, screen, x, y1, y2, c_vert=V_CHAR):
 191         for y in range(y1, y2):
 192             screen[y][x] = c_vert
 193 
 194     def draw_link(s, screen, link):
 195         (fr, to, start, end, attr) = link
 196 
 197         (box_id1, tx1, ty1, undef, undef, w1, h1, undef) = s.boxes[fr]
 198         if not box_id1:
 199             return
 200 
 201         (box_id2, tx2, ty2, undef, undef, w2, h2, undef) = s.boxes[to]
 202         if not box_id2:
 203             return
 204 
 205         if ( (ty1 - ty2) == 0):
 206             if (abs(tx2 - tx1) == 1):
 207                 if (tx1 < tx2):
 208                     x1 = s.cols_start[tx1] + w1
 209                     x2 = s.cols_start[tx2]
 210                 else:
 211                     x1 = s.cols_start[tx2] + w1
 212                     x2 = s.cols_start[tx1]
 213 
 214                 h = h2//2
 215                 if h1 < h2: h = h1//2
 216                 s.draw_hline(screen, x1, x2, s.rows_start[ty1] + h, start, end)
 217             
 218             elif (abs(tx2 - tx1) > 1):
 219                 if (tx1 < tx2):
 220                     x1 = s.cols_start[tx1] + w1//2
 221                     x2 = s.cols_start[tx2] + w2//2 - 1
 222                 else:
 223                     x1 = s.cols_start[tx2] + w2//2
 224                     x2 = s.cols_start[tx1] + w1//2 - 1
 225 
 226                 h = h1
 227                 if h1 < h2: h2
 228                 s.draw_h2line(screen, x1, x2, s.rows_start[ty1] + h, start, end)
 229 
 230         elif ((tx1 - tx2)==0 and abs(ty2 - ty1)==1):
 231             if (ty1 < ty2):
 232                 y1 = s.rows_start[ty1] + s.rows_height[ty1]
 233                 y2 = s.rows_start[ty2]
 234             else:
 235                 y1 = s.rows_start[ty2] + s.rows_height[ty2]
 236                 y2 = s.rows_start[ty1]
 237 
 238             w = w2//2
 239             if w1 < w2: w = w1//2
 240             s.draw_vline(screen, s.cols_start[tx1] + w, y1, y2)
 241 
 242         else:
 243             if (tx1 < tx2):
 244                 x1 = s.cols_start[tx1] + w1
 245                 x2 = s.cols_start[tx2]
 246             else:
 247                 x1 = s.cols_start[tx2] + w1
 248                 x2 = s.cols_start[tx1]
 249             
 250             if (ty1 < ty2):
 251                 y1 = s.rows_start[ty1] + h1//2
 252                 y2 = s.rows_start[ty2] + h2//2
 253             else:
 254                 y1 = s.rows_start[ty2] + h2//2
 255                 y2 = s.rows_start[ty1] + h1//2
 256 
 257             w = s.DX//2
 258             s.draw_hline(screen, x1, x1 + w, y1, start, H_CHAR)
 259             s.draw_vline(screen, x1 + w, y1, y2)
 260             s.draw_hline(screen, x1 + w, x2, y2, H_CHAR, end)
 261 
 262     def draw_diagram(s):
 263         screen_w = s.cols_start[s.tab_nx] + s.cols_width[s.tab_nx]
 264         screen_h = s.rows_start[s.tab_ny] + s.rows_height[s.tab_ny]
 265         screen = []
 266         while screen_h > 0:
 267             screen.append(map(lambda x: ' ', range(screen_w)))
 268             screen_h -= 1
 269 
 270         for links in s.links_from.values():
 271             for link in links:
 272                 s.draw_link(screen, link)
 273 
 274         for box_id in  s.boxes.keys():
 275             s.draw_box(screen, box_id)
 276 
 277         return print_screen(screen)    
 278 
 279 #################################################################
 280 def make_line(l, hch=H_CHAR, cch=C_CHAR):
 281     sline = cch
 282     while l > 2:
 283         l, sline = l-1, sline + hch
 284     return sline + cch
 285     
 286 def frame_text (text, vch=V_CHAR):
 287         
 288     lines = text.split(V_CHAR);
 289     
 290     smax = 0
 291     for line in lines:
 292         if len(line) > smax: smax = len(line) 
 293         
 294     for i in range(len(lines)):
 295         ltmp = vch + ' ' + lines[i].ljust(smax) + ' ' + vch
 296         if re.match('\s*\-+\s*', lines[i]):
 297             lines[i] = ltmp.replace(' ','-')
 298         else:    
 299             lines[i] = ltmp
 300         
 301     return (smax + 4, lines)
 302         
 303 def make_textbox (text, symbols=''):
 304     if not symbols: symbols = H_CHAR + V_CHAR + C_CHAR
 305     hchar, vchar, cchar = symbols
 306 
 307     (width, lines) = frame_text(text, vchar);
 308 
 309     sline = make_line(width, hchar, cchar);
 310     lines.insert(0, sline)
 311     lines.append(sline)
 312     return (width, lines);
 313 
 314 
 315 def parse_int(val, dflt):
 316     if val:
 317         return int(val)
 318     else:
 319         return int(dflt)
 320 
 321 def print_screen(screen):
 322     rc = ''
 323     for j in range(len(screen)):
 324         for i in range(len(screen[j])):
 325             rc += screen[j][i]
 326         rc += '\n'
 327     return rc    
 328 
 329 #################################################################
 330 def process(request, formatter, lines):
 331     try:
 332         ad = UMLAsciiDiagram()
 333         ad.parse_params(lines[0])
 334         del lines[0]
 335         
 336         rc = 0
 337         for line in lines:
 338             rc += ad.parse_ddl(line)
 339 
 340         if (rc > 0):
 341             ad.define_geometry()
 342             sb = ad.draw_diagram()
 343         else:
 344             sb = string.join(lines, '\n')
 345             sb = USAGE + sb
 346     except:
 347         raise
 348 
 349     sys.stdout.write(formatter.rawHTML('<font color=\"' + ad.fgcolor + '\">\n'))
 350     sys.stdout.write(formatter.rawHTML('<PRE class=code>'))
 351     sys.stdout.write(formatter.rawHTML(sb))
 352     sys.stdout.write(formatter.rawHTML('</PRE></font>'))
 353     return

Attached Files

To refer to attachments on a page, use attachment:filename, as shown below in the list of files. Do NOT use the URL of the [get] link, since this is subject to change and can break easily.
  • [get | view] (2007-04-16 19:34:05, 11.4 KB) [[attachment:uml2ascii-2004.py]]
  • [get | view] (2007-04-16 19:34:27, 13.5 KB) [[attachment:uml2ascii-moin16.py]]
 All files | Selected Files: delete move to page copy to page

You are not allowed to attach a file to this page.