Setting tag plcapi-5.4-2
[plcapi.git] / doc / DocBook.py
1 #!/usr/bin/python
2 #
3 # Generates a DocBook section documenting all PLCAPI methods on
4 # stdout.
5 #
6 # Mark Huang <mlhuang@cs.princeton.edu>
7 # Copyright (C) 2006 The Trustees of Princeton University
8 #
9
10 import xml.dom.minidom
11 from xml.dom.minidom import Element, Text
12 import codecs
13
14 from PLC.Parameter import Parameter, Mixed, xmlrpc_type, python_type
15
16 # xml.dom.minidom.Text.writexml adds surrounding whitespace to textual
17 # data when pretty-printing. Override this behavior.
18 class TrimText(Text):
19     """text"""
20     def __init__(self, text = None):
21         self.data = unicode(text)
22
23     def writexml(self, writer, indent="", addindent="", newl=""):
24         Text.writexml(self, writer, "", "", "")
25
26 class TrimTextElement(Element):
27     """<tagName>text</tagName>"""
28     def __init__(self, tagName, text = None):
29         Element.__init__(self, tagName)
30         if text is not None:
31             self.appendChild(TrimText(text))
32
33     def writexml(self, writer, indent="", addindent="", newl=""):
34         writer.write(indent)
35         Element.writexml(self, writer, "", "", "")
36         writer.write(newl)
37
38 class simpleElement(TrimTextElement): pass
39
40 class paraElement(simpleElement):
41     """<para>text</para>"""
42     def __init__(self, text = None):
43         simpleElement.__init__(self, 'para', text)
44
45 class blockquoteElement(Element):
46     """<blockquote><para>text...</para><para>...text</para></blockquote>"""
47     def __init__(self, text = None):
48         Element.__init__(self, 'blockquote')
49         if text is not None:
50             # Split on blank lines
51             lines = [line.strip() for line in text.strip().split("\n")]
52             lines = "\n".join(lines)
53             paragraphs = lines.split("\n\n")
54
55             for paragraph in paragraphs:
56                 self.appendChild(paraElement(paragraph))
57
58 def param_type(param):
59     """Return the XML-RPC type of a parameter."""
60     if isinstance(param, Mixed) and len(param):
61         subtypes = [param_type(subparam) for subparam in param]
62         return " or ".join(subtypes)
63     elif isinstance(param, (list, tuple, set)) and len(param):
64         return "array of " + " or ".join([param_type(subparam) for subparam in param])
65     else:
66         return xmlrpc_type(python_type(param))
67
68 class paramElement(Element):
69     """An optionally named parameter."""
70     def __init__(self, name, param):
71         # <listitem>
72         Element.__init__(self, 'listitem')
73
74         description = Element('para')
75
76         if name:
77             description.appendChild(simpleElement('parameter', name))
78             description.appendChild(TrimText(": "))
79
80         description.appendChild(TrimText(param_type(param)))
81
82         if isinstance(param, (list, tuple, set)) and len(param) == 1:
83             param = param[0]
84
85         if isinstance(param, Parameter):
86             description.appendChild(TrimText(", " + param.doc))
87             param = param.type
88
89         self.appendChild(description)
90
91         if isinstance(param, dict):
92             itemizedlist = Element('itemizedlist')
93             self.appendChild(itemizedlist)
94             for name, subparam in param.iteritems():
95                 itemizedlist.appendChild(paramElement(name, subparam))
96
97         elif isinstance(param, (list, tuple, set)) and len(param):
98             itemizedlist = Element('itemizedlist')
99             self.appendChild(itemizedlist)
100             for subparam in param:
101                 itemizedlist.appendChild(paramElement(None, subparam))
102
103 class DocBook:
104     
105     def __init__ (self,functions_list):
106         self.functions_list = functions_list
107
108     def Process (self):
109         
110         for func in self.functions_list:
111             method = func.name
112
113             if func.status == "deprecated":
114                 continue
115
116             (min_args, max_args, defaults) = func.args()
117
118             section = Element('section')
119             section.setAttribute('id', func.name)
120             section.appendChild(simpleElement('title', func.name))
121
122             prototype = "%s (%s)" % (method, ", ".join(max_args))
123             para = paraElement('Prototype:')
124             para.appendChild(blockquoteElement(prototype))
125             section.appendChild(para)
126
127             para = paraElement('Description:')
128             para.appendChild(blockquoteElement(func.__doc__))
129             section.appendChild(para)
130
131             para = paraElement('Allowed Roles:')
132             para.appendChild(blockquoteElement(", ".join(func.roles)))
133             section.appendChild(para)
134
135             section.appendChild(paraElement('Parameters:'))
136             params = Element('itemizedlist')
137             if func.accepts:
138                 for name, param, default in zip(max_args, func.accepts, defaults):
139                     params.appendChild(paramElement(name, param))
140             else:
141                 listitem = Element('listitem')
142                 listitem.appendChild(paraElement('None'))
143                 params.appendChild(listitem)
144             section.appendChild(params)
145
146             section.appendChild(paraElement('Returns:'))
147             returns = Element('itemizedlist')
148             returns.appendChild(paramElement(None, func.returns))
149             section.appendChild(returns)
150
151             print section.toprettyxml(encoding = "UTF-8")