The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.

NAME

PerlPoint::Backend - frame class to transform PerlPoint::Parser output

VERSION

This manual describes version 0.15.

SYNOPSIS

  # load the module:
  use PerlPoint::Backend;

  # build the backend
  my ($backend)=new PerlPoint::Backend(name=>'synopsis');

  # register handlers
  $backend->register(DIRECTIVE_BLOCK,    \&handleBlock);
  $backend->register(DIRECTIVE_COMMENT,  \&handleComment);
  $backend->register(DIRECTIVE_DOCUMENT, \&handleDocument);
  $backend->register(DIRECTIVE_HEADLINE, \&handleHeadline);
  $backend->register(DIRECTIVE_POINT,    \&handlePoint);
  $backend->register(DIRECTIVE_SIMPLE,   \&handleSimple);
  $backend->register(DIRECTIVE_TAG,      \&handleTag);
  $backend->register(DIRECTIVE_TEXT,     \&handleText);
  $backend->register(DIRECTIVE_VERBATIM, \&handleVerbatim);

  # finally run the backend
  $backend->run(\@streamData);

DESCRIPTION

After an ASCII text is parsed by an PerlPoint::Parser object, the original text is transformed into stream data hold in a Perl array. To process this intermediate stream further (mostly to generate output in a certain document description language), a program has to walk through the stream and to process its tokens.

Well, PerlPoint::Backend provides a class which encapsulates this walk in objects which deal with the stream, while the translator programmer is focussed on generating the final representation of the original text. This is done by registering handlers which will be called when their target objects are discovered in the intermediate stream.

The stream walk can be performed in various ways (please see following sections for details). The common way is to use run() which walks through the stream from its first to its last token and takes everything found into account to invoke appropriate callbacks.

Modes

By default, a backend object inspects the token stream token by token. This way everything is handled in the original order, according to the input once parsed. But sometimes you want to know something about the documents structure which simply means about headlines only.

  For example, consider the case that you want to build
  a table of contents or a table of valid chapter references
  before the "real" slides are made. In the mentioned token
  mode this takes more time than it should, because a lot
  of additional tokens are processed besides the headlines.

In such cases, the backend can be enforced to work in "headline mode". This means that only headlines are processed which accelerates things significantly.

Modes are switched by method mode(). Please note that a stream can be processed more than once, so one can process it in headline mode first, use the headline information, and then switch back to the usual token mode and process the entire document data.

Ways of stream processing

The base model of stream processing implemented by this class is based on "events". This means that the token stream is processed by a loop which invokes user specified callback functions to handle certain token types. In this model, the loop is in control. This works fine in stream translation, e.g. to produce slides/documents in a target format, and is done by invoking the method run().

Nevertheless, there are cases when converters need to be in full control, which means in fine grained control of token processing. In this model the calling program (the converter) initiates the processing of each token. This is especially useful if a converter is not really a converter but a projector which uses the stream to present the slides on the fly.

This second model of fine grained control is supported as well. The appropriate method (used as an alternative of run()) is next().

Stream navigaton

Usually a stream is processed from the beginning to its end, but it is possible to set up an arbitrary sequence of chapters as well. (This is mostly intended for use in projectors.) Two methods are provided to do this: reset() moves back to the beginning of the entire stream, while move2chapter() chooses a certain chapter to continue the processing with.

Stream navigation works both in callbacks and if walking the stream via next().

The whole picture

Modes, the stream processing method and stream navigation can be freely combined. If the defaults are used as shown in the SYNOPSIS, a backend object works in headline mode and processes the stream by run(), usually without further navigation. But this is no rule. Make use of the features as it is necessary to build the converter you want!

METHODS

new()

The constructor builds and prepares a new backend object. You may have more than one object at a certain time, they work independently.

Parameters: All parameters except of the class parameter are named (pass them by hash).

class

The class name.

name

Because there can be more than exactly one backend object, your object should be named. This is not necessarily a need but helpful reading traces.

trace

