Plim 中文文档

https://pypip.in/v/Plim/badge.png https://pypip.in/d/Plim/badge.png https://api.travis-ci.org/avanov/Plim.png https://coveralls.io/repos/avanov/Plim/badge.png?branch=develop

Plim 是 Ruby Slim 模版 的 Python 移植版本基于 Mako Templates ,并使用 Mako 预处理特性 将其语法转换为符合 HTML/Mako 标准的标签。

安装指南

pip install Plim

运行测试

Plim 的测试依赖于 nosetests ,你可以输入下面的命令来运行测试

python setup.py nosetests

你可以在 这里 看到覆盖率统计。

示例

/ base.html
--------------------------
doctype html
html = next.body()
/ helpers.html
--------------------------
-def other_headers()
    meta charset="utf-8"
    link rel="stylesheet" href="/static/css/main.css"
/ layout.html
--------------------------
-inherit base.html
-namespace name="helper" helpers.html

head
  title Plim Example
  meta name="keywords" content="template language"
  = helper.other_headers()

  script
    /* "script" and "style" blocks do not require explicit literal indicator "|"  */
    $(content).do_something();

  style
    body {
      background:#FFF;
      }

  -scss
    /* SCSS/SASS extension */
    @option compress: no;
    .selector {
      a {
        display: block;
      }
      strong {
        color: blue;
      }
    }

  -coffee
    # CoffeeScript extension
    square = (x) -> x * x

body
  h1 Markup examples
  #content.example1
    p Nest by indentation
    <div>
      p Mix raw HTML and Plim markup
    </div>

    -md
      Use Markdown
      ============

      See the syntax on [this page][1].

      [1]: http://daringfireball.net/projects/markdown/basics

    -rest
      or Use reStructuredText
      =======================

      See the syntax on `this page`_.

      .. _this page: http://docutils.sourceforge.net/docs/user/rst/quickref.html


  -if items
    table: -for item in items: tr
      td = item.name
      td = item.price
  -elif show_empty
    p No items found
  -else
    a href=request.route_url('items.add') =, _('Add items')

  -unless user.authenticated
    p Please, sign in.
  -else
    p Welcome, ${user.name}!
    ul
      --- i = 0
          limit = 5

      -while i < limit
        li#idx-${i}.up: a href='#' title="Title" == i
        --- i += 1

      -until i < 0
        li#idx-${i}.down-${i}: a href='''#''' title="""Title""" ==, i
        --- i -= 1

  #footer
    Copyright &copy; 2014.
    -include footer_links.html

= render('tracking_code')

主要文档

语法

文档的某些部分直接复制自 Slim 官方文档

行内标识符(Line Indicator)

|

管道符告诉 Plim 只需要复制整行即可,不需要做任何转换。

,

逗号告诉 Plim 复制整行(与管道符类似),但是在行尾添加一个空格字符。

注解

