reportlab/lib/yaml.py
author andy_robinson
Tue, 06 Mar 2001 17:42:38 +0000
changeset 682 c4ae7b303888
child 817 8c3a399effda
permissions -rw-r--r--
Added
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
682
andy_robinson
parents:
diff changeset
     1
#copyright ReportLab Inc. 2000
andy_robinson
parents:
diff changeset
     2
#see license.txt for license details
andy_robinson
parents:
diff changeset
     3
#history http://cvs.sourceforge.net/cgi-bin/cvsweb.cgi/docs/tools/yaml.py?cvsroot=reportlab
andy_robinson
parents:
diff changeset
     4
#$Header: /tmp/reportlab/reportlab/lib/yaml.py,v 1.1 2001/03/06 17:42:38 andy_robinson Exp $
andy_robinson
parents:
diff changeset
     5
# parses "Yet Another Markup Language" into a list of tuples.
andy_robinson
parents:
diff changeset
     6
# Each tuple says what the data is e.g.
andy_robinson
parents:
diff changeset
     7
# ('Paragraph', 'Heading1', 'Why Reportlab Rules')
andy_robinson
parents:
diff changeset
     8
# and the pattern depends on type.
andy_robinson
parents:
diff changeset
     9
"""
andy_robinson
parents:
diff changeset
    10
.h1 Welcome to YAML!
andy_robinson
parents:
diff changeset
    11
YAML is "Yet Another Markup Language" - a markup language
andy_robinson
parents:
diff changeset
    12
which is easier to type in than XML, yet gives us a
andy_robinson
parents:
diff changeset
    13
reasonable selection of formats.
andy_robinson
parents:
diff changeset
    14
andy_robinson
parents:
diff changeset
    15
The general rule is that if a line begins with a '.',
andy_robinson
parents:
diff changeset
    16
it requires special processing. Otherwise lines
andy_robinson
parents:
diff changeset
    17
are concatenated to paragraphs, and blank lines
andy_robinson
parents:
diff changeset
    18
separate paragraphs. 
andy_robinson
parents:
diff changeset
    19
andy_robinson
parents:
diff changeset
    20
If the line ".foo bar bletch" is encountered,
andy_robinson
parents:
diff changeset
    21
it immediately ends and writes out any current
andy_robinson
parents:
diff changeset
    22
paragraph.
andy_robinson
parents:
diff changeset
    23
andy_robinson
parents:
diff changeset
    24
It then looks for a parser method called 'foo';
andy_robinson
parents:
diff changeset
    25
if found, it is called with arguments (bar, bletch).
andy_robinson
parents:
diff changeset
    26
andy_robinson
parents:
diff changeset
    27
If this is not found, it assumes that 'foo' is a
andy_robinson
parents:
diff changeset
    28
paragraph style, and the text for the first line
andy_robinson
parents:
diff changeset
    29
of the paragraph is 'bar bletch'.  It would be
andy_robinson
parents:
diff changeset
    30
up to the formatter to decide whether on not 'foo'
andy_robinson
parents:
diff changeset
    31
was a valid paragraph.
andy_robinson
parents:
diff changeset
    32
andy_robinson
parents:
diff changeset
    33
Special commands understood at present are:
andy_robinson
parents:
diff changeset
    34
dot image filename
andy_robinson
parents:
diff changeset
    35
- adds the image to the document
andy_robinson
parents:
diff changeset
    36
dot beginPre Code
andy_robinson
parents:
diff changeset
    37
- begins a Preformatted object in style 'Code'
andy_robinson
parents:
diff changeset
    38
dot endPre
andy_robinson
parents:
diff changeset
    39
- ends a preformatted object.
andy_robinson
parents:
diff changeset
    40
"""
andy_robinson
parents:
diff changeset
    41
andy_robinson
parents:
diff changeset
    42
andy_robinson
parents:
diff changeset
    43
import sys
andy_robinson
parents:
diff changeset
    44
import string
andy_robinson
parents:
diff changeset
    45
andy_robinson
parents:
diff changeset
    46
#modes:
andy_robinson
parents:
diff changeset
    47
PLAIN = 1
andy_robinson
parents:
diff changeset
    48
PREFORMATTED = 2
andy_robinson
parents:
diff changeset
    49
andy_robinson
parents:
diff changeset
    50
BULLETCHAR = '\267'  # assumes font Symbol, but works on all platforms
andy_robinson
parents:
diff changeset
    51
andy_robinson
parents:
diff changeset
    52
class BaseParser:
andy_robinson
parents:
diff changeset
    53
    """"Simplest possible parser with only the most basic options.
andy_robinson
parents:
diff changeset
    54
andy_robinson
parents:
diff changeset
    55
    This defines the line-handling abilities and basic mechanism.
andy_robinson
parents:
diff changeset
    56
    The class YAMLParser includes capabilities for a fairly rich
andy_robinson
parents:
diff changeset
    57
    story."""
andy_robinson
parents:
diff changeset
    58
    
andy_robinson
parents:
diff changeset
    59
    def __init__(self):
