跳转到主要内容

Zope资源模板

项目描述

本包提供了一种非常简单的模板系统,用于非SGML数据文件,如CSS和JavaScript。

模板资源

Zope的设计目标之一是允许设计师提交HTML模板、CSS和JavaScript文件,使其(带有一些附加信息)直接可用。对于HTML代码,我们使用Zope的页面模板来实现这一目标。对于CSS和JavaScript,我们之前不需要这样的功能,因为那些文件大多是静态的,或者在运行时可以通过其他方式插入变量。

然而,现在在CSS URL中(例如背景图像),经常插入到CSS指令中。然而,设计师的路径布局可能与资源文件结构不匹配。此包提供了一种简单的机制来替换字符串。

为此,提供了一种模板资源。模板语法以一种不会干扰资源语法的方式提供。对于JavaScript和CSS,这是一种形式为/* ... */的注释。

以下是通用语法

<COMMAND-BEGIN> <ZRT-COMMAND>: <COMMAND-ARGUMENTS> <COMMAND-END>

以下是CSS的一个示例

/* zrt-replace: ".." "@@" */

为了演示此功能,我们首先必须创建一个CSS文件。

>>> import tempfile
>>> fn = tempfile.mktemp('.css')
>>> open(fn, 'w').write('''\
... /* zrt-replace: "../img1" "++resource++/img" */
... /* zrt-replace: "fontName" "Arial, Tahoma" */
... h1 {
...   color: red;
...   font: fontName;
...   background: url('../img1/mybackground.gif');
... }
...
... h2 {
...   color: red;
...   background: url('../img2/mybackground.gif');
... }
... /* zrt-replace: "../img2" "++resource++/img" */
... ''')

全局替换命令替换一个字符串为另一个。它仅在声明之后的行中有效。因此,在这种情况下,第二个命令是没有意义的。

现在我们从资源工厂创建一个ZRT资源…

>>> from z3c.zrtresource import ZRTFileResourceFactory
>>> cssFactory = ZRTFileResourceFactory(fn, None, 'site.css')
>>> from zope.publisher.browser import TestRequest
>>> css = cssFactory(TestRequest())

然后渲染该资源

>>> print css.GET()
h1 {
  color: red;
  font: Arial, Tahoma;
  background: url('++resource++/img/mybackground.gif');
}
<BLANKLINE>
h2 {
  color: red;
  background: url('../img2/mybackground.gif');
}

如您所见,只有第一个URL被替换了,因为第二个语句的位置不正确。

这就完成了!在您的ZCML中,您可以如下使用此工厂

<zrt-resource
    name="site.css"
    path="css/site.css"
    />

替换字符串

zrt-replace命令将匹配项替换为输出字符串,替换次数与指定次数相同。以下是语法

zrt-replace: <EXPR-TYPE>”<INPUT-EXPR>” <EXPR-TYPE>”<OUTPUT-EXPR>” <NUM>

如上例所示,zrt-replace调用可以放在文件的任何位置。让我们确保一些特殊情况也能正常工作

>>> from z3c.zrtresource import processor, replace
>>> def process(text):
...     p = processor.ZRTProcessor(
...         text, commands={'replace': replace.Replace})
...     return p.process(None, None)
>>> print process('''\
...        /* zrt-replace: "foo" "bar" */
... foo''')
bar
>>> print process('''\
... /*      zrt-replace: "foo" "bar"      */
... foo''')
bar
>>> print process('''\
... /* zrt-replace:   "foo"         "bar" */
... foo''')
bar

但是以下情况不工作

>>> print process('''\
... /* zrt-replace : "foo" "bar" */
... foo''')
/* zrt-replace : "foo" "bar" */
foo
>>> print process('''\
... /* zrt -replace : "foo" "bar" */
... foo''')
/* zrt -replace : "foo" "bar" */
foo

到目前为止,我们只考虑了多次替换。现在让我们使用最后一个参数限制替换次数。最初,匹配字符串的所有出现都将被替换

>>> print process('''\
... /* zrt-replace: "foo" "bar" */
... foo foo foo foo foo''')
bar bar bar bar bar

当我们指定替换次数时,则只替换该次数

>>> print process('''\
... /* zrt-replace: "foo" "bar" 1 */
... foo foo foo foo foo''')
bar foo foo foo foo
>>> print process('''\
... /* zrt-replace: "foo" "bar" 3 */
... foo foo foo foo foo''')
bar bar bar foo foo
>>> print process('''\
... /* zrt-replace: "foo" "bar" 6 */
... foo foo foo foo foo''')
bar bar bar bar bar

字符串表达式

到目前为止,我们只处理了简单的字符串替换,因为这是默认的表达式类型。另一种拼写表达式类型的方法是