This parameter is optional. It is intended to activate trace code while the object methods run. You may pass any of the "TRACE_..." constants declared in PerlPoint::Constants, combined by addition as in the following example:

  trace => TRACE_NOTHING+TRACE_BACKEND,

In fact, only TRACE_NOTHING and TRACE_BACKEND take effect to backend objects.

If you omit this parameter or pass TRACE_NOTHING, no traces will be displayed.

display

This parameter is optional. It controls the display of runtime messages like informations or warnings in all object methods. By default, all messages are displayed. You can suppress these informations partially or completely by passing one or more of the "DISPLAY_..." variables declared in PerlPoint::Constants.

Constants can be combined by addition.

vispro

activates "process visualization" which simply means that a user will see progress messages while the backend processes the stream. The numerical value of this setting determines how often the progress message shall be updated by a chapter interval:

  # inform every five chapters
  vispro => 5,

Process visualization is automatically suppressed unless STDERR is connected to a terminal, if this option is omitted, display was set to DISPLAY_NOINFO or backend traces are activated.

generator

This is an internal interface, to make backends work together with PerlPoint::Generator objects. If you build a backend manually, you do not have to care for this, just ignore it. If you build a PerlPoint::Generator application, just pass the generator object.

Note: Generator handling is in alpha state, so manual usage is standard and traditional.

Returns: the new object.

Example:

  my ($backend)=new PerlPoint::Backend(name=>'example');

register()

After building a new object by new() the object can be prepared by calls of the register method.

If the object walks through the data stream generated by PerlPoint::Parser, it will find several directives. A directive is a data struture flagging that a certain document part (or even formatting) starts or is completed. E.g. a headline is represented by headline start directive followed by tokens for the headline contents followed by a headline completion directive.

By using this method, you can register directive specific functions which should be called when the related directives are discovered. The idea is that such a function can produce a target language construct representing exactly the same document token that is modelled by the directive. E.g. if your target language is HTML and you register a headline handler and a headline start is found, this handler can generate a "<Hx>" tag. This is quite simple.

According to this design, the object will pass the following data to a registered function:

directive

the directive detected, this should be the same the function was registered for. See PerlPoint::Constants for a list of directives.

start/stop flag

The document stream generated by the parser is strictly synchronous. Everything except of plain strings is represented by an open directive and a close directive, which may embed other parts of the document. A headline begins, something is in, then it is complete. It's the same for every tag or paragraph and even for the whole document.

So well, because of this structure, a handler registered for a certain directive is called for opening directives as well as for closing directives. To decide which case is true, a callback receives this parameter. It's always one of the constants DIRECTIVE_START or DIRECTIVE_COMPLETED.

For simple strings (words, spaces etc.) and line number hints, the callback will always (and only) be called with DIRECTIVE_START.

directive values, if available

Certain directives provide additional data such as the headline level or the original documents name which are passed to their callbacks additionally. See the following list:

Documents

transfer the basename of the original ASCII document being parsed;

Headlines

transfer the headline level;

Ordered list points
  optionally transfer a fix point number;
Tags

transfer the tag name ("I", "B" etc.).

To express this by a prototype, all registered functions should have an interface of "$$:@".

Parameters:

object

a backend object as made by new();

directive

the directive this handler is registered for. See PerlPoint::Constants for a list of directives.

handler

the function to be called if a pointed directive is entered while the run() method walks through the document stream.

Returns: no certain value;

Example:

  $backend->register(DIRECTIVE_HEADLINE, \&handleHeadline);

where handleHeadline could be something like

  sub handleDocument
   {
    my ($directive, $startStop, $level)=@_;
    confess "Something is wrong\n"
      unless $directive==DIRECTIVE_HEADLINE;
    if ($startStop==DIRECTIVE_START)
      {print "<head$level>";}
    else
      {print "</head>";}
   }

If no handler is registered, detected items will be ignored by default except of plain strings, which will be printed by default.

mode()

Switches the way an object inspects stream tokens. The new behaviour comes into action with the next supplied token - either within run() or by invokation of next().

"Inspecting tokens" means how the object reads stream data to invoke registered handlers.

Parameters:

object

