##############################################################################
#
# Copyright (c) 2001, 2002 Zope Corporation and Contributors.
# All Rights Reserved.
#
# This software is subject to the provisions of the Zope Public License,
# Version 2.0 (ZPL). A copy of the ZPL should accompany this distribution.
# THIS SOFTWARE IS PROVIDED "AS IS" AND ANY AND ALL EXPRESS OR IMPLIED
# WARRANTIES ARE DISCLAIMED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
# WARRANTIES OF TITLE, MERCHANTABILITY, AGAINST INFRINGEMENT, AND FITNESS
# FOR A PARTICULAR PURPOSE.
#
##############################################################################
"""
Dummy TALES engine so that I can test out the TAL implementation.
"""
import re
import sys
from TALDefs import NAME_RE,TALESError,ErrorInfo
from ITALES import ITALESCompiler,ITALESEngine
from DocumentTemplate.DT_Util import ustr
IDomain = None
if sys.modules.has_key('Zope'):
try:
from Zope.I18n.ITranslationService import ITranslationService
from Zope.I18n.IDomain import IDomain
except ImportError:
pass
if IDomain is None:
# Before 2.7, or not in Zope
class ITranslationService: pass
class IDomain: pass
class _Default:
pass
Default = _Default()
name_match = re.compile(r"(?s)(%s):(.*)\Z" % NAME_RE).match
class CompilerError(Exception):
pass
class DummyEngine:
position = None
source_file = None
__implements__ = ITALESCompiler, ITALESEngine
def __init__(self, macros=None):
if macros is None:
macros = {}
self.macros = macros
dict = {'nothing': None, 'default': Default}
self.locals = self.globals = dict
self.stack = [dict]
self.translationService = DummyTranslationService()
def getCompilerError(self):
return CompilerError
def getCompiler(self):
return self
def setSourceFile(self, source_file):
self.source_file = source_file
def setPosition(self, position):
self.position = position
def compile(self, expr):
return "$%s$" % expr
def uncompile(self, expression):
assert (expression.startswith("$") and expression.endswith("$"),
expression)
return expression[1:-1]
def beginScope(self):
self.stack.append(self.locals)
def endScope(self):
assert len(self.stack) > 1, "more endScope() than beginScope() calls"
self.locals = self.stack.pop()
def setLocal(self, name, value):
if self.locals is self.stack[-1]:
# Unmerge this scope's locals from previous scope of first set
self.locals = self.locals.copy()
self.locals[name] = value
def setGlobal(self, name, value):
self.globals[name] = value
def evaluate(self, expression):
assert (expression.startswith("$") and expression.endswith("$"),
expression)
expression = expression[1:-1]
m = name_match(expression)
if m:
type, expr = m.group(1, 2)
else:
type = "path"
expr = expression
if type in ("string", "str"):
return expr
if type in ("path", "var", "global", "local"):
return self.evaluatePathOrVar(expr)
if type == "not":
return not self.evaluate(expr)
if type == "exists":
return self.locals.has_key(expr) or self.globals.has_key(expr)
if type == "python":
try:
return eval(expr, self.globals, self.locals)
except:
raise TALESError("evaluation error in %s" % `expr`)
if type == "position":
# Insert the current source file name, line number,
# and column offset.
if self.position:
lineno, offset = self.position
else:
lineno, offset = None, None
return '%s (%s,%s)' % (self.source_file, lineno, offset)
raise TALESError("unrecognized expression: " + `expression`)
def evaluatePathOrVar(self, expr):
expr = expr.strip()
if self.locals.has_key(expr):
return self.locals[expr]
elif self.globals.has_key(expr):
return self.globals[expr]
else:
raise TALESError("unknown variable: %s" % `expr`)
def evaluateValue(self, expr):
return self.evaluate(expr)
def evaluateBoolean(self, expr):
return self.evaluate(expr)
def evaluateText(self, expr):
text = self.evaluate(expr)
if text is not None and text is not Default:
text = ustr(text)
return text
def evaluateStructure(self, expr):
# XXX Should return None or a DOM tree
return self.evaluate(expr)
def evaluateSequence(self, expr):
# XXX Should return a sequence
return self.evaluate(expr)
def evaluateMacro(self, macroName):
assert (macroName.startswith("$") and macroName.endswith("$"),
macroName)
macroName = macroName[1:-1]
file, localName = self.findMacroFile(macroName)
if not file:
# Local macro
macro = self.macros[localName]
else:
# External macro
import driver
program, macros = driver.compilefile(file)
macro = macros.get(localName)
if not macro:
raise TALESError("macro %s not found in file %s" %
(localName, file))
return macro
def findMacroDocument(self, macroName):
file, localName = self.findMacroFile(macroName)
if not file:
return file, localName
import driver
doc = driver.parsefile(file)
return doc, localName
def findMacroFile(self, macroName):
if not macroName:
raise TALESError("empty macro name")
i = macroName.rfind('/')
if i < 0:
# No slash -- must be a locally defined macro
return None, macroName
else:
# Up to last slash is the filename
fileName = macroName[:i]
localName = macroName[i+1:]
return fileName, localName
def setRepeat(self, name, expr):
seq = self.evaluateSequence(expr)
return Iterator(name, seq, self)
def createErrorInfo(self, err, position):
return ErrorInfo(err, position)
def getDefault(self):
return Default
def translate(self, domain, msgid, mapping):
return self.translationService.translate(domain, msgid, mapping)
class Iterator:
def __init__(self, name, seq, engine):
self.name = name
self.seq = seq
self.engine = engine
self.nextIndex = 0
def next(self):
i = self.nextIndex
try:
item = self.seq[i]
except IndexError:
return 0
self.nextIndex = i+1
self.engine.setLocal(self.name, item)
return 1
class DummyDomain:
__implements__ = IDomain
def translate(self, msgid, mapping=None, context=None,
target_language=None):
# This is a fake translation service which simply uppercases non
# ${name} placeholder text in the message id.
#
# First, transform a string with ${name} placeholders into a list of
# substrings. Then upcase everything but the placeholders, then glue
# things back together.
def repl(m, mapping=mapping):
return mapping[m.group(m.lastindex).lower()]
cre = re.compile(r'\$(?:([_A-Z]\w*)|\{([_A-Z]\w*)\})')
return cre.sub(repl, msgid.upper())
class DummyTranslationService:
__implements__ = ITranslationService
def translate(self, domain, msgid, mapping=None, context=None,
target_language=None):
# Ignore domain
return self.getDomain(domain).translate(msgid, mapping, context,
target_language)
def getDomain(self, domain):
return DummyDomain()
|