andy_robinson
parents:
diff changeset
    60
        self.reset()
andy_robinson
parents:
diff changeset
    61
        
andy_robinson
parents:
diff changeset
    62
    def reset(self):
andy_robinson
parents:
diff changeset
    63
        self._lineNo = 0
andy_robinson
parents:
diff changeset
    64
        self._style = 'Normal'  # the default
andy_robinson
parents:
diff changeset
    65
        self._results = []
andy_robinson
parents:
diff changeset
    66
        self._buf = []
andy_robinson
parents:
diff changeset
    67
        self._mode = PLAIN
andy_robinson
parents:
diff changeset
    68
        
andy_robinson
parents:
diff changeset
    69
    def parseFile(self, filename):
andy_robinson
parents:
diff changeset
    70
        #returns list of objects
andy_robinson
parents:
diff changeset
    71
        data = open(filename, 'r').readlines()
andy_robinson
parents:
diff changeset
    72
        
andy_robinson
parents:
diff changeset
    73
        for line in data:
andy_robinson
parents:
diff changeset
    74
            #strip trailing newlines
andy_robinson
parents:
diff changeset
    75
            self.readLine(line[:-1])
andy_robinson
parents:
diff changeset
    76
        self.endPara()
andy_robinson
parents:
diff changeset
    77
        return self._results
andy_robinson
parents:
diff changeset
    78
andy_robinson
parents:
diff changeset
    79
    def parseText(self, textBlock):
andy_robinson
parents:
diff changeset
    80
        "Parses the a possible multi-line text block"
andy_robinson
parents:
diff changeset
    81
        lines = string.split(textBlock, '\n')
andy_robinson
parents:
diff changeset
    82
        for line in lines:
andy_robinson
parents:
diff changeset
    83
            self.readLine(line)
andy_robinson
parents:
diff changeset
    84
        self.endPara()
andy_robinson
parents:
diff changeset
    85
        return self._results
andy_robinson
parents:
diff changeset
    86
    
andy_robinson
parents:
diff changeset
    87
    def readLine(self, line):    
andy_robinson
parents:
diff changeset
    88
        #this is the inner loop
andy_robinson
parents:
diff changeset
    89
        self._lineNo = self._lineNo + 1
andy_robinson
parents:
diff changeset
    90
        stripped = string.lstrip(line)
andy_robinson
parents:
diff changeset
    91
        if len(stripped) == 0:
andy_robinson
parents:
diff changeset
    92
            if self._mode == PLAIN:
andy_robinson
parents:
diff changeset
    93
                self.endPara()
andy_robinson
parents:
diff changeset
    94
            else:  #preformatted, append it
andy_robinson
parents:
diff changeset
    95
                self._buf.append(line)
andy_robinson
parents:
diff changeset
    96
        elif line[0]=='.':
andy_robinson
parents:
diff changeset
    97
            # we have a command of some kind
andy_robinson
parents:
diff changeset
    98
            self.endPara()
andy_robinson
parents:
diff changeset
    99
            words = string.split(stripped[1:])
andy_robinson
parents:
diff changeset
   100
            cmd, args = words[0], words[1:]
andy_robinson
parents:
diff changeset
   101
    
andy_robinson
parents:
diff changeset
   102
            #is it a parser method?
andy_robinson
parents:
diff changeset
   103
            if hasattr(self.__class__, cmd):
andy_robinson
parents:
diff changeset
   104
                method = eval('self.'+cmd)
andy_robinson
parents:
diff changeset
   105
                #this was very bad; any type error in the method was hidden
andy_robinson
parents:
diff changeset
   106
                #we have to hack the traceback
andy_robinson
parents:
diff changeset
   107
                try:
andy_robinson
parents:
diff changeset
   108
                    apply(method, tuple(args))
andy_robinson
parents:
diff changeset
   109
                except TypeError, err:
andy_robinson
parents:
diff changeset
   110
                    sys.stderr.write("Parser method: apply(%s,%s) %s at line %d\n" % (cmd, tuple(args), err, self._lineNo))
andy_robinson
parents:
diff changeset
   111
                    raise
andy_robinson
parents:
diff changeset
   112
            else:
andy_robinson
parents:
diff changeset
   113
                # assume it is a paragraph style -
andy_robinson
parents:
diff changeset
   114
                # becomes the formatter's problem
andy_robinson
parents:
diff changeset
   115
                self.endPara()  #end the last one
andy_robinson
parents:
diff changeset
   116
                words = string.split(stripped, ' ', 1)
andy_robinson
parents:
diff changeset
   117
                assert len(words)==2, "Style %s but no data at line %d" % (words[0], self._lineNo)
andy_robinson
parents:
diff changeset
   118
                (styletag, data) = words
andy_robinson
parents:
diff changeset
   119
                self._style = styletag[1:]
andy_robinson
parents:
diff changeset
   120
                self._buf.append(data)
andy_robinson
parents:
diff changeset
   121
        else:
andy_robinson
parents:
diff changeset
   122
            #we have data, add to para