An object as built by new().

new mode

All modes are declared by STREAM_... constants in PerlPoint::Constants (import these constants by using the ":stream" tag).

STREAM_TOKENS

The default mode. All stream tokens are inspected which takes time but enables a complete document processing.

STREAM_HEADLINES

In headline mode the object only inspects headlines, which means opening and closing headline directives and everything between. Headline mode is less complete but obviously faster because all tokens outside headlines are ignored and headlines usually claim only a small percentage of a document. This mode is useful to get informed about the structure of a document, to build tables of contents or the like.

Returns:

the new mode.

Example:

  $backend->mode(STREAM_HEADLINES);

run()

The stream processor. The method walks through the data stream and inspects its tokens according to the current mode (see mode()) (which may be changed on the way). For each token, run() detects the appropriate type and checks if there is a callback registered for this type (see register()). If so, the callback is invoked to handle the token. If no handler is registered, the token will be ignored except in the case of simple tokens, which will be printed to STDOUT by default.

If all (mode according) stream data are handled <run()> finishs.

The model of this method is to perform stream data processing by an enclosing loop which is in control and knows of callbacks to handle "events" (occurences of certainly typed data). There is an alternative model using next() to give the caller control of when to process the next token.

Parameters:

object

An object as built by new().

stream data

A reference to the stream data produced by a PerlPoint::Parser call. Stream data are not stored in an object (yet?), but nevertheless nothing but a data structure as supplied by the parser will be accepted.

Returns:

nothing specific.

Example:

  $backend->run($streamData);

next()

This is an alternative stream data processing method to run(). While run() processes all data completely, next() handles exactly one token. The most important difference of these two approaches is that with next() a caller is in full control of what happens. This enables to move freely between chapters, to switch modes or to abort processing dependend on current needs which might be expressed by a users input. In fact, next() was introduced to enable the implementation of projectors working on base of the token stream data directly.

Processing a token works equally to run() by type detection and handler invokation, see there for details.

Please note that different to run() a stream must be bound to a backend object before using next(). This is necessary to store processing states between various next() calls and is done by bind(). After processing all data, unbind() may be used to detach the stream.

To avoid confusion, next() cannot be called from a callback invoked by run(). In other words, both approaches cannot be mixed.

Parameters:

object

An object as built by new().

Returns:

A true value if there is more to process, a false value otherwise. It is up to the caller to handle these cases appropriately.

Example:

  # This example emulates run() by next().
  $backend->bind($streamData);
  {redo while $backend->next;}
  $backend->unbind;

bind()

Binds a stream data structure to a backend object. If run() is used to process a stream, there is no need to use bind() because it is called by run() implicitly.

If there was already a stream connected to the backend object, the new connection will replace the old one.

Binding a stream resets stream processing (see reset()). Do not call this method from a handler unless you know exactly what is going on.

Parameters:

object

An object as built by new().

stream data

A reference to the stream data produced by a PerlPoint::Parser call. Stream data are not stored in an object (yet?), but nevertheless nothing but a data structure as supplied by the parser will be accepted.

Returns:

nothing significant.

Example:

  $backend->bind($streamData);

unbind()

Detaches a stream data structure bound to the backend object.

Unbinding a stream resets stream processing (see reset()) - if the stream is rebound to the object and furtherly processed, it will be processed from its beginning.

Do not call this method from a handler unless you know exactly what is going on.

Parameters:

object

An object as built by new().

Returns:

nothing significant.

Example:

  $backend->unbind();

reset()

Resets processing of a stream associated with (or bound to) the backend object. This means that further processing will start with the very first token matching the current mode (see mode()).

Parameters:

object

An object as built by new().

Returns:

nothing significant.

Example:

  $backend->reset;

move2chapter()

Causes stream processing to continue with a certain chapter.

Parameters:

object

An object as built by new().

chapter

The number of the target chapter to process next. This is an absolute number - the first headline is headline 1, the second 2 etc., regardless of headline hierachies. The highest valid number is equal to the result of headlineNr().

Returns:

nothing significant.