>>> print process('''\
... /* zrt-replace: str"foo" "bar" */
... foo''')
bar
>>> print process('''\
... /* zrt-replace: "foo" str"bar" */
... foo''')
bar
>>> print process('''\
... /* zrt-replace: str"foo" str"bar" */
... foo''')
bar

正则表达式

正则表达式只有作为输入表达式才有意义,因此它们只在那里受支持

>>> print process('''\
... /* zrt-replace: re"foo" "bar" */
... foo''')
bar
>>> print process('''\
... /* zrt-replace: re"[a-z]*foo" "bar" */
... myfoo''')
bar

我们也支持分组

>>> print process('''\
... /* zrt-replace: re"([a-z]*)foo" "bar" */
... myfoo''')
bar
>>> print process('''\
... /* zrt-replace: re"([a-z]*)foo" "bar" */
... myfoo''')
bar
>>> print process('''\
... /* zrt-replace: re"([a-z]*)foo" "bar" */
... myfoo mybar''')
bar mybar

是的,甚至分组替换也工作

>>> print process('''\
... /* zrt-replace: re"([a-z]*)foo" "bar\\1" */
... myfoo a9foo''')
barmy a9bar
>>> print process('''\
... /* zrt-replace: re"(?P<prefix>[a-z]*)foo" "bar\\g<prefix>" */
... myfoo a9foo''')
barmy a9bar

TALES表达式

一个没有TALES表达式的基于Zope的模板语言会是什么样子?如果您想根据请求和上下文创建绝对URL和其他动态部分,这将特别有用

>>> import zope.interface
>>> from zope.traversing.interfaces import IContainmentRoot
>>> class Root(object):
...     zope.interface.implements(IContainmentRoot)
>>> from zope.publisher.browser import TestRequest
>>> def process(text):
...     p = processor.ZRTProcessor(
...         text, commands={'replace': replace.Replace})
...     return p.process(Root(), TestRequest())
>>> print process('''\
... /* zrt-replace: "foo" tal"string:${context/@@absolute_url}/@@/foo" */
... foo''')
http://127.0.0.1/@@/foo

自定义ZRT命令

我们可以创建自定义ZRT命令。为此,我们应该注册一个名为IZRTCommandFactory的实用工具

>>> import re
>>> from zope import interface
>>> from zope.component import provideUtility
>>> from z3c.zrtresource import interfaces
>>> class MyCustomCommand(object):
...   interface.implements(interfaces.IZRTCommand)
...
...   data = {'color1': 'red', 'color2': 'green'}
...
...   isAvailable = True
...
...   def __init__(self, args, start, end):
...      self.args = args
...      self.start = start
...      self.end = end
...
...   def process(self, text, context, request):
...      for key, value in self.data.items():
...         regex = re.compile(re.escape(key))
...         text = regex.subn(value, text)[0]
...
...      return text
>>> from zope.component.factory import Factory
>>> my_command = Factory(MyCustomCommand, 'mycommand')
>>> interface.directlyProvides(my_command, interfaces.IZRTCommandFactory)
>>> provideUtility(my_command, interfaces.IZRTCommandFactory, name='mycommand')
>>> open(fn, 'w').write('''\
... /* zrt-replace: "../img1" "++resource++/img" */
... /* zrt-replace: "fontFamily" "Arial, Tahoma" */
... /* zrt-mycommand: */
... /* oh, and we're testing that when the file changes, it is reloaded */
... h1 {
...   color: color1;
...   font: fontFamily;
...   background: url('../img1/mybackground.gif');
... }
...
... h2 {
...   color: color2;
...   background: url('../img2/mybackground.gif');
... }
... /* zrt-replace: "../img2" "++resource++/img" */
... ''')

我们必须重新创建ZRTFileResourceFactory以重新加载更改后的文件内容(不用担心 - 在现实生活中,Zope在每次请求时都会创建这些,因为资源实际上是作为IResourceFactoryFactory实用工具注册的)。

>>> cssFactory = ZRTFileResourceFactory(fn, None, 'site.css')
>>> css = cssFactory(TestRequest())
>>> print css.GET()
/* oh, and we're testing that when the file changes, it is reloaded */
h1 {
  color: red;
  font: Arial, Tahoma;
  background: url('++resource++/img/mybackground.gif');
}
<BLANKLINE>
h2 {
  color: green;
  background: url('../img2/mybackground.gif');
}
<BLANKLINE>

边缘情况

在Windows上,结果中留有空白行

>>> open(fn, 'w').write('''\
... some-head
... /* zrt-replace: "../img1" "++resource++/img" */
... /* zrt-replace: "fontName" "Arial, Tahoma" */
... some-in-the-middle
... /* zrt-replace: "../img2" "++resource++/img" */
... some-at-the-end
... ''')
>>> cssFactory = ZRTFileResourceFactory(fn, None, 'site.css')
>>> from zope.publisher.browser import TestRequest
>>> css = cssFactory(TestRequest())

