spyce
home
license
community
download
examples
resources
wishlist
contrib (@sf)
documentation
intro
lang
runtime
modules
tags
install
exits
sourceforge
statistics
freshmeat

transparent transparent transparent
Documentation - Tags
[[ Spyce ]]
Python Server Pages
by Rimon Barr

Prev: 5.1 - Core Up: 5 - Tags Next: 6 - Installation

5.2. Writing Tag Libraries

Creating your own active tags is quite easy, and this section explains how. You may want to create your own active tags for a number of reasons. More advanced uses of tags include database querying and separation of business logic. On the other hand, you might consider creating simpler task-specific tag libraries. For example, if you do not wish to rely on style-sheets you could easily define your own custom tags to perform the formatting in a consistent manner at the server. These are only a few of the uses for tags.

Request to users: If you like the idea of active tags, please help. More tag libraries need to be written! For ideas, please start at the library listing at Sun's JSP site. As you will see, writing a Spyce active tag is far simpler than writing a JSP tag.

We begin with a basic example:

examples/myTaglib.py
from spyceTag import spyceTagLibrary, spyceTagPlus

class tag_foo(spyceTagPlus):
  name = 'foo'
  def syntax(self):
    self.syntaxPairOnly()
    self.syntaxExist('val')
    self.syntaxNonEmpty('val')
  def begin(self, val):
    val = self.contextEval(val)
    self.getOut().write('<font size="%s"><b>' % str(val))
    return 1
  def end(self):
    self.getOut().write('</b></font><br>')

class myTaglib(spyceTagLibrary):
  tags = [
    tag_foo, 
  ]

Saving this code in myTaglib.py, in the same directory as your script or anywhere else in the search path, one could then use the foo active tag (defined above), as follows:

examples/tag.spy
[[.taglib name=core as=spy]]
[[.taglib name=myTaglib as=me]]
<html><body>
<spy:for var=x items="=range(2,6)">
  <me:foo val="=x">size <spy:print val="=x" /></me:foo>
</spy:for>
</body></html>
Run this code.
(requires Spyce-enabled web server)

An active tag library can be any Python class that derives from spyceTag.spyceTagLibrary. The interesting aspects of this class definition to implementors are:

  • tags:
    This field is usually all that requires redefinition. It should be a list of the classes (as opposed to instances) of the active tags.
  • start():
    This methd is invoked by the engine upon loading the library. The inherited method is a noop.
  • finish():
    This method is invoked by the engine upon unloading the library after a request. The inherited method is a noop.
Each active tag can be any Python class that derives from spyceTag.spyceTag. The interesting aspects of the class definition for tag implementors are:

  • name:
    This field MUST be overidden to indicate the name of the tag that this class defines.
  • buffer:
    This flag indicates whether the processing of the body of the tag should be performed in its own output buffer, or unbuffered. Buffering is necessary when a tag wants to transform, or otherwise use, the output of processing its body. The inherited default is false.
  • syntax():
    This method is invoked at compile time to perform any additional tag-specific syntax checks. The inherited method returns None, which means that there are no syntax errors. If a syntax error is detected, this function should return a string with a helpful message about the problem. Alternatively, one could raise an spyceTagSyntaxException.
  • begin( ... ):
    This method is invoked when the corresponding start tag is encountered in the document. All the attributes of the tag are passed in by name. In the case of a paired tag, this method is expected to return a boolean flag. A true return value indicates that the body of the tag should be processed. Otherwise, it is skipped. The inherited method simply returns true.
  • body( contents ):
    This method is invoked when the body of the tag has completed processing. It will, of course, not be called if there is no tag body, as is the case with singleton tags. It will also not be called if the begin() method has chosen to skip body processing. If the tag uses a buffer for capturing processing output (see above), then the string output of the body processing has been captured and stored in contents. It is the responsibility of this method to emit something, if necessary. If the tag does not buffer, then contents will be None, and the output has already been written to the enclosing scope. This method is expected to return a boolean flag. If the flag is true, then the body will be processed again, followed by another invocation of this method. The inherited method returns false.
  • end():
    This method is invoked when the corresponding end tag is encountered, if it exists. The runtime engine semantics ensure that if the begin method terminates successfully, this method will get called for the closing of a paired tag. The inherited method is a noop.
  • catch( ex ):
    If any exception occurs in the begin(), body() or end() methods or from the body processing, this method will be called. The parameter ex holds the value that was thrown. The inherited method will re-raise the exception.
  • getPrefix():
    Return the prefix under which this tag library was installed.
  • getAttributes():
    Return a dictionary of tag attributes.
  • getPaired():
    Return true if this is a paired (open and close) tag, or false if it is a singleton.
  • getParent():
    Return the object of the direct parent tag, or None if this is the root active tag. Plain (inactive) tags do not have associated objects in this hierarchy.
  • getOut():
    Return the (possibly buffered) output stream that this tag should write to.
  • getContext():
    Return the tag context dictionary, where all tags variables are kept and expression are evaluated. The context contains references to each of the loaded Spyce modules. These variables may used to access module functionality, but they should not be deleted or modified.
  • getBuffered():
    Returns true if the tag output stream is a local buffer, or false if the output is connected to the enlosing scope.