Example:

  $backend->move2chapter(15);

headlineNr()

Replies the number of headlines in the stream associated with the object. If no stream is associated, an undefined value is supplied.

Parameters:

object

An object as built by new().

Returns:

The number of headlines in the stream if a stream is associated, an undefined value otherwise.

Example:

  $backend->headlineNr;

headlineIds2Data()

Parameters:

object

An object as built by new().

list of headline ids

A list of ids. An id is an absolute headline number, starting with 1.

Returns:

The number of headlines in the stream if a stream is associated, an undefined value otherwise.

Example:

  $backend->headlineIds2Data;

currentChapterNr()

Replies the number of the currently processed chapter - in the stream associated with the object. If no stream is associated, an undefined value is supplied.

Parameters:

object

An object as built by new().

Returns:

The number of the currently handled headline in the stream if a stream is associated, an undefined value otherwise.

Example:

  $backend->currentChapterNr;

toc()

This method provides a convenient way to get a list of subchapters related to a certain "parent" chapter. More, it can be used to get a complete table of contents as well. Each subchapter is presented by its headline (hierarchy) level and its title in plain text.

Parameters:

object

An object as built by new().

chapter of interest

This is an absolute number as used in various other methods as well. The first headline in the document is number 1, the next headline number 2 and so on. (The number of the chapter currently processed is always provided by currentChapterNr().)

If this parameter is omitted or 0, the whole documents hierarchy will be reported.

result depth

There may be a deep hierarchy of subchapters. If only a certain depth is of interest, supply it here. If this parameter is omitted or set to 0, all subchapters will be reported.

Returns:

a reference to an array of arrays, where each entry describes a subchapter by its headline level and its title (as plain text - tags etc. are stripped off).

Example:

  $subchapters=$backend->toc(5, 2);

docstreams()

Supplies the names of all document streams in the data stream. A data streams needs to be bound to the object.

Parameters:

object

An object as built by new().

Returns:

A list of document stream titles in list context, the number of document streams in scalar context.

Example:

  @docstreams=$backend->docstreams;

SEE ALSO

PerlPoint::Parser

A parser for Perl Point ASCII texts.

PerlPoint::Constants

Public PerlPoint::... module constants.

SUPPORT

A PerlPoint mailing list is set up to discuss usage, ideas, bugs, suggestions and translator development. To subscribe, please send an empty message to perlpoint-subscribe@perl.org.

If you prefer, you can contact me via perl@jochen-stenzel.de as well.

AUTHOR

Copyright (c) Jochen Stenzel (perl@jochen-stenzel.de), 1999-2002. All rights reserved.

This module is free software, you can redistribute it and/or modify it under the terms of the Artistic License distributed with Perl version 5.003 or (at your option) any later version. Please refer to the Artistic License that came with your Perl distribution for more details.

The Artistic License should have been included in your distribution of Perl. It resides in the file named "Artistic" at the top-level of the Perl source tree (where Perl was downloaded/unpacked - ask your system administrator if you dont know where this is). Alternatively, the current version of the Artistic License distributed with Perl can be viewed on-line on the World-Wide Web (WWW) from the following URL: http://www.perl.com/perl/misc/Artistic.html

DISCLAIMER

This software is distributed in the hope that it will be useful, but is provided "AS IS" WITHOUT WARRANTY OF ANY KIND, either expressed or implied, INCLUDING, without limitation, the implied warranties of MERCHANTABILITY and FITNESS FOR A PARTICULAR PURPOSE.

The ENTIRE RISK as to the quality and performance of the software IS WITH YOU (the holder of the software). Should the software prove defective, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.

IN NO EVENT WILL ANY COPYRIGHT HOLDER OR ANY OTHER PARTY WHO MAY CREATE, MODIFY, OR DISTRIBUTE THE SOFTWARE BE LIABLE OR RESPONSIBLE TO YOU OR TO ANY OTHER ENTITY FOR ANY KIND OF DAMAGES (no matter how awful - not even if they arise from known or unknown flaws in the software).

Please refer to the Artistic License that came with your Perl distribution for more details.