在 Slim 中对应的是单引号(')。

-

横线表示控制模块,包括循环、条件、mako 标签以及扩展。

=

等号表示 Python 调用,并会将代码的输出添加到 HTML 输出缓冲区中。

=,

与等号类似,但是会在 Python 代码的输出后添加一个空格字符。

==

与等号类似,但是会在输出为 mako 时添加 ‘过滤器 “n” <http://docs.makotemplates.org/en/latest/filtering.html>`_ 。

== python_expression                       =>      ${python_expression|n}

== python_expression | custom_filter       =>      ${python_expression |n,custom_filter}
==,

== 类似,但是会在 Python 表达式的结尾添加空格字符。

/

正斜线用于代码注释,其后的任何内容都不会输出到 Mako 模板中。

注解

Slim 中的 “/!” HTML 注释并没有对应的 Plim 写法 ,这是因为 Plim 现在已经支持原生的 HTML 标记,无需多余的控制语法。

/ You can use raw HTML comment tags, as well as all other tags
<!-- HTML comment -->
<div>

  / You can use Plim markup inside the raw HTML
  a href="#" = link.title

/ If you use raw HTML, you have to close all tags manually
</div>

缩进

Plim 缩进规则和 Slim 类似:缩进很重要,但是并不需要像 Haml 那样严格,你尽可以在代码中使用 2 空格、5 空格缩进。实际上只需要提供 1 个以上的空格即符合 Plim 的语法。

标签属性

静态属性

Static tag attributes can be specified in the same form as any valid python string declaration.

例如:

input type='text' name="username" value='''Max Power''' maxlength="""32"""

将会输出:

<input type="text" name="username" value="Max Power" maxlength="32"/>

和 Python 字符串声明一样,你需要注意引号的转译:

input value='It\'s simple'
input value="It's simple"
input value='''It's simple'''
input value="""It's simple"""

input value="He said \"All right!\""
input value='He said "All right!"'
input value='''He said "All right!"'''
input value="""He said "All right!\""""

对于纯数字属性,引号并不是必须的:

input type='text' name="measure" value=+.97 maxlength=32

输出:

<input type="text" name="measure" value="+.97" maxlength="32"/>
动态属性

动态值必须以以下形式传入:

  • Mako 表达式

    input type="text" name="username" value="${user.name}" maxlength=32
    a href="${request.route_url('user_profile', tagname=user.login, _scheme='https')}"
    

    或者

    input type="text" name="username" value=${user.name} maxlength=32
    a href=${request.route_url('user_profile', tagname=user.login, _scheme='https')}
    
  • Python 表达式

    input type="text" name="username" value=user.name maxlength=32
    a href=request.route_url('user_profile', tagname=user.login, _scheme='https')
    

    或者使用圆括号

    input type="text" name="username" value=(user.name) maxlength=32
    a href=(request.route_url('user_profile', tagname=user.login, _scheme='https'))
    

以上代码都会输出相同的 Mako 代码:

<input type="text" name="username" value="${user.name}" maxlength="32"/>
<a href="${request.route_url('user_profile', tagname=user.login, _scheme='https')}"></a>
布尔属性

布尔属性即可以通过静态也可以使用动态方法定义:

静态属性示例:

/ Static boolean attribute "disabled"
input type="text" name="username" disabled="disabled"

/ If you wrap your attributes with parentheses, you can use
  shortcut form
input (type="text" name="username" disabled)

动态属性示例(注意结尾的问号):

/ Dynamic boolean attribute "disabled"
  will be evaluated to 'disabled="disabled"' if `is_disabled`
  evaluates to True

input type="text" name="username" disabled=${is_disabled}?

/ or you can write it that way
input type="text" name="username" disabled=is_disabled?

/ or even that way
input type="text" name="username" disabled=(is_disabled or
                                            is_really_disabled)?
Dynamic unpacking

这个功能和 Slim 的 splat 属性 对应,但是语法上稍有不同,以契合 Python 的 **kwargs 语法。

假设有这样一个 Python 字典:

attrs = {
    'id': 'navbar-1',
    'class': 'navbar',
    'href': '#',
    'data-context': 'same-frame',
}

Now we can unpack the dictionary in order to populate tags with attributes. The following line:

a**attrs Link

将会输出与下面这段 HTML 等价的 Mako 代码:

<a id="navbar-1" class="navbar" href="#" data-context="same-frame">Link</a>

其它示例:

a **attrs|Link

a **attrs **more_attrs Link

a(**attrs disabled) Disabled Link

a **function_returning_dict(
  *args, **kwargs
) Link

Attribute Wrapping

你可以是用圆括号 () 包裹标签属性。但和 Slim 不同的是,Plim 并不支持方括号 [] 和花括号 {} 用作属性封装。

body
  h1(id="logo" class="small tagline") = page_logo
  h2 id=(id_from_variable + '-idx') = page_tagline

使用属性包裹后,属性赋值将支持跨行:

body

  h1 (id="logo"
    class="small tagline") = page_logo

  h2 id=(
    id_from_variable +
    '-idx'
  ) = page_tagline

单行标签内容

你可以将标签中的内容与标签写在同一行:

body
  h1 id="headline" Welcome to my site.

也可以使用缩进嵌套。注意:需要使用管道符或者 隐式文本标识(Implicit literal indicators)

body
  h1 id="headline"

    / Explicit literal with pipe character
    | Welcome to my site.

    / Implicit literal (uppercase letter at the beginning of the line)
    Yes, Welcome to my site

动态标签内容

你可以在同一行调用动态属性

body
  h1 id="headline" = page_headline

或者缩进:

body
  h1 id="headline"
    = page_headline

idclass 的简易写法

你可以使用下面的格式设置标签的 id 和 class 属性:

body

  / Static shortcuts
  h1#headline
    = page_headline
  h2#tagline.small.tagline
    = page_tagline
  .content
    = show_content

与下面的写法等价:

body
  h1 id="headline"
    = page_headline
  h2 id="tagline" class="small tagline"
    = page_tagline
  div class="content"
    = show_content

与 Slim 不同 的是,Plim 支持在这种简写中混合动态表达式:

/ Dynamic shortcuts
h1#headline-${'dynamic'} = page_headline
h2#${tagline.id}.small-${tagline.cls}.${tagline.other_cls}
  = page_tagline
.${'content'}
  = show_content

与下面的写法等价:

h1 id="headline-${'dynamic'}" = page_headline
h2 id="${tagline.id}" class="small-${tagline.cls} ${tagline.other_cls}"
  = page_tagline
div class="${'content'}"
  = show_content

行内标签

你可能会希望这样更简洁的行内标签支持:

ul
  li.first: a href="/a" A link
  li: a href="/b" B link

别忘了,还可以使用圆括号增加代码的可读性:

ul
  li.first: a(href="/a") A link
  li: a(href="/b") B link

行内状态(Inline Statement)

Python 循环和条件表达式的单行写法和 HTML 标签类似:

ul: -for link in ['About', 'Blog', 'Sitemap']: li: a href=route_to(link) = link

将会输出:

<ul>
%for link in ['About', 'Blog', 'Sitemap']:
<li><a href="${route_to(link)}">${link}</a></li>
%endfor
</ul>

Python 代码与纯文本混合

使用标准 Mako 表达式语法 。文本的解析方式决定于 Mako 默认过滤器的设置

body
  h1 Welcome ${current_user.name} to the show.
  Explicit non-escaped ${content|n} is also possible.

目前,Mako 并没有提供一种简单的其嵌入表达式的渲染方法(比如原样输出)。你可以使用 <%text> 标签(或者 Plim -text 标记)或者下面的取巧办法:

body
  h1 Welcome ${'${current_user.name}'} to the show.

嵌入的标记

你可以在隐式文本块中嵌入 Plim 标记:

a href="#" Embedded `strong string` everywhere

将输出:

<a href="#">Embedded <strong>string</strong> everywhere</a>

如果你想要紧接着使用两个嵌入标记,需要在第一个嵌入标记后跟上一个下划线 _

a href="#" Embedded `strong string`_`i s` everywhere

将输出:

<a href="#">Embedded <strong>string</strong><i>s</i> everywhere</a>

这种嵌入机制可迭代,也就是说你可以在嵌入标记中使用嵌入标记:

Another `a href="#" very ``strong funny ````i recursive``````` test

将输出:

Another <a href="#">very <strong>funny <i>recursive</i></strong></a> test

停用 HTML 转义

使用双等号:

body
  h1 id="headline"
    == page_headline

或者在表达式的结尾添加 | n 过滤器:

body
  h1 id="headline"
    = page_headline | n

代码注释

使用正斜线 / 标记代码中的注释:

body
  p
    / This is a comment.
      Indentation is the natural way to get block comments

原生 HTML 标签

在 Plim 中你可以使用原生的 HTML 标签,也可以和所有逻辑控制模块混合使用,在下面的情况中非常实用:

- if edit_profile
  / Wrap interface with editable block
  <div id="edit-profile">

- include new_or_edit_interface.html

- if edit_profile
  / close wrapper tag
  </div>

Doctype 声明

Plim 并不提供默认的 doctype 声明,因此你需要指定 HTML 的 doctype

doctype 5

可用的 HTML doctype 包括:

doctype html

<!DOCTYPE html>

doctype 5

<!DOCTYPE html>

doctype 1.1

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">

doctype strict

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">

doctype xml

<?xml version="1.0" encoding="utf-8" ?>

doctype transitional

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

doctype frameset

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">

doctype basic

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML Basic 1.1//EN" "http://www.w3.org/TR/xhtml-basic/xhtml-basic11.dtd">

doctype mobile

<!DOCTYPE html PUBLIC "-//WAPFORUM//DTD XHTML Mobile 1.2//EN" "http://www.openmobilealliance.org/tech/DTD/xhtml-mobile12.dtd">

逻辑控制

if/elif/else
-if items
  table
    -for item in items
      tr
        td = item.name
        td = item.price
-elif show_empty
  p No items found
-else
  a href=request.route_url('items.add') =, _('Add items')
unless

unless- if not (<EXPR>) 的缩写形式

-unless user.authenticated
  p Please, sign in.
-else
  p Welcome, ${user.name}!
for 循环
table
  -for item in items
    tr
      td = item.name
      td = item.price

你可以在 -for 中使用 -continue-break 标记。参考链接 Returning Early from a Template.

while statement
-python
  i = 0
  limit = 5

ul
  -while i < limit
    li#idx-${i}.up: a href='#' title="Title" == i
    -py i += 1

你同样可以在 -while 循环中使用 -continue-break 标记。参考链接 Returning Early from a Template.

until

until- while not (<EXPR>) 的简写方式:

-until i < 0
  li#idx-${i}.down-${i}: a href='''#''' title="""Title""" ==, i
  -py i -= 1

你同样可以在 -until 中使用 -continue-break 标记参考链接 Returning Early from a Template

with

Mako 0.7.0 中引入了``% with`` 标记:

-with <EXPR> as <VAR>
  / Do some stuff
try/except
- try
  div = item[0]
  div = price['usd']

- except IndexError
  div IndexError

- except KeyError as e
  div = e
Returning Early from a Template

Plim 同样提供 Mako <% return %> 标签 的简写形式:

- if not len(records)
  No records found.
  -return

等价于:

- if not len(records)
  No records found.
  -py return

你可以在 Plim 模板中的任意位置这样使用,而不独是控制结构中。

There are also the -break and -continue shortcuts, that can be used inside the -for, -while, and -until loops.

文本块

你可以定义显式或者隐式的文本块,区别在于以 | 显式声明符还是隐式声明符开头。

显式声明

使用管道符 ( | ) 或者逗号 ( , ) literal indicators to start the escape.Each following line that is indented greater than the first one is copied over.

body
  p
    / Explicit literal
    | This is a test of the text block.
body
  p
    |
      This is a test of the text block.

上面的输出结果如下:

<body><p>This is a test of the text block.</p></body>

边缘空格将被抹去。其它位置的空格则会原样复制。

body
  p
    |  This line is on the zero left margin.
        This line will have one space in front of it.
          This line will have two spaces in front of it.
            And so on...
隐式文本块

以下字符开头的文本块将被当作隐式声明:

  • 大写 ASCII 字母;

  • 任何非 ASCII 字符;

  • 没有正/负号的数字;

  • HTML 转义字符,如 &nbsp;

  • Mako 格式的开括号 ${

  • an open square brace [;
  • an open parenthesis (;
  • any unicode character outside the range of U0021 - U007E (ASCII 33 - 126).
p
  | pipe is the explicit literal indicator. It is required if your line starts with
    the non-literal character.

p
  I'm the implicit literal, because my first letter is in uppercase.

p
  1. Digits
  2. are
  3. the
  4. implicit
  5. literals
  6. too.

p
  ${raw_mako_expression} indicates the implicit literal line.

p
  If subsequent lines do not start with implicit literal indicator,
    you must indent them
  | or you can use the "explicit" pipe.
p
  если ваш блок текста написан на русском, или любом другом языке, не
  использующим символы из ASCII-диапазона, то вам даже не обязательно
  использовать заглавную букву в начале блока.

  / if your literal blocks are written in Russian, or any other
    language which uses non-ASCII letters, you can put even the
    lowercase letter at the beginning of the block

Python 代码块

旧式写法

使用 -py 或者 -python 标记来代替 <% %> mako 标签

例如:

- python x = 1

或者

-py
    x = 1

或者:

- python x = 1
    y = x + 1
    if True:
        y += 1
    else:
        y -= 1

在后面的例子中, x = 1 将会和 y = x + 1 出现在同一行。

新式写法

0.9.1 新版功能: 新式写法将提高嵌入的 Python 代码的可读性。

新式写法使用三个以上的横线开头的字符串作为 Python 代码块的开始。

下面是对应的新式写法示例:

--- x = 1
-------------
    x = 1
--- x = 1
    y = x + 1
    if True:
        y += 1
    else:
        y -= 1

And here’s an example of how we can use an inline statement for providing a block description

ul#userlist
    ---------- # prepare a list of users ---------------
        users = UsersService.get_many(max=100, offset=0)
        friends = UsersService.get_friends_for(users)
    ----------------------------------------------------
    -for user in users: li
        h4: a#user-${user.id} href='#' = user.name
        ul: -for friend in friends[user.id]: li
            a#friend-${friend.id} href='#' = friend.name

输出(真实输出不包括下面的缩进):

<ul id="userlist">
    <%
        # prepare a list of users
        users = UsersService.get_many(max=100, offset=0)
        friends = UsersService.get_friends_for(users)
    %>

    %for user in users:
        <li>
            <h4>
                <a href="#" id="user-${user.id}">${user.name}</a>
            </h4>
            <ul>
                %for friend in friends[user.id]:
                    <li>
                        <a href="#" id="friend-${friend.id}">${friend.name}</a>
                    </li>
                %endfor
            </ul>
        </li>
    %endfor
</ul>

模块级 Block

使用 -py! 或者 -python! 代替 <%! %> mako 标签

-py!
    import mylib
    import re

    def filter(text):
        return re.sub(r'^@', '', text)

0.9.1 新版功能: 新式写法:

---! import mylib
     import re

     def filter(text):
         return re.sub(r'^@', '', text)

Mako 标签

Plim supports a complete set of Mako Tags, except the <%doc>. The latter has been considered deprecated, since Plim itself has built-in support of multi-line comments.

注解

Plim 支持 <%doc> 以外的大部分 Mako 标签 ,Plim 本身提供了多行注释的另一种写法,因此这一标记略显多余。

-page 标签
-page args="x, y, z='default'"

输出:

<%page args="x, y, z='default'"/>

See the details of what <%page> is used for in The body() Method and Caching sections of Mako Documentation.

-include 标签
-include footer.html

或者

-include file="footer.html"

输出是一样的:

<%include file="footer.html"/>

查看 <%include> 章节 或者其它文档以获取更多内容。

-inherit 标签
-inherit base.html

或者

-inherit file="base.html"

同样输出:

<%inherit file="base.html"/>

参考 Mako 继承章节 获取更多信息。

-namespace 标签
-namespace name="helper" helpers.html

或者

-namespace file="helpers.html" name="helper"

输出:

<%namespace file="helpers.html" name="helper"/>

更多信息参见 Mako 文档 namespace 章节

-def 标签
-def account(accountname, type='regular')

或者

-def name="account(accountname, type='regular')"

输出:

<%def name="account(accountname, type='regular')">
</%def>

See Mako’s defs and blocks documentation to get more information about functions and blocks.

-block 标签

-def 不同的是,block 支持匿名:

-block
  This is an anonymous block.

当然也可以用于定义命名函数:

-block name="post_prose"
  = pageargs['post'].content

或者

-block post_prose
  = pageargs['post'].content

以上 Plim 片段都会输出相同的 Mako 标记:

<%block name="post_prose">
${pageargs['post'].content}</%block>

You can also specify other block arguments as well

- block filter="h"
  html this is some escaped html.

See Mako’s defs and blocks documentation to get more information about functions and blocks.

-call 标签

-call 可以用于定制标签。

下面的例子

-call expression="${4==4}" self:conditional
  |i'm the result

- call expression=${4==4} self:conditional
  | i'm the result

- call self:conditional
  | i'm the result

- call self:conditional

将输出:

<%self:conditional expression="${4==4}">
i'm the result
</%self:conditional>

<%self:conditional expression="${4==4}">
i'm the result
</%self:conditional>

<%self:conditional>
i'm the result
</%self:conditional>

<%self:conditional>
</%self:conditional>

更多信息参见 Mako 文档 <%nsname:defname> 章节Calling a Def with Embedded Content and/or Other Defs 章节。

-text 标签

和 Mako 类似 ,该标签中的代码将不会对 Mako 命令进行任何渲染操作,这在写 Mako 文档这样的情况下会很有帮助:

-text filter="h"
  here's some fake mako ${syntax}
  <%def name="x()">${x}</%def>

- text filter="h" here's some fake mako ${syntax}
  <%def name="x()">${x}</%def>

- text filter="h" = syntax
  <%def name="x()">${x}</%def>

-text
  here's some fake mako ${syntax}
  <%def name="x()">${x}</%def>

-text , here's some fake mako ${syntax}
  <%def name="x()">${x}</%def>

语法区别

Plim 不是完整的 Slim 移植,两者区别在于:

  1. Slim 中有 ( ' )、( =' )、( ==' ) ` 三种行内指示符(line indicators)<https://github.com/stonean/slim#line-indicators>`_ 。Plim 使用 , 代替 '

    , value
    =, value
    ==, value
    

    之所以这样改动,是为了避免这种情况下的语法歧义:

    / Is this an empty python string or a syntax error caused by the unclosed single quote?
    =''
    
    / Is this a python string 'u' ('u''' is the correct python syntax) or
      a syntax error caused by the unclosed unicode docstring?
    ='u'''
    

    然而 Python 表达式不允许以逗号起始,因此下面的例子并不会产生歧义

    / Syntax error at mako runtime caused by the unclosed single quote
    =,'
    
    / Correct and consistent. Produces an empty unicode string followed by an
      explicit trailing whitespace
    =,u''
    

    另外,使用逗号相比引号也更自然,因为我们在书写普通英文单词,如 “I’m”、“it’s” 时也会使用单引号。

  2. 和 Slim 不同的是,Plim 并不支持方括号或者花括号作为标签属性标记,只允许小括号 ()

    / For attributes wrapping we can use only parentheses
    p(title="Link Title")
      h1 class=(item.id == 1 and 'one' or 'unknown') Title
    
      / Square and curly braces are allowed only in Python and Mako expressions
      a#idx-${item.id} href=item.get_link(
                   **{'argument': 'value'}) = item.attrs['title']
    
  3. Plim 中,所有 HTML 标签 必须 完全小写:

    该限制是为了提供 隐式纯文本块(Implicit Litaral Blocks) 功能。

    doctype 5
    html
      head
        title Page Title
      body
        p
          | Hello, Explicit Literal Block!
        p
          Hello, Implicit Literal Block!
    
  4. 不必在 style and script 标签中使用 | (管道符)。

  5. Plim 并不对结构控制和内嵌的过滤器之间加以区别。

    在 Slim 中你需要写 -if-for 以及 coffee: ,但是在 Plim 中你不可以在结尾添加冒号: -if-for-coffee

  6. 和 Slim 不同,Plim 并不支持 /! 这样的 HTML 批量注释 ,在 Plim 中你只能使用原生 HTML 注释符。

扩展

标准扩展

CoffeeScript

Plim 使用 Python-CoffeeScript 包作为 JS 与 CoffeeScript 之间的桥梁。你可以使用 -coffee 作为 CoffeeScript 代码块标记。

- coffee
  # Assignment:
  number   = 42
  opposite = true

  # Conditions:
  number = -42 if opposite

  # Functions:
  square = (x) -> x * x

  # Arrays:
  list = [1, 2, 3, 4, 5]

  # Objects:
  math =
    root:   Math.sqrt
    square: square
    cube:   (x) -> x * square x

  # Splats:
  race = (winner, runners...) ->
    print winner, runners

  # Existence:
  alert "I knew it!" if elvis?

  # Array comprehensions:
  cubes = (math.cube num for num in list)
SCSS/SASS

Plim 使用 pyScss 包将 SCSS/SASS 翻译为普通的 CSS。你可以使用 -scss-sass 作为 SCSS/SASS 代码块标记。输出结果中将会自动包裹在 <style></style> 标签中。

例如:

- scss
  @option compress: no;
  .selector {
    a {
      display: block;
    }
    strong {
      color: blue;
    }
  }

输出:

<style>.selector a {
  display: block;
}
.selector strong {
  color: #00f;
}</style>
Stylus

Plim uses stylus package to translate stylus markup to plain CSS. You can start Stylus block with the -stylus construct. The output will be wrapped with <style></style> tags.

例如:

- stylus
  @import 'nib'
  body
    background: linear-gradient(top, white, black)

  border-radius()
    -webkit-border-radius arguments
    -moz-border-radius arguments
    border-radius arguments

  a.button
    border-radius 5px

输出:

<style>body {
  background: -webkit-gradient(linear, left top, left bottom, color-stop(0, #fff), color-stop(1, #000));
  background: -webkit-linear-gradient(top, #fff 0%, #000 100%);
  background: -moz-linear-gradient(top, #fff 0%, #000 100%);
  background: -o-linear-gradient(top, #fff 0%, #000 100%);
  background: -ms-linear-gradient(top, #fff 0%, #000 100%);
  background: linear-gradient(top, #fff 0%, #000 100%);
}
a.button {
  -webkit-border-radius: 5px;
  -moz-border-radius: 5px;
  border-radius: 5px;
}</style>
Markdown

Plim uses python-markdown2 package for the -markdown (or -md) extension.

例如:

- markdown
  A First Level Header
  ====================

  A Second Level Header
  ---------------------

  Now is the time for all good men to come to
  the aid of their country. This is just a
  regular paragraph.

  The quick brown fox jumped over the lazy
  dog's back.

  ### Header 3

  > This is a blockquote.
  >
  > This is the second paragraph in the blockquote.
  >
  > ## This is an H2 in a blockquote

输出:

<h1>A First Level Header</h1>

<h2>A Second Level Header</h2>

<p>Now is the time for all good men to come to
the aid of their country. This is just a
regular paragraph.</p>

<p>The quick brown fox jumped over the lazy
dog's back.</p>

<h3>Header 3</h3>

<blockquote>
    <p>This is a blockquote.</p>

    <p>This is the second paragraph in the blockquote.</p>

    <h2>This is an H2 in a blockquote</h2>
</blockquote>
reStructuredText

Plim 使用 python-markdown2 作为 -markdown (或者 -md) 扩展。

例如:

- rest
  Grid table:

  +------------+------------+-----------+
  | Header 1   | Header 2   | Header 3  |
  +============+============+===========+
  | body row 1 | column 2   | column 3  |
  +------------+------------+-----------+
  | body row 2 | Cells may span columns.|
  +------------+------------+-----------+
  | body row 3 | Cells may  | - Cells   |
  +------------+ span rows. | - contain |
  | body row 4 |            | - blocks. |
  +------------+------------+-----------+

输出:

<p>Grid table:</p>
<table border="1">
  <thead valign="bottom">
    <tr>
      <th>Header 1
      </th><th>Header 2
      </th><th>Header 3
    </th></tr>
  </thead>
  <tbody valign="top">
    <tr>
      <td>body row 1
      </td><td>column 2
      </td><td>column 3
    </td></tr>
    <tr>
      <td>body row 2
      </td><td colspan="2">Cells may span columns.
    </td></tr>
    <tr>
      <td>body row 3
      </td><td rowspan="2">Cells may<br>span rows.
      </td><td rowspan="2">
        <ul>
          <li>Cells
          </li><li>contain
          </li><li>blocks.
        </li></ul>
    </td></tr>
    <tr>
      <td>body row 4
    </td></tr>
</tbody></table>
Handlebars

handlebars 是 Plim 支持的一个特殊标签,将会翻译为 handlebars

<script type="text/x-handlebars"></script>

这对 Ember.js 开发者来说非常便利。

例如,下面的 Plim 文档

html
    body
        handlebars#testapp
            .container {{outlet}}

        handlebars#about: .container {{outlet}}

将会成为

<html>
    <body>
        <script type="text/x-handlebars" id="testapp">
            <div class="container">{{outlet}}</div>
        </script>
        <script type="text/x-handlebars" id="about">
            <div class="container">{{outlet}}</div>
        </script>
    </body>
</html>

使用定制的分析器扩展 Plim

0.9.2 新版功能.

你也可以自己扩展 Plim 标签,该功能允许你在 Plim 之上定义自己的 DSL。例如,下面的代码将定义一个新的 HTML 链接解释器,将会处理 http_url > title 形式的链接。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
# my_module.py
import re
from plim import preprocessor_factory


PARSE_HTTP_LINKS_RE = re.compile('(?P<url>https?://[^>]+)+\s+>\s+(?P<title>.*)')


def parse_http_link(indent_level, current_line, matched, source, syntax):
    url = matched.group('url')
    url_title = matched.group('title')
    rt = '<a href="{}">{}</a>'.format(url, url_title)
    return rt, indent_level, '', source


CUSTOM_PARSERS = [
    (PARSE_HTTP_LINKS_RE, parse_http_link)
]


custom_preprocessor = preprocessor_factory(custom_parsers=CUSTOM_PARSERS, syntax='mako')

parse_http_link() 函数的定义严格地遵循了 Plim API,

所有扩展解释器都应该接受 5 个参数:

  1. indent_level - an indentation level of the current line. When the parser reaches a line which indentation is lower or equal to indent_level, it returns control to a top-level function.
  2. current_line - a line which is being parsed. This is the line that has been matched by matched object at the previous parsing step.
  3. matched - an instance of re.MatchObject of the regex associated with the current parser.
  4. source - an instance of an enumerated object returned by plim.lexer.enumerate_source().
  5. syntax - an instance of one of plim.syntax.BaseSyntax children.

并返回 4 位元组:

  1. parsed_data - a string of successfully parsed data
  2. tail_indent - an indentation level of the tail line
  3. tail_line - a line which indentation level (tail_indent) is lower or equal to the input indent_level.
  4. source - an instance of enumerated object returned by plim.lexer.enumerate_source() which represents the remaining (untouched) plim markup.

现在我们已经可以像使用标准 Plim 预处理器 plim.preprocessor 一样使用 custom_preprocessor 了。

让我们使用新定义的语法来创建一个 plim 文档:

1
2
3
4
5
6
7
8
9
/ hamilton.plim
---------------
html
    head:title Alexander Hamilton
    body
        h1 Alexander Hamilton
        ul
            li: http://en.wikipedia.org/wiki/Alexander_Hamilton > Wikipedia Article
            li: http://www.amazon.com/Alexander-Hamilton-Ron-Chernow/dp/0143034758 > Full-length Biography

将会输出这样的有效 HTML (注意 -p 参数):

$ plimc -H -p my_module:custom_preprocessor hamilton.plim

输出结果:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
<html>
    <head>
        <title>Alexander Hamilton</title>
    </head>
    <body>
        <h1>Alexander Hamilton</h1>
        <ul>
            <li><a href="http://en.wikipedia.org/wiki/Alexander_Hamilton">Wikipedia Article</a></li>
            <li><a href="http://www.amazon.com/Alexander-Hamilton-Ron-Chernow/dp/0143034758">Full-length Biography</a></li>
        </ul>
    </body>
</html>

与 Web 框架集成

Pyramid

plim.adapters.pyramid_renderer 添加至项目 .ini 配置文件的 pyram`id.includes 列表中:

[app:main]
pyramid.includes =
    # ... (other packages)
    plim.adapters.pyramid_renderer

The adapter will add the .plim renderer for use in Pyramid. This can be overridden and more may be added via the config.add_plim_renderer() directive:

config.add_plim_renderer('.plm', mako_settings_prefix='mako.')

The renderer will load its configuration from a provided mako prefix in the Pyramid settings dictionary. The default prefix is ‘mako.’.

Flask

想要在 Flask 中使用 plim 只需要在项目中添加下面的代码:

from flask import Flask
from flask.ext.mako import MakoTemplates, render_template
from plim import preprocessor

app = Flask(__name__)
mako = MakoTemplates(app)
app.config['MAKO_PREPROCESSOR'] = preprocessor

@app.route('/')
def hello():
    return render_template('hello.html', name='mako')

if __name__ == "__main__":
    app.run(debug=True)

templates 目录中的 hello.html 需要写成这样:

doctype html
html
  head
    title hello ${name}
  body
    p hello ${name}

代码高亮

现在还没有专门的 plim 语法高亮工具。

不过,由于 Plim 和 Slim 的语法很相似,你可以使用 Slim 的语法高亮工具 作为替代。

编辑器支持

命令行接口

0.7.12 新版功能.

Plim 提供命令行工具 plimc 用于将 plim 源文件转换为 mako 模板。

$ plimc -h
usage: plimc [-h] [--encoding ENCODING] source target

Compile plim source files into mako files.

positional arguments:
  source               path to source plim template
  target               path to target mako template

optional arguments:
  -h, --help           show this help message and exit
  --encoding ENCODING  source file encoding

许可

Plim 源代码遵循 MIT 协议 开源。

Plim 文档遵循 创作共享 署名-相同方式分享 3.0 Unported License

作者

Plim 最初由 Maxim Avanov 开发。

贡献者(按时间顺序排列)

参见 Slim 作者列表

Changelog

Version 0.9

  • 0.9.11

    • Hotfix: Windows-样式换行(CR+LF)的错误解析修复

  • 0.9.10

    • Hotfix: 修复 plimc 无法使用当前目录下的预处理器模块问题。

  • 0.9.9

    • Hotfix: Fix UnicodeEncodeError in -def blocks with unicode strings as default argument values.
  • 0.9.8

    • Change: Stylus extension no longer depends on the nib package.
  • 0.9.7

    • Hotfix: Include requirements.txt into the distribution.
  • 0.9.6

    • Hotfix: Conditional statements parser now can handle strings containing inline tag separator sequences (#27).
  • 0.9.5

    • Hotfix: Fix plimc unicode decoding regression introduced by the previous hotfix.
  • 0.9.4

    • Hotfix: plimc no longer crashes with TypeError in Python3 environments

      when it writes bytes to sys.stdout.

  • 0.9.3

    • Hotfix: Fix UnicodeEncodeError in plimc when it writes to STDOUT.
  • 0.9.2

  • 0.9.1

  • 0.9.0

    • Change: Pyramid adapter now relies on Pyramid>=1.5a2 and pyramid_mako>=0.3.1.

    • Change: The package now depends on Mako>=0.9.0.

    • Change: Sass/Scss extension now requires PyScss>=1.2.0.post3.

    • Change: Pyramid adapter’s plim.file_extension configuration option is deprecated.

      The config.add_plim_renderer() directive is provided instead.

Version 0.8

  • 0.8.9

    • Bugfix: Use sys.maxsize instead of unavailable sys.maxint on Python 3.
  • 0.8.8

    • Hotfix: Make Plim working with a development version of pyScss for Python-3.x setups.
  • 0.8.7

    • Bugfix: Pyramid adapter is now compatible with the 1.5a2+ version of the framework.

    • Change: default template file extension

      used in pyramid bindings is changed from ”.plm” to ”.plim”.

  • 0.8.6

    • Hotfix: fixed assertion error in handlebars parser.
  • 0.8.5

  • 0.8.4

    • Hotfix: updated links to github.
  • 0.8.3

    • Hotfix: prevent lexer from parsing embedded markup inside style and script blocks.
  • 0.8.2

    • Feature: added support for Embedded Markup.
    • Feature: plimc utility is now able to output plain HTML.
  • 0.8.1

  • 0.8.0

    • Feature: added support for dynamic attributes unpacker (an equivalent to Slim’s splat attributes).

Version 0.7

  • 0.7.14
    • Hotfix: fixed bug with unicode handling.
  • 0.7.13
    • Hotfix: fixed bug with static unicode attributes.
  • 0.7.12
    • Unnecessary newline characters at the end of literal blocks have been removed.
    • Added the command-line tool plimc.
  • 0.7.11
    • Fixed bug that had to do with incorrect parsing of multi-line dynamic class attributes.
    • Fixed bug that had to do with passing incorrect data to plim parser in babel adapter.
  • 0.7.10 Fixed bug with unicode error in python block. Thanks to sqrabs@github!
  • 0.7.9 Added babel message extraction plugin.
  • 0.7.8 Expanded range of possible numeric values that don’t require double-quoting.
  • 0.7.7
    • Fixed bug with linebreaks without trailing newline character.
    • Fixed bug with missing explicit whitespace after =, and ==, line indicators.
  • 0.7.6 Fixed bug with incorrect parsing of static boolean attributes.
  • 0.7.5 Fixed bug with comment and content blocks separated by empty lines.
  • 0.7.4 Added -stylus extension.
  • 0.7.3 Fix bug with literal one-liners.
  • 0.7.1 Fixed installation error caused by missing README.rst.
  • 0.7.0 Initial public release.

Indices and tables