For convenience, tag implementors may wish to derive their implementations from spyceTagPlus, which provides some useful additional methods:
  • contextSet( name, (exists,value) ):
    Accepts a variable name and a tuple containing an exists flag and a value. If the flag is true, then the variable is assigned the value within the tag context. If the flag is false, the variable is deleted from the context dictionary. This function returns the previous state of this variable, as per contextGet().
  • contextGet( name ):
    Returns the current state of the variable name in the tag context. The state is a tuple containing a flag whether the variable is defined and its value.
  • contextEval( expr ):
    Evaluates a string expr as follows. If the string begins with an '=', then the rest of the string is treated as a Python expression. This is expression is evaluated within the tag context dictionary, and the result is returned. Otherwise, the parameter is treated as a string constant and returned as-is.
  • contextGetModule( name ):
    Return a reference to a module from the tag context. The module is loaded, if necessary.
  • syntaxExist( [must]* ):
    Ensure that the list of attributes given in must are all defined in the attributes of this tag. Otherwise, a spyceTagSyntaxException is thrown.
  • syntaxExistOr( [mustgroups]* ):
    Ensure that at least one of the lists of attributes specified in mustgroups satisfies syntaxExist(). Otherwise, a spyceTagSyntaxException is thrown.
  • syntaxExistOrEx( [mustgroups]* ):
    Ensure that exactly one of the lists of attributes specified in mustgroups satisfies syntaxExist(). Otherwise, a spyceTagSyntaxException is thrown.
  • syntaxNonEmpty( [names]* ):
    Ensure that if the attributes listed in names exist, then each of them does not contain an empty string value. Otherwise, a spyceTagSyntaxException is thrown. Note that the actual existence of a tag is checked by syntaxExists(), and that this method only checks that a tag is non-empty. Specifically, there is no exception raised from this method, if the attribute does not exist.
  • syntaxValidSet( name, validSet ):
    Ensure that the value of the attribute name, if it exists, is one of the values in the set validSet. Otherwise, a spyceTagSyntaxException is raised.
  • syntaxPairOnly():
    Ensure that this tag is a paired tag. Otherwise, a spyceTagSyntaxException is thrown.
  • syntaxSingleOnly():
    Ensure that this tag is a singleton tag. Otherwise, a spyceTagSyntaxException is thrown.
Despite the length of this description, most tags are trivial to write, as shown in the initial example. The easiest way to start is by having at a look at various implemented tag libraries, such as tags/core.py. The more curious reader is welcome to look at the tag library internals in spyceTag.py and modules/taglib.py. The tag semantics are ensured by the Spyce compiler (see spyceCompile.py), though it is likely easier simply to look at the generated Python code using the "spyce -c" command-line facility.


Prev: 5.1 - Core Up: 5 - Tags Next: 6 - Installation


© 2002 Rimon Barr
email: rimon AT acm DOT org
Spyce Powered SourceForge Logo [[ Spyce ]]
Python Server Pages
version 1.3.10