blob: ecf2825ede1c266aa99066e5dd679d7713f615a7 [file] [log] [blame]
#
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License
#
"""Library for generating asciidoc documentation from a L{schema.Schema}"""
from collections import namedtuple
import sys
from .schema import quotestr
class SchemaWriter(object):
"""Write the schema as an asciidoc document"""
def __init__(self, output, schema, quiet=True):
self.output, self.schema, self.quiet = output, schema, quiet
self._heading = 0
# Options affecting how output is written
def warn(self, message):
if not self.quiet: print >>sys.stderr, message
def write(self, text): self.output.write(text)
def writeln(self, text=""): self.output.write(text+"\n")
def para(self, text): self.write(text+"\n\n")
def heading(self, text=None, sub=0):
self._heading += sub
if text: self.para("\n=%s %s" % ("="*self._heading, text))
class Section(namedtuple("Section", ["writer", "heading"])):
def __enter__(self): self.writer.heading(self.heading, sub=+1)
def __exit__(self, ex, value, trace): self.writer.heading(sub=-1)
def section(self, heading): return self.Section(self, heading)
def attribute_qualifiers(self, attr, show_create=True, show_update=True):
default = attr.default
if isinstance(default, basestring) and default.startswith('$'):
default = None # Don't show defaults that are references, confusing.
return ' (%s)' % (', '.join(
filter(None, [str(attr.atype),
default and "default=%s" % quotestr(default),
attr.required and "required",
attr.unique and "unique",
show_create and attr.create and "`CREATE`",
show_update and attr.update and "`UPDATE`"
])))
def attribute_type(self, attr, holder=None, show_create=True, show_update=True):
self.writeln("'%s'%s::" % (
attr.name, self.attribute_qualifiers(attr, show_create, show_update)))
if attr.description:
self.writeln(" %s" % attr.description)
else:
self.warn("Warning: No description for %s in %s" % (attr, attr.defined_in.short_name))
self.writeln()
def attribute_types(self, holder):
for attr in holder.my_attributes:
self.attribute_type(attr, holder)
def operation_def(self, op, holder):
def request_response(what):
message = getattr(op, what)
if message:
if message.body:
self.para(".%s body%s\n\n%s" % (
what.capitalize(), self.attribute_qualifiers(message.body),
message.body.description))
if message.properties:
self.para(".%s properties" % (what.capitalize()))
for prop in message.properties.itervalues():
self.attribute_type(prop)
with self.section("Operation %s" % op.name):
if op.description: self.para(op.description)
request_response("request")
request_response("response")
def operation_defs(self, entity_type):
for op in entity_type.operation_defs.itervalues():
self.operation_def(op, entity_type)
def entity_type(self, entity_type, operation_defs=True):
with self.section(entity_type.short_name):
if entity_type.description:
self.para('%s' % entity_type.description)
else:
self.warn("Warning no description for %s" % entity_type)
if entity_type.operations:
self.para("Operations allowed: `%s`\n\n" % "`, `".join(entity_type.operations))
self.attribute_types(entity_type)
if entity_type.operation_defs:
self.operation_defs(entity_type)
def entity_types_extending(self, base_name):
base = self.schema.entity_type(base_name)
for entity_type in self.schema.filter(lambda t: t.extends(base)):
self.entity_type(entity_type)