andy_robinson
parents:
diff changeset
   123
            self._buf.append(line)            
andy_robinson
parents:
diff changeset
   124
andy_robinson
parents:
diff changeset
   125
    def endPara(self):
andy_robinson
parents:
diff changeset
   126
        #ends the current paragraph, or preformatted block
andy_robinson
parents:
diff changeset
   127
            
andy_robinson
parents:
diff changeset
   128
        text = string.join(self._buf, ' ')
andy_robinson
parents:
diff changeset
   129
        if text:
andy_robinson
parents:
diff changeset
   130
            if self._mode == PREFORMATTED:
andy_robinson
parents:
diff changeset
   131
                #item 3 is list of lines
andy_robinson
parents:
diff changeset
   132
                self._results.append(('PREFORMATTED', self._style,
andy_robinson
parents:
diff changeset
   133
                                 string.join(self._buf,'\n')))
andy_robinson
parents:
diff changeset
   134
            else:
andy_robinson
parents:
diff changeset
   135
                self._results.append(('PARAGRAPH', self._style, text))
andy_robinson
parents:
diff changeset
   136
        self._buf = []
andy_robinson
parents:
diff changeset
   137
        self._style = 'Normal'
andy_robinson
parents:
diff changeset
   138
andy_robinson
parents:
diff changeset
   139
    def beginPre(self, stylename):
andy_robinson
parents:
diff changeset
   140
        self._mode = PREFORMATTED
andy_robinson
parents:
diff changeset
   141
        self._style = stylename
andy_robinson
parents:
diff changeset
   142
        
andy_robinson
parents:
diff changeset
   143
    def endPre(self):
andy_robinson
parents:
diff changeset
   144
        self.endPara()
andy_robinson
parents:
diff changeset
   145
        self._mode = PLAIN
andy_robinson
parents:
diff changeset
   146
andy_robinson
parents:
diff changeset
   147
    def image(self, filename):
andy_robinson
parents:
diff changeset
   148
        self.endPara()
andy_robinson
parents:
diff changeset
   149
        self._results.append(('IMAGE', filename))
andy_robinson
parents:
diff changeset
   150
andy_robinson
parents:
diff changeset
   151
andy_robinson
parents:
diff changeset
   152
class Parser(BaseParser):
andy_robinson
parents:
diff changeset
   153
    """This adds a basic set of "story" components compatible with HTML & PDF.
andy_robinson
parents:
diff changeset
   154
andy_robinson
parents:
diff changeset
   155
    Images, spaces"""
andy_robinson
parents:
diff changeset
   156
andy_robinson
parents:
diff changeset
   157
    def vSpace(self, points):
andy_robinson
parents:
diff changeset
   158
        """Inserts a vertical spacer"""
andy_robinson
parents:
diff changeset
   159
        self._results.append(('VSpace', points))
andy_robinson
parents:
diff changeset
   160
        
andy_robinson
parents:
diff changeset
   161
    def pageBreak(self):
andy_robinson
parents:
diff changeset
   162
        """Inserts a frame break"""
andy_robinson
parents:
diff changeset
   163
        self._results.append(('PageBreak','blah'))  # must be a tuple
andy_robinson
parents:
diff changeset
   164
andy_robinson
parents:
diff changeset
   165
    def custom(self, moduleName, funcName):
andy_robinson
parents:
diff changeset
   166
        """Goes and gets the Python object and adds it to the story"""
andy_robinson
parents:
diff changeset
   167
        self.endPara()
andy_robinson
parents:
diff changeset
   168
        self._results.append(('Custom',moduleName, funcName))
andy_robinson
parents:
diff changeset
   169
andy_robinson
parents:
diff changeset
   170
    def nextPageTemplate(self, templateName):
andy_robinson
parents:
diff changeset
   171
        self._results.append(('NextPageTemplate',templateName))
andy_robinson
parents:
diff changeset
   172
andy_robinson
parents:
diff changeset
   173
def parseFile(filename):
andy_robinson
parents:
diff changeset
   174
    p = Parser()
andy_robinson
parents:
diff changeset
   175
    return p.parseFile(filename)
andy_robinson
parents:
diff changeset
   176
andy_robinson
parents:
diff changeset
   177
def parseText(textBlock):
andy_robinson
parents:
diff changeset
   178
    p = Parser()
andy_robinson
parents:
diff changeset
   179
    return p.parseText(textBlock)
andy_robinson
parents:
diff changeset
   180
andy_robinson
parents:
diff changeset
   181
        
andy_robinson
parents:
diff changeset
   182
if __name__=='__main__': #NORUNTESTS
andy_robinson
parents:
diff changeset
   183
    if len(sys.argv) <> 2:
andy_robinson
parents:
diff changeset
   184
        results = parseText(__doc__)
andy_robinson
parents:
diff changeset
   185
    else:
andy_robinson
parents:
diff changeset
   186
        results = parseFile(sys.argv[1])
andy_robinson
parents:
diff changeset
   187
    import pprint
andy_robinson
parents:
diff changeset
   188
    pprint.pprint(results)