然后渲染该资源

>>> css.GET().splitlines()
['some-head', 'some-in-the-middle', 'some-at-the-end']

zrt-resource 指令

此包提供一个新的指令来使用特殊资源指令。让我们先注册它

>>> from zope.configuration import xmlconfig
>>> context = xmlconfig.string('''
... <configure i18n_domain="zope">
...   <include package="z3c.zrtresource" file="meta.zcml" />
... </configure>
... ''')

现在我们可以注册一个资源

>>> import tempfile
>>> fn = tempfile.mktemp('.css')
>>> open(fn, 'w').write('''\
... /* zrt-replace: "../img1" "++resource++/img" */
... h1 {
...   color: red;
...   background: url('../img1/mybackground.gif');
... }
... ''')
>>> context = xmlconfig.string('''
... <configure xmlns="http://namespaces.zope.org/browser" i18n_domain="zope">
...   <zrt-resource
...       name="test.css"
...       file="%s" />
... </configure>
... ''' %fn, context=context)

现在让我们看看适配器是否已注册

>>> import zope.component
>>> import zope.interface
>>> from zope.publisher.browser import TestRequest
>>> resource = zope.component.getAdapter(
...     TestRequest(), zope.interface.Interface, name='test.css')

现在运行它

>>> print resource.GET()
h1 {
  color: red;
  background: url('++resource++/img/mybackground.gif');
}

我们还可以使用标准的browser:resource指令注册ZRT资源。此包中的configure.zcml文件注册了一个用于“zrt”扩展名的ZRT资源工厂,因此任何扩展名为“zrt”的文件都将是一个ZRT资源。

首先,让我们包含browser:resource指令和资源工厂注册

>>> context = xmlconfig.string('''
... <configure i18n_domain="zope">
...   <include package="zope.browserresource" file="meta.zcml" />
...   <include package="zope.component" file="meta.zcml" />
...   <include package="z3c.zrtresource" />
... </configure>
... ''')

现在我们需要创建一个扩展名为“zrt”的文件

>>> fn = tempfile.mktemp('.zrt')
>>> open(fn, 'w').write('''\
... /* zrt-replace: "../img1" "++resource++/img" */
... h1 {
...   color: red;
...   background: url('../img1/mybackground.gif');
... }
... ''')

并使用browser:resource指令将其注册为资源。

>>> context = xmlconfig.string('''
... <configure xmlns="http://namespaces.zope.org/browser" i18n_domain="zope">
...   <resource
...       name="test2.css"
...       file="%s" />
... </configure>
... ''' %fn, context=context)

让我们看看适配器是否已注册

>>> resource2 = zope.component.getAdapter(
...     TestRequest(), zope.interface.Interface, name='test2.css')

现在,让我们渲染它并检查ZRT机制是否对其有效。

>>> print resource2.GET()
h1 {
  color: red;
  background: url('++resource++/img/mybackground.gif');
}

变更记录

1.4.0 (2013-05-31)

  • 使测试与zope.browserresource 3.11兼容,因此至少需要此版本。

  • 修复:绕过Windows:它有一个2个字符的换行序列

1.3.0 (2009-08-27)

  • 使用新的zope.browserresource包代替zope.app.publisher,因为资源机制已移至那里以减少依赖。

  • 在包的configure.zcml中将ZRTFileResourceFactory注册为名为“zrt”的资源工厂。这使使用browser:resource指令为扩展名为“zrt”的文件创建ZRT资源自动。它还将使资源目录中的*.zrt文件成为ZRTFileResource。

  • 删除对zope.app.testing测试依赖的引用。

  • 删除未使用的SETUP.CFG和z3c.zrtresource-meta.zcml文件。

1.2.0 (2009-06-25)

  • 删除了对zope.app.componentzope.app.pagetemplate的依赖。

  • 修复了主页和作者电子邮件地址。

1.1.0 (2007-12-01)

  • 修复了替换表达式中空格的bug

  • 添加了自定义ZRT命令

1.0.1 (2007-10-30)

  • 修复了包的长描述,使其成为有效的reStructuredText。

1.0.0 (2007-10-30)

  • 初始发布。

项目详细信息


下载文件

下载适合您平台的文件。如果您不确定选择哪个,请了解有关安装包的更多信息。

源代码发行版

z3c.zrtresource-1.4.0.zip (30.7 kB 查看哈希值)

上传时间 源代码

由以下支持

AWS AWS 云计算和安全赞助商 Datadog Datadog 监控 Fastly Fastly CDN Google Google 下载分析 Microsoft Microsoft PSF 赞助商 Pingdom Pingdom 监控 Sentry Sentry 错误日志 StatusPage StatusPage 状态页面