perlpodspec - 纯文本文档:格式规范和说明
本文档是关于 Pod 标记语言的详细说明。大多数人只需要阅读 perlpod 即可了解如何编写 Pod,但本文档可能会回答一些关于解析和渲染 Pod 的偶然问题。
在本文件中,“必须”/“禁止”,“应该”/“不应该”和“可以”具有其惯例意义(参见 RFC 2119):“X 必须做 Y”意味着如果 X 不做 Y,则违反本规范,应予以修复。“X 应该做 Y”意味着建议这样做,但如果存在正当理由,X 可以不做 Y。“X 可以做 Y”仅仅表示 X 可以随意做 Y(尽管由读者判断“我认为如果 X 做 Y 会很好”与“如果 X 做 Y 我不会介意”之间的任何含义)。
值得注意的是,当我提到“解析器应该做 Y”时,如果调用应用程序明确要求解析器不做 Y,则解析器可能不做 Y。我通常将其表述为“解析器默认情况下应该做 Y”。这并不要求解析器提供关闭 Y 功能的选项(例如,在逐字段落中扩展制表符),尽管这意味着可能提供此类选项。
Pod 嵌入在文件中,通常是 Perl 源代码文件中,但您也可以编写一个只包含 Pod 的文件。
文件中的行由零个或多个非换行符组成,以换行符或文件结尾符结束。
换行符序列通常是一个平台相关的概念,但 Pod 解析器应该理解它表示 CR(ASCII 13)、LF(ASCII 10)或 CRLF(ASCII 13 后紧跟 ASCII 10),以及任何其他系统特定的含义。文件中的第一个 CR/CRLF/LF 序列可用于识别用于解析文件其余部分的换行符序列。
空行是仅包含零个或多个空格(ASCII 32)或制表符(ASCII 9)且以换行符或文件结尾符结束的行。非空行是包含一个或多个除空格或制表符以外的字符(并以换行符或文件结尾符结束)的行。
(注意:许多较旧的 Pod 解析器不接受由空格/制表符和换行符组成的行作为空行。它们认为只有不包含任何字符且以换行符结束的行才是空行。)
空白在本文件中用作空格、制表符和换行符序列的统称。(就其本身而言,此术语通常是指字面空白。也就是说,Pod 源代码中的空白字符序列,而不是“E<32>”,它是一个表示空白字符的格式化代码。)
Pod 解析器是一个用于解析 Pod 的模块(无论这是否涉及调用回调、构建解析树或直接格式化它)。Pod 格式化器(或Pod 翻译器)是一个模块或程序,它将 Pod 转换为其他格式(HTML、纯文本、TeX、PostScript、RTF)。Pod 处理器可能是一个格式化器或翻译器,也可能是一个对 Pod 执行其他操作的程序(例如,统计字数、扫描索引点等)。
Pod 内容包含在Pod 块中。Pod 块以匹配m/\A=[a-zA-Z]/
的行开头,并一直持续到下一行匹配m/\A=cut/
的行,或者如果不存在m/\A=cut/
行,则持续到文件末尾。
请注意,解析器不应区分看起来像 Pod 但在引号字符串中的内容,例如 here 文档。
在 Pod 块中,存在Pod 段落。Pod 段落由非空文本行组成,这些行之间用一个或多个空行隔开。
出于 Pod 处理的目的,Pod 块中存在四种类型的段落。
命令段落(也称为“指令”)。此段落的首行必须匹配m/\A=[a-zA-Z]/
。命令段落通常只有一行,例如:
=head1 NOTES
=item *
但它们可能跨越多行(非空行)。
=for comment
Hm, I wonder what it would look like if
you tried to write a BNF for Pod from this.
=head3 Dr. Strangelove, or: How I Learned to
Stop Worrying and Love the Bomb
某些命令段落允许在其内容中使用格式化代码(即,在匹配m/\A=[a-zA-Z]\S*\s*/
的部分之后),例如:
=head1 Did You Remember to C<use strict;>?
换句话说,"head1" 的 Pod 处理程序将对 "Did You Remember to C<use strict;>?" 应用与对普通段落相同的处理(即,像 "C<...>" 这样的格式化代码被解析并可能被适当地格式化,并且空格形式的文字空格和/或制表符并不重要)。
逐字段落。此段落的首行必须是文字空格或制表符,并且此段落不能位于 "=begin 标识符",... "=end 标识符" 序列中,除非 "标识符" 以冒号 (":") 开头。也就是说,如果一个段落以文字空格或制表符开头,但位于 "=begin 标识符",... "=end 标识符" 区域内,那么它就是一个数据段落,除非 "标识符" 以冒号开头。
空格在逐字段落中是重要的(尽管在处理中,制表符可能会被扩展)。
普通段落。如果一个段落的首行既不匹配m/\A=[a-zA-Z]/
也不匹配m/\A[ \t]/
,并且它不在 "=begin 标识符",... "=end 标识符" 序列中,除非 "标识符" 以冒号 (":") 开头,那么它就是一个普通段落。
一个数据段落。这是一个位于“=begin 标识符”...“=end 标识符”序列中的段落,其中“标识符”不以字面冒号(“:”)开头。从某种意义上说,数据段落根本不属于 Pod(即,实际上它是“带外”的),因为它不受大多数 Pod 解析的约束;但它在这里被指定,因为 Pod 解析器需要能够为它调用一个事件,或者以某种形式将其存储在解析树中,或者至少只是解析周围它。
例如:考虑以下段落
# <- that's the 0th column
=head1 Foo
Stuff
$foo->bar
=cut
这里,“=head1 Foo”和“=cut”是命令段落,因为每行的第一行都匹配m/\A=[a-zA-Z]/
。“[空格][空格]$foo->bar”是一个逐字段落,因为它的第一行以字面空格字符开头(并且周围没有“=begin”...“=end”区域)。
如果标识符不以冒号开头,“=begin 标识符”...“=end 标识符”命令会阻止它们包围的段落被解析为普通段落或逐字段落。这将在“关于数据段落和“=begin/=end”区域”部分中详细讨论。
本节旨在补充和澄清“perlpod 中的命令段落”中的讨论。这些是当前识别的 Pod 命令
此命令表示段落其余部分中的文本是标题。该文本可能包含格式代码。示例
=head1 Object Attributes
=head3 What B<Not> to Do!
=head5
和=head6
都在 2020 年添加,可能不受所有 Pod 解析器的支持。Pod::Simple 3.41 于 2020 年 10 月发布,支持这两者,为所有基于Pod::Simple的 Pod 解析器提供支持。
此命令表示此段落开始一个 Pod 块。(如果我们已经在 Pod 块的中间,此命令没有任何效果。)如果此命令段落中在“=pod”之后有任何文本,则必须忽略它。示例
=pod
This is a plain Pod paragraph.
=pod This text is ignored.
此命令表示此行是先前启动的 Pod 块的结束。如果此行在“=cut”之后有任何文本,则必须忽略它。示例
=cut
=cut The documentation ends here.
=cut
# This is the first line of program text.
sub foo { # This is the second.
尝试使用“=cut”命令启动 Pod 块是错误的。在这种情况下,Pod 处理器必须停止解析输入文件,并且默认情况下必须发出警告。
此命令表示这是一个列表/缩进区域的开始。如果在“=over”之后有任何文本,它必须仅包含一个非零正数。此数字的语义将在下面进一步的“关于 =over...=back 区域”部分中解释。格式代码不会扩展。示例
=over 3
=over 3.5
=over
此命令表示列表中的一个项目从这里开始。格式化代码将被处理。本段剩余部分中(可选)文本的语义将在下面更详细的 "关于 =over...=back 区域" 部分中解释。示例
=item
=item *
=item *
=item 14
=item 3.
=item C<< $thing->stuff(I<dodad>) >>
=item For transporting us beyond seas to be tried for pretended
offenses
=item He is at this time transporting large armies of foreign
mercenaries to complete the works of death, desolation and
tyranny, already begun with circumstances of cruelty and perfidy
scarcely paralleled in the most barbarous ages, and totally
unworthy the head of a civilized nation.
此命令表示这是由最近的 "=over" 命令开始的区域的结束。它不允许在 "=back" 命令之后有任何文本。
这将以下段落(直到匹配的 "=end formatname")标记为某种特殊类型的处理。除非 "formatname" 以冒号开头,否则包含的非命令段落是数据段落。但是,如果 "formatname" *确实* 以冒号开头,那么非命令段落是普通段落或数据段落。这将在 "关于数据段落和 "=begin/=end" 区域" 部分中详细讨论。
建议 formatname 匹配正则表达式 m/\A:?[-a-zA-Z0-9_]+\z/
。formatname 后的空格后的所有内容都是一个参数,格式化程序在处理此区域时可能会使用它。此参数不能在 "=end" 段落中重复。实现者应该预料到 "=begin"/"=end"/"=for" 的第一个参数的语义和语法在未来会扩展。
这标志着由匹配的 "=begin formatname" 区域打开的区域的结束。如果 "formatname" 不是最近打开的 "=begin formatname" 区域的 formatname,那么这是一个错误,并且必须生成错误消息。这将在 "关于数据段落和 "=begin/=end" 区域" 部分中详细讨论。
这与以下内容同义
=begin formatname
text...
=end formatname
也就是说,它创建一个由单个段落组成的区域;如果 "formatname" 以冒号开头,则该段落将被视为普通段落;如果 "formatname" *不* 以冒号开头,那么 "text..." 将构成数据段落。无法使用 "=for formatname text..." 来表达 "text..." 作为逐字段落。
此命令应该出现在文档的早期(至少在任何非 US-ASCII 数据之前!),声明此文档以编码 encodingname 编码,它必须是 Encode 识别的编码名称。(Encode 支持的编码列表,在 Encode::Supported 中,在这里很有用。)如果 Pod 解析器无法解码声明的编码,它应该发出警告,并且可能会完全中止解析文档。
如果一个文档包含多个“=encoding”行,则应视为错误。Pod 处理器可能会默默地容忍这种情况,如果非第一个“=encoding”行只是第一个行的重复(例如,如果存在“=encoding utf8”行,之后又出现另一个“=encoding utf8”行)。但如果同一个文档中存在矛盾的“=encoding”行(例如,如果文档开头有“=encoding utf8”,后面有“=encoding big5”),Pod 处理器应该报错。识别 BOM 的 Pod 处理器也可能会报错,如果它们看到与 BOM 矛盾的“=encoding”行(例如,如果一个带有 UTF-16LE BOM 的文档包含“=encoding shiftjis”行)。
如果 Pod 处理器看到任何除上面列出的命令之外的命令(如“=head”,“=haed1”,“=stuff”,“=cuttlefish”,“=w123”),则该处理器默认应将其视为错误。它不能处理以该命令开头的段落,默认情况下应将其作为错误警告,并可能中止解析。Pod 解析器可以允许特定应用程序将上述已知命令列表扩展,并为每个附加命令指定是否应处理格式化代码。
本规范的未来版本可能会添加其他命令。
(注意,在本规范和 perlpod 的早期草案中,格式化代码被称为“内部序列”,这个术语可能仍然存在于 Pod 解析器的文档中,以及 Pod 处理器的错误消息中。)
格式化代码有两种语法
格式化代码以一个大写字母(仅限 US-ASCII [A-Z])开头,后面跟着一个“<”,任意数量的字符,最后以第一个匹配的“>”结束。例如
That's what I<you> think!
What's C<CORE::dump()> for?
X<C<chmod> and C<unlink()> Under Different Operating Systems>
格式化代码以一个大写字母(仅限 US-ASCII [A-Z])开头,后面跟着两个或多个“<”,一个或多个空格字符,任意数量的字符,一个或多个空格字符,最后以第一个匹配的两个或多个“>”序列结束,其中“>”的数量等于此格式化代码开头“<”的数量。例如
That's what I<< you >> think!
C<<< open(X, ">>thing.dat") || die $! >>>
B<< $foo->bar(); >>
使用这种语法,"C<<<"后面的空格字符和">>>"(或任何字母)前面的空格字符不可渲染。它们不代表空格,仅仅是格式化代码本身的一部分。也就是说,这些都是同义词
C<thing>
C<< thing >>
C<< thing >>
C<<< thing >>>
C<<<<
thing
>>>>
等等。
最后,多角度括号形式不改变对嵌套格式化代码的解释,这意味着以下四个示例行在含义上是相同的
B<example: C<$a E<lt>=E<gt> $b>>
B<example: C<< $a <=> $b >>>
B<example: C<< $a E<lt>=E<gt> $b >>>
B<<< example: C<< $a E<lt>=E<gt> $b >> >>>
在解析 Pod 时,一个特别棘手的部分是正确解析(可能嵌套的!)格式化代码。实现者应该参考 Pod::Parser 中的 parse_text
例程中的代码,作为正确实现的示例。
I<text>
-- 斜体文本请参阅 "perlpod 中的格式化代码" 中的简要讨论。
B<text>
-- 粗体文本请参阅 "perlpod 中的格式化代码" 中的简要讨论。
C<code>
-- 代码文本请参阅 "perlpod 中的格式化代码" 中的简要讨论。
F<filename>
-- 文件名样式请参阅 "perlpod 中的格式化代码" 中的简要讨论。
X<topic name>
-- 索引条目请参阅 "perlpod 中的格式化代码" 中的简要讨论。
此代码不同寻常,因为大多数格式化程序会完全丢弃此代码及其内容。其他格式化程序将使用不可见的代码来渲染它,这些代码可用于构建当前文档的索引。
Z<>
-- 空(零效果)格式化代码在 "perlpod 中的格式化代码" 中简要讨论。
此代码不同寻常,因为它不应该有任何内容。也就是说,如果处理器看到 Z<potatoes>
,它可能会报错。无论它是否报错,potatoes 文本都应该被忽略。
L<name>
-- 超链接此代码的复杂语法在 "perlpod 中的格式化代码" 中进行了详细讨论,实现细节将在下面的 "关于 L<...> 代码" 中讨论。解析 L<content> 的内容很棘手。值得注意的是,必须检查内容是否看起来像 URL,或者是否必须在文字 "|" 和/或 "/"(按正确的顺序!)上拆分,等等,在 E<...> 代码解析之前。
E<escape>
-- 字符转义参见 "perlpod 中的格式化代码",以及 "关于实现 Pod 处理器的注意事项" 中的几个要点。
S<text>
-- 文本包含不间断空格此格式化代码语法简单,但语义复杂。它的含义是,此代码的可打印内容中的每个空格都代表一个不间断空格。
考虑
C<$x ? $y : $z>
S<C<$x ? $y : $z>>
两者都表示由 "$x"、一个空格、"?"、一个空格、":"、一个空格和 "$z" 组成的等宽字体(c[ode] 风格)文本。区别在于,在后者中,使用 S 代码,这些空格不是“普通”空格,而是不间断空格。
如果 Pod 处理器看到任何不在上述列表中的格式化代码(如 "N<...>" 或 "Q<...>" 等),则该处理器默认情况下必须将其视为错误。Pod 解析器可能允许特定应用程序将上述已知格式化代码列表扩展;Pod 解析器甚至可能允许为每个附加命令指定是否需要某种形式的特殊处理,就像 L<...> 一样。
此规范的未来版本可能会添加其他格式化代码。
历史说明:一些较旧的 Pod 处理器不会将 ">" 视为 "C<" 代码的结束,如果 ">" 紧接在 "-" 之前。这是为了使
C<$foo->bar>
解析为等效于
C<$foo-E<gt>bar>
而不是等效于包含 "C" 格式化代码的 "$foo-",以及 "C" 格式化代码之外的 "bar>"。这个问题已通过添加以下语法解决
C<< $foo->bar >>
符合标准的解析器不得将 "->" 视为特殊字符。
格式化代码绝对不能跨段落。如果在一个段落中打开一个代码,并且在该段落结束时没有找到结束代码,则 Pod 解析器必须关闭该格式化代码,并应发出警告(如“段落 123 行开始处的 I 代码未终止:'时间对象不是...'”)。因此,这两个段落
I<I told you not to do this!
Don't make me say it again!>
...不应解析为两个斜体段落(I 代码在一个段落中开始,在另一个段落中开始)。相反,第一个段落应该生成一个警告,但除此之外,上述代码必须解析为
I<I told you not to do this!>
Don't make me say it again!E<gt>
(在 SGMLish 行话中,所有 Pod 命令都类似于块级元素,而所有 Pod 格式化代码都类似于内联级元素。)
以下是关于 Pod 处理的各种要求和建议。
Pod 格式化程序应该容忍逐字块中的任意长度的线条,即使这意味着必须将它们分解(对于非常长的线条可能需要分解多次)以避免文本超出页面边缘。Pod 格式化程序可能会警告这种断行。对于超过 100 个字符的线条,这种警告尤其适用,因为它们通常不是故意的。
Pod 解析器必须识别所有三种众所周知的换行符格式:CR、LF 和 CRLF。参见 perlport。
Pod 解析器应该接受任意长度的输入行。
由于 Perl 识别文件开头的 Unicode 字节顺序标记,表示该文件以 UTF-16(无论是大端序还是小端序)或 UTF-8 编码,因此 Pod 解析器也应该这样做。否则,如果文件中的第一个高位字节序列似乎是有效的 UTF-8 序列,则字符编码应理解为 UTF-8,否则应理解为 CP-1252(本规范的早期版本使用 Latin-1 而不是 CP-1252)。
本规范的未来版本可能会指定 Pod 如何接受其他编码。可以推测,在 Pod 解析中处理其他编码的方式与 XML 解析相同:无论特定 Pod 文件声明的编码是什么,内容都应该在内存中以 Unicode 字符存储。
众所周知的 Unicode 字节顺序标记如下:如果文件以两个字面字节值 0xFE 0xFF 开头,则这是大端序 UTF-16 的 BOM。如果文件以两个字面字节值 0xFF 0xFE 开头,则这是小端序 UTF-16 的 BOM。在 ASCII 平台上,如果文件以三个字面字节值 0xEF 0xBB 0xBF 开头,则这是 UTF-8 的 BOM。一种可移植到 EBCDIC 平台的机制是
my $utf8_bom = "\x{FEFF}";
utf8::encode($utf8_bom);
在 ASCII 平台上,一种简单但通常足够有效的启发式方法,用于测试无 BOM 文件(无论是在代码中还是在 Pod 中!)中的第一个高位字节序列,以查看该序列是否有效作为 UTF-8(RFC 2279),是检查该序列中的第一个字节是否在 0xC2 - 0xFD 范围内,并且下一个字节是否在 0x80 - 0xBF 范围内。如果是,解析器可以得出结论,该文件是 UTF-8,并且文件中的所有高位序列都应假定为 UTF-8。否则,解析器应将文件视为 CP-1252。(更好的检查,并且在 EBCDIC 平台上也能正常工作,是将序列的副本传递给 utf8::decode(),它对序列执行完整有效性检查,如果它是有效的 UTF-8,则返回 TRUE,否则返回 FALSE。此函数始终预先加载,速度很快,因为它是用 C 编写的,并且最多只调用一次,因此您无需出于性能考虑而避免它。)在真正非 UTF-8 文件中的第一个高位序列碰巧看起来像 UTF-8 的极不可能的情况下,可以通过在该行之前添加包含明显不是有效 UTF-8 的高位序列的注释行来满足我们的启发式方法(以及任何更智能的启发式方法)。仅包含“#”、一个重音 e 和任何非高位字节的行就足以确定该文件的编码。
Pod 处理器必须将“=for [label] [content...]”段落视为与“=begin [label]”段落、内容和“=end [label]”段落相同。(解析器可能会将这两种结构合并,或者保持它们不同,预期格式化程序仍然会将它们视为相同。)
当将 Pod 渲染为允许注释的格式(即,除了纯文本之外的几乎所有格式)时,Pod 格式化程序必须插入注释文本,标识其名称和版本号,以及它可能用于处理 Pod 的任何模块的名称和版本号。 最小的例子
%% POD::Pod2PS v3.14159, using POD::Parser v1.92
<!-- Pod::HTML v3.14159, using POD::Parser v1.92 -->
{\doccomm generated by Pod::Tree::RTF 3.14159 using Pod::Tree 1.08}
.\" Pod::Man version 3.14159, using POD::Parser version 1.92
格式化程序还可以插入其他注释,包括:Pod 格式化程序程序的发布日期、格式化程序作者的联系地址、当前时间、输入文件名、生效的格式化选项、使用的 Perl 版本等。
格式化程序还可以选择将错误/警告作为注释,除了或代替以其他方式发出它们(如向 STDERR 发送消息,或 die
ing)。
Pod 解析器可以向 STDERR 发出警告或错误消息(“未知 E 代码 E<zslig>!”)(无论是通过打印到 STDERR,还是 warn
ing/carp
ing,还是 die
ing/croak
ing),但必须允许抑制所有此类 STDERR 输出,并允许使用其他方式报告错误/警告,无论是通过触发回调,还是在文档对象的某个属性中记录错误,或者使用类似的非侵入性机制——甚至通过在解析后的文档形式的末尾附加一个“Pod 错误”部分。
在文档异常异常的情况下,Pod 解析器可能会中止解析。 即使那样,也要避免使用 die
ing/croak
ing; 尽可能,解析器库可以简单地关闭输入文件,并在(部分)内存中文档的末尾添加类似“*** 格式化中止 ***”的文本。
在理解格式化代码(如 E<...>、B<...>)的段落中(即不是逐字段落,而是包括普通段落和产生可渲染文本的命令段落,如“=head1”),文字空格通常被认为是“不重要的”,因为一个文字空格与任何(非零)数量的文字空格、文字换行符和文字制表符具有相同的含义(只要这不会产生空白行,因为空白行会终止段落)。 Pod 解析器应该压缩每个处理过的段落中的文字空格,但可以提供一个选项来覆盖此选项(因为某些处理任务不需要它),或者可以遵循其他特殊规则(例如,专门处理句点-空格-空格或句点-换行符序列)。
Pod 解析器默认情况下不应尝试将撇号(')和引号(")强制转换为智能引号(小 9's、66's、99's 等),也不应尝试将反引号(`)转换为除单个反引号字符以外的任何其他字符(与打开的引号字符不同!),也不应将 "--" 转换为除两个减号以外的任何其他字符。 它们绝不对 C<...> 格式化代码中的文本执行任何这些操作,并且绝不对逐字段落中的文本执行任何这些操作。
当将 Pod 渲染成包含两种连字符 (-) 的格式时,一种是非断行连字符,另一种是可断行连字符(例如在 "object-oriented" 中,可以跨行拆分为 "object-",换行,"oriented"),格式化程序鼓励将 "-" 普遍翻译为非断行连字符,但可以应用启发式方法将其中一些转换为可断行连字符。
Pod 格式化程序应尽力避免将 Perl 代码中的单词跨行拆分。例如,在某些格式化系统中,"Foo::Bar" 被视为可以跨行拆分为 "Foo::" 换行 "Bar" 甚至 "Foo::-" 换行 "Bar"。应尽可能避免这种情况,要么通过禁用单词中间的所有断行,要么通过将包含内部标点的特定单词用 "不要跨行断开" 代码包装起来(在某些格式中,这可能不是单个代码,而是指在单词中每个字符对之间插入非断行零宽度空格)。
Pod 解析器应默认在处理时展开逐字段落中的制表符,然后再将其传递给格式化程序或其他处理器。解析器也可以允许覆盖此选项。
Pod 解析器应默认在将普通段落和逐字段落传递给格式化程序之前,从其末尾删除换行符。例如,虽然您现在正在阅读的段落可以在 Pod 源代码中被认为以(并包含)结束它的换行符结尾,但它应该被处理为以(并包含)结束本句的句号结尾。
Pod 解析器在报告错误时,应尽力报告一个近似行号("Paragraph #52 中嵌套的 E<>,位于 Thing/Foo.pm 的第 633 行附近!"),而不是仅仅指出段落号("Thing/Foo.pm 的 Paragraph #52 中嵌套的 E<>!")。如果这有困难,段落号至少应该附带段落中的摘录("Thing/Foo.pm 的 Paragraph #52 中嵌套的 E<>,该段落以 'Read/write accessor for the C<interest rate> attribute...' 开头")。
Pod 解析器在依次处理一系列逐字段落时,应将其视为一个包含空行的较大的逐字段落。即,这两行,它们之间有一个空行
use Foo;
print Foo->VERSION
应该在传递给格式化程序或其他处理器之前统一成一个段落("\tuse Foo;\n\n\tprint Foo->VERSION")。解析器也可以允许覆盖此选项。
虽然这在基于事件的 Pod 解析器中可能过于繁琐,但对于返回解析树的解析器来说,这很简单。
建议 Pod 格式化程序在可行的情况下避免将短的逐字段落(例如,少于 12 行)拆分到不同的页面。
Pod 解析器必须将仅包含空格和/或制表符的行视为“空行”,例如用于分隔段落。(一些较旧的解析器只识别两个相邻的换行符作为“空行”,但不会识别换行符、空格和换行符作为空行。这是一种不符合规范的行为。)
Pod 格式化程序/处理器作者应尽一切努力避免编写自己的 Pod 解析器。CPAN 中已经存在多个解析器,它们具有多种接口样式——其中一个解析器 Pod::Simple 随现代版本的 Perl 一起提供。
Pod 文档中的字符可以通过字面量、E<n> 代码中的数字或等效的助记符来表示,例如 E<eacute> 等效于 E<233>。这些数字是 Latin1/Unicode 值,即使在 EBCDIC 平台上也是如此。
当使用 E<n> 数字代码引用字符时,范围为 32-126 的数字指的是那些众所周知的 US-ASCII 字符(Unicode 中也定义了这些字符,含义相同),所有 Pod 格式化程序都必须忠实地渲染这些字符。E<> 数字在 0-31 和 127-159 范围内的字符不应使用(既不作为字面量,也不作为 E<number> 代码),除了换行符的字面字节序列(ASCII 13、ASCII 13 10 或 ASCII 10)和制表符(ASCII 9)。
范围为 160-255 的数字指的是 Latin-1 字符(Unicode 中也定义了这些字符,含义相同)。大于 255 的数字应理解为指的是 Unicode 字符。
请注意,一些格式化程序无法可靠地渲染 32-126 之外的字符;许多格式化程序能够处理 32-126 和 160-255,但不能处理大于 255 的字符。
除了众所周知的“E<lt>”和“E<gt>”分别代表小于号和大于号之外,Pod 解析器还必须理解“E<sol>”代表“/”(斜杠)和“E<verbar>”代表“|”(竖线)。Pod 解析器还应该理解“E<lchevron>”和“E<rchevron>”作为字符 171 和 187 的遗留代码,即“左向双角引号”=“左向双引号”和“右向双角引号”=“右向双引号”。(它们看起来像“<<”和“>>” ,现在最好用 HTML/XHTML 代码“E<laquo>”和“E<raquo>”表示。)
Pod 解析器应该理解所有在最新 XHTML 规范中定义的实体声明中的“E<html>”代码,位于 www.W3.org
。Pod 解析器必须至少理解定义 160-255 范围内字符的实体(Latin-1)。当遇到未知的“E<identifier>”代码时,Pod 解析器不应该简单地将其替换为空字符串(至少默认情况下),而是可以将其作为包含字面字符 E、小于号、identifier、大于号的字符串传递。或者,Pod 解析器可以提供另一种选择,即通过为这些代码触发事件或在内存文档树中添加特殊节点类型来处理这些未知的“E<identifier>”代码。这些“E<identifier>”可能对某些处理器具有特殊含义,或者某些处理器可能会选择将它们添加到特殊的错误报告中。
Pod 解析器还必须支持 XHTML 代码“E<quot>”代表字符 34(双引号,"),“E<amp>”代表字符 38(& 符号,&),以及“E<apos>”代表字符 39(撇号,')。
请注意,在所有“E<whatever>”的情况下,whatever(无论是 htmlname 还是任何基数的数字)都必须仅包含字母数字字符 - 也就是说,whatever 必须匹配 m/\A\w+\z/
。因此 "E< 0 1 2 3 >" 是无效的,因为它包含空格,而空格不是字母数字字符。这可能不需要 Pod 处理器进行特殊处理;" 0 1 2 3 " 在任何基数中都不像数字,因此它可能会在 HTML 类名称表中查找。由于不存在(也不可能存在)名为 " 0 1 2 3 " 的 HTML 类实体,因此这将被视为错误。但是,Pod 处理器可能会将 "E< 0 1 2 3 >" 或 "E<e-acute>" 视为语法无效,可能会产生与仅仅是未知(但理论上有效)的 htmlname(如 "E<qacute>" [sic])所产生的错误消息(或警告,或事件)不同的错误消息。但是,Pod 解析器不需要进行这种区分。
请注意,E<number> 不能被解释为仅仅是“当前/本机字符集中的代码点 number”。它始终只表示“Unicode 中代码点 number 所代表的字符”。(这与 &#number 的语义相同;在 XML 中。)
这很可能要求许多格式化程序具有表格,将可处理的 Unicode 代码点(例如,用于 e-acute 字符的“\xE9”)映射到在目标输出格式中传递这些序列所需的转义序列或代码。例如,一个转换为 *roff 的转换器会知道“\xE9”(无论是直接传递还是通过 E<...> 序列传递)应该传递为“e\\*'”。类似地,在 Mac OS 应用程序窗口中渲染 Pod 的程序,可能需要知道“\xE9”映射到 MacRoman 编码中的代码点 142,该编码(在撰写本文时)是 Mac OS 的本机编码。对于常见的输出格式,这些 Unicode2whatever 映射可能已经广泛可用。(这些映射可能不完整!实现者不需要为了渲染切罗基音节文字、伊特鲁里亚语符文、拜占庭音乐符号或 Unicode 可以编码的任何其他奇怪事物而费尽心思。)如果 Pod 文档使用在这些映射中找不到的字符,则格式化程序应该将其视为不可渲染的字符。
如果,令人惊讶的是,Pod 格式化程序的实现者无法找到目标格式中满意的预先存在的 Unicode 字符到转义字符的映射表(例如,一个不错的 Unicode 字符到 *roff 转义字符的表),那么就需要构建这样的表。如果您遇到这种情况,应该从 0x00A0 - 0x00FF 范围内的字符开始,这些字符主要是常用的重音字符。然后(根据耐心和一丝不苟的程度)继续处理 (X)HTML 标准组认为足够重要以至于值得用助记符来表示的字符。这些字符在 www.W3.org 网站的 (X)HTML 规范中声明。在撰写本文时(2001 年 9 月),最新的实体声明文件是
http://www.w3.org/TR/xhtml1/DTD/xhtml-lat1.ent
http://www.w3.org/TR/xhtml1/DTD/xhtml-special.ent
http://www.w3.org/TR/xhtml1/DTD/xhtml-symbol.ent
然后,您可以继续处理 0x2000-0x204D 范围内任何剩余的值得注意的 Unicode 字符(请参阅 www.unicode.org 上的字符表),以及任何其他吸引您注意力的字符。例如,在 xhtml-symbol.ent 中,有以下条目
<!ENTITY infin "∞"> <!-- infinity, U+221E ISOtech -->
虽然映射 "infin" 到字符 "\x{221E}"(希望)已经被 Pod 解析器处理过了,但该字符出现在此文件中意味着它足够重要,需要包含在格式化程序的表中,该表将值得注意的 Unicode 字符映射到渲染它们所需的代码。因此,例如,对于 Unicode 到 *roff 的映射,这将需要以下条目
"\x{221E}" => '\(in',
人们热切地希望,在未来,越来越多的格式(和格式化程序)将直接支持 Unicode 字符(就像 (X)HTML 使用 ∞
、∞
或 ∞
一样),从而减少对 Unicode 到 my_escapes 的特殊映射的需求。
对于单个 Pod 格式化程序来说,当遇到无法渲染的字符时(这与解析器无法解析为任何内容的未知 E<thing> 序列不同,无论是否可渲染),需要表现出良好的判断力。一个好的做法是将带重音的拉丁字母(如 "E<eacute>"/"E<233>")映射到相应的无重音的 US-ASCII 字母(如简单的字符 101,"e"),但显然这通常不可行,无法渲染的字符可能被表示为 "?",或类似的字符。在尝试合理的回退(例如,从 E<233> 到 "e")时,Pod 格式化程序可以使用 Pod::Escapes 中的 %Latin1Code_to_fallback 表,或者如果可用,可以使用 Text::Unidecode。
例如,这段 Pod 文本
magic is enabled if you set C<$Currency> to 'E<euro>'.
可以渲染为:"magic is enabled if you set $Currency
to '?'" 或 "magic is enabled if you set $Currency
to '[euro]'",或者 "magic is enabled if you set $Currency
to '[x20AC]',等等。
Pod 格式化程序还可以在一个注释或警告中记录遇到的无法渲染的字符列表。
E<...> 可以自由地出现在任何格式化代码中(除了在另一个 E<...> 或 Z<> 中)。也就是说,“X<The E<euro>1,000,000 Solution>” 是有效的,同样,“L<The E<euro>1,000,000 Solution|Million::Euros>” 也是有效的。
一些 Pod 格式化程序输出到实现不间断空格作为单个字符的格式(我称之为“NBSP”),而另一些则输出到实现不间断空格作为用“不要跨行断开”代码包装的空格的格式。请注意,在 Pod 层面上,两种类型的代码都可能出现:Pod 可以包含 NBSP 字符(无论是作为字面量,还是作为“E<160>” 或“E<nbsp>” 代码);Pod 还可以包含“S<foo I<bar> baz>” 代码,其中此类代码中的“普通空格”(字符 32)被视为不间断空格。Pod 解析器应考虑支持可选地将“S<foo I<bar> baz>” 解析为“fooNBSPI<bar>NBSPbaz”,反之亦然,可选地将由 NBSP 连接的词组解析为每个词组都在 S<...> 代码中,以便格式化程序可以使用最适合输出格式要求的表示形式。
一些处理器可能会发现,通过将 S 内容下解析树中的每个空格替换为 NBSP,S<...>
代码最容易实现。但请注意:替换应该不应用于所有文本中的空格,而只应用于可打印文本中的空格。(这种区别在 Pod 解析器实现的特定树/事件模型中可能明显,也可能不明显。)例如,考虑以下不寻常的情况
S<L</Autoloaded Functions>>
这意味着可见链接文本中间的空格不能跨行断开。换句话说,它与以下内容相同
L<"AutoloadedE<160>Functions"/Autoloaded Functions>
但是,错误应用的空格到 NBSP 替换可能会(错误地)生成与以下内容等效的内容
L<"AutoloadedE<160>Functions"/AutoloadedE<160>Functions>
...这几乎肯定无法作为超链接使用(假设此格式化程序输出支持超文本的格式)。
格式化程序可以选择不支持 S 格式代码,尤其是在输出格式根本没有 NBSP 字符/代码,也没有“不要跨行断开这些内容”代码的情况下。
除了上面讨论的 NBSP 字符外,实现者还需注意 Latin-1 中另一个“特殊”字符的存在,即“软连字符”字符,也称为“可选连字符”,即 E<173>
= E<0xAD>
= E<shy>
)。此字符表示一个可选的连字符位置。也就是说,它通常不显示,但在格式化程序在该位置断词时可能会显示为“-”。Pod 格式化程序应根据需要执行以下操作之一:1) 使用具有相同含义的代码呈现它(例如,RTF 中的“\-”),2) 将其传递,期望格式化程序理解此字符,或 3) 删除它。
例如
sigE<shy>action
manuE<shy>script
JarkE<shy>ko HieE<shy>taE<shy>nieE<shy>mi
这些信号告诉格式化程序,如果要对“sigaction”或“manuscript”进行连字符处理,则应将其处理为“sig-[换行符]action”或“manu-[换行符]script”(如果它不进行连字符处理,则 E<shy>
根本不会显示)。如果要对“Jarkko”和/或“Hietaniemi”进行连字符处理,则只能在有 E<shy>
代码的位置进行。
实际上,预计此字符不会经常使用,但格式化程序应支持它或删除它。
如果您认为需要向 Pod 添加新命令(例如,"=biblio" 命令),请考虑是否可以通过 for 或 begin/end 序列获得相同的效果:"=for biblio ..." 或 "=begin biblio" ... "=end biblio"。不理解 "=for biblio" 等的 Pod 处理器将简单地忽略它,而它们可能会在看到 "=biblio" 时发出强烈抱怨。
在本文档中,“Pod”一直是文档格式名称的首选拼写。也可以使用“POD”或“pod”。对于通常以 Pod 格式存在的文档,您可以使用“pod”或“Pod”或“POD”。理解这些区别很有用;但通常不必执着于如何拼写它们。
正如您从浏览 perlpod 可以看出,L<...> 代码是 Pod 格式化代码中最复杂的代码。以下几点将有助于澄清它的含义以及处理器如何处理它。
在解析 L<...> 代码时,Pod 解析器必须区分至少四个属性
链接文本。如果不存在,则必须为undef
。(例如,在“L<Perl Functions|perlfunc>”中,链接文本为“Perl Functions”。在“L<Time::HiRes>”甚至“L<|Time::HiRes>”中,没有链接文本。请注意,链接文本可能包含格式。)
可能推断的链接文本;即,如果没有真正的链接文本,那么这就是我们将推断的替代文本。(例如,对于“L<Getopt::Std>”,推断的链接文本为“Getopt::Std”。)
名称或 URL,如果不存在则为undef
。(例如,在“L<Perl Functions|perlfunc>”中,名称(有时也称为页面)为“perlfunc”。在“L</CAVEATS>”中,名称为undef
。)
部分(在旧的 perlpod 中称为“项目”,或undef
如果不存在。例如,在“L<Getopt::Std/DESCRIPTION>”中,“DESCRIPTION”是部分。(请注意,这与 manpage 部分不同,例如“man 5 crontab”中的“5”。Pod 意义上的“部分 Foo”是指由标题或项目引入的文本部分,其文本为“Foo”。)
Pod 解析器还可以注意到其他属性,包括
一个标志,用于指示项目 3(如果存在)是否为 URL(例如“http://lists.perl.org”),在这种情况下不应该有部分属性;Pod 名称(例如“perldoc”和“Getopt::Std”);或者可能是 manpage 名称(例如“crontab(5)”)。
原始的 L<...> 内容,在文本被拆分为“|”、“/”等之前,以及在 E<...> 代码被扩展之前。
(以上仅用于简洁的参考。这些不需要作为实际列表或数组传递。)
例如
L<Foo::Bar>
=> undef, # link text
"Foo::Bar", # possibly inferred link text
"Foo::Bar", # name
undef, # section
'pod', # what sort of link
"Foo::Bar" # original content
L<Perlport's section on NL's|perlport/Newlines>
=> "Perlport's section on NL's", # link text
"Perlport's section on NL's", # possibly inferred link text
"perlport", # name
"Newlines", # section
'pod', # what sort of link
"Perlport's section on NL's|perlport/Newlines"
# original content
L<perlport/Newlines>
=> undef, # link text
'"Newlines" in perlport', # possibly inferred link text
"perlport", # name
"Newlines", # section
'pod', # what sort of link
"perlport/Newlines" # original content
L<crontab(5)/"DESCRIPTION">
=> undef, # link text
'"DESCRIPTION" in crontab(5)', # possibly inferred link text
"crontab(5)", # name
"DESCRIPTION", # section
'man', # what sort of link
'crontab(5)/"DESCRIPTION"' # original content
L</Object Attributes>
=> undef, # link text
'"Object Attributes"', # possibly inferred link text
undef, # name
"Object Attributes", # section
'pod', # what sort of link
"/Object Attributes" # original content
L<https://www.perl5.cn/>
=> undef, # link text
"https://www.perl5.cn/", # possibly inferred link text
"https://www.perl5.cn/", # name
undef, # section
'url', # what sort of link
"https://www.perl5.cn/" # original content
L<Perl.org|https://www.perl5.cn/>
=> "Perl.org", # link text
"https://www.perl5.cn/", # possibly inferred link text
"https://www.perl5.cn/", # name
undef, # section
'url', # what sort of link
"Perl.org|https://www.perl5.cn/" # original content
请注意,您可以通过以下事实来区分 URL 链接和其他任何内容:它们与m/\A\w+:[^:\s]\S*\z/
匹配。因此L<https://perldotcom.perl5.cn>
是 URL,但L<HTTP::Response>
不是。
对于没有“text|”部分的 L<...> 代码,旧的格式化程序在实际显示链接或交叉引用方面表现出很大的差异。例如,L<crontab(5)> 将呈现为“crontab(5)
manpage”,“在crontab(5)
manpage 中”或仅仅是“crontab(5)
”。
Pod 处理器现在必须按如下方式处理没有“text|”的链接
L<name> => L<name|name>
L</section> => L<"section"|/section>
L<name/section> => L<"section" in name|name/section>
请注意,部分名称可能包含标记。即,如果部分以
=head2 About the C<-M> Operator
或
=item About the C<-M> Operator
开头,那么指向它的链接将如下所示
L<somedoc/About the C<-M> Operator>
格式化程序可以选择忽略用于解析链接的标记,并且仅使用部分名称中的可渲染字符,如
<h1><a name="About_the_-M_Operator">About the <code>-M</code>
Operator</h1>
...
<a href="somedoc#About_the_-M_Operator">About the <code>-M</code>
Operator" in somedoc</a>
以前版本的 perlpod 区分了L<name/"section">
链接和L<name/item>
链接(及其目标)。这些在当前规范中已在语法和语义上合并,并且section 可以指代“=headn Heading Content”命令或“=item Item Content”命令。本规范没有指定在给定文档中有多个似乎都产生相同section 标识符的情况下的行为(例如,在 HTML 中,多个元素都产生相同anchorname 的 <a name="anchorname">...</a> 元素)。在 Pod 处理器可以控制此行为的情况下,它们应该使用第一个这样的锚点。也就是说,L<Foo/Bar>
指的是 Foo 中的第一个“Bar”部分。
但对于某些处理器/格式,这不容易控制;与 HTML 示例一样,多个模糊的 <a name="anchorname">...</a> 的行为最容易留给浏览器决定。
在 L<text|...>
代码中,文本可能包含用于格式化或用于 E<...> 转义的格式化代码,例如
L<B<ummE<234>stuff>|...>
对于没有“name|”部分的 L<...>
代码,只能出现 E<...>
和 Z<>
代码。也就是说,作者不应该使用“L<B<Foo::Bar>>
”。
但是请注意,格式化代码和 Z<> 可以出现在 L<...> 的任何和所有部分(即,在 name、section、text 和 url 中)。
作者不得嵌套 L<...> 代码。例如,“L<The L<Foo::Bar> man page>” 应被视为错误。
请注意,Pod 作者可以在“L<text|name>” 的“text”部分使用格式化代码(对于 L<text|/"sec"> 也是如此)。
换句话说,这是有效的
Go read L<the docs on C<$.>|perlvar/"$.">
一些允许将“L<...>” 代码渲染为超文本的输出格式可能不允许链接文本进行格式化;在这种情况下,格式化程序将不得不忽略该格式化。
在撰写本文时,L<name>
值有两种类型:要么是 Pod 页面名称,如 L<Foo::Bar>
(这可能是一个真实的 Perl 模块或程序,位于 @INC / PATH 目录中,或者是一个位于这些位置的 .pod 文件);要么是 Unix 手册页名称,如 L<crontab(5)>
。理论上,L<chmod>
在名为“chmod”的 Pod 页面或 Unix 手册页“chmod”(在任何手册部分)之间是模棱两可的。但是,括号中的字符串的存在,如“crontab(5)”,足以表明正在讨论的不是 Pod 页面,因此可能是一个 Unix 手册页。这种区别对于许多 Pod 处理器来说并不重要,但一些渲染为超文本格式的处理器可能需要区分它们,以便知道如何渲染给定的 L<foo>
代码。
Perlpod 的早期版本允许使用 L<section>
语法(如 L<Object Attributes>
),这与 L<name>
语法难以区分,而 L<"section">
语法则略微模糊。这种语法不再包含在规范中,已被 L</section>
语法取代(其中斜杠以前是可选的)。Pod 解析器应该至少在一段时间内容忍 L<"section">
语法。区分 L<section>
和 L<name>
的建议启发式方法是,如果它包含任何空格,则它是一个section。Pod 处理器应该警告这种过时的语法。
"=over"..."=back" 区域用于各种列表状结构。(我在这里使用“区域”一词仅仅作为从“=over”到匹配的“=back”的所有内容的总称。)
"=over indentlevel" ... "=back" 中的非零数字indentlevel 用于为格式化程序提供一个线索,说明它应该缩进多少个“空格”(em 或大致等效的单位),尽管许多格式化程序将不得不将其转换为绝对测量值,这可能与文档基本字体中空格(或 M)的大小不完全匹配。其他格式化程序可能必须完全忽略该数字。缺少任何显式indentlevel 参数等效于indentlevel 值为 4。如果indentlevel 存在但不是匹配 m/\A(\d*\.)?\d+\z/
的正数,Pod 处理器可能会抱怨。
Pod 格式化程序的作者应注意,"=over" ... "=back" 可能会映射到您输出格式中的几种不同的结构。例如,在将 Pod 转换为 (X)HTML 时,它可以映射到 <ul>...</ul>、<ol>...</ol>、<dl>...</dl> 或 <blockquote>...</blockquote> 中的任何一个。类似地,"=item" 可以映射到 <li> 或 <dt>。
每个 "=over" ... "=back" 区域应该以下列之一
一个 "=over" ... "=back" 区域,其中只包含 "=item *" 命令,每个命令后面都跟着一些普通/逐字段落、其他嵌套的 "=over" ... "=back" 区域、"=for..." 段落和 "=begin"..."=end" 区域。
(Pod 处理器必须容忍一个裸 "=item",就好像它是 "=item *" 一样。)"*" 是以文字星号、"o" 还是某种真正的项目符号字符的形式呈现,这取决于 Pod 格式化程序,并且可能取决于嵌套级别。
一个 "=over" ... "=back" 区域,只包含 m/\A=item\s+\d+\.?\s*\z/
段落,每个段落(或每组段落)后面跟着一些普通/逐字段落、其他嵌套的 "=over" ... "=back" 区域、"=for..." 段落和/或 "=begin"..."=end" 代码。注意,每个部分的数字必须从 1 开始,并且必须按顺序排列,不能跳过数字。
(Pod 处理器必须容忍像 "=item 1" 这样的行,就好像它们是 "=item 1." 一样,带有句号。)
一个 "=over" ... "=back" 区域,只包含 "=item [text]" 命令,每个命令(或每组命令)后面跟着一些普通/逐字段落、其他嵌套的 "=over" ... "=back" 区域、"=for..." 段落和 "=begin"..."=end" 区域。
"=item [text]" 段落不应该匹配 m/\A=item\s+\d+\.?\s*\z/
或 m/\A=item\s+\*\s*\z/
,也不应该只匹配 m/\A=item\s*\z/
。
一个 "=over" ... "=back" 区域,根本不包含 "=item" 段落,只包含一些普通/逐字段落,以及可能的一些嵌套的 "=over" ... "=back" 区域、"=for..." 段落和 "=begin"..."=end" 区域。Pod 中这样的无项目 "=over" ... "=back" 区域在语义上等同于 HTML 中的 "<blockquote>...</blockquote>" 元素。
注意,对于以上所有情况,你可以通过检查 "=over" 命令后的第一个(非 "=cut"、非 "=pod")Pod 段落来确定你拥有哪种类型的 "=over" ... "=back"。
Pod 格式化程序 *必须* 容忍 "=item text..." 段落中任意数量的文本。在实践中,大多数这样的段落都很短,例如
=item For cutting off our trade with all parts of the world
但它们可以任意长
=item For transporting us beyond seas to be tried for pretended
offenses
=item He is at this time transporting large armies of foreign
mercenaries to complete the works of death, desolation and
tyranny, already begun with circumstances of cruelty and perfidy
scarcely paralleled in the most barbarous ages, and totally
unworthy the head of a civilized nation.
Pod 处理器应该容忍 "=item *" / "=item number" 命令,没有伴随的段落。中间项目就是一个例子
=over
=item 1
Pick up dry cleaning.
=item 2
=item 3
Stop by the store. Get Abba Zabas, Stoli, and cheap lawn chairs.
=back
任何 "=over" ... "=back" 区域都不能包含标题。处理器可能会将这样的标题视为错误。
注意,"=over" ... "=back" 区域应该有一些内容。也就是说,作者不应该有像这样的空区域
=over
=back
Pod 处理器看到这样的无内容 "=over" ... "=back" 区域,可能会忽略它,也可能会将其报告为错误。
处理器必须容忍一个 "=over" 列表超出文档末尾(即没有匹配的 "=back"),但它们可能会警告这样的列表。
Pod 格式化程序的作者应该注意,这种结构
=item Neque
=item Porro
=item Quisquam Est
Qui dolorem ipsum quia dolor sit amet, consectetur, adipisci
velit, sed quia non numquam eius modi tempora incidunt ut
labore et dolore magnam aliquam quaerat voluptatem.
=item Ut Enim
在语义上是模棱两可的,这使得格式化决策有点困难。一方面,它可能是对项目 "Neque" 的提及,对项目 "Porro" 的提及,以及对项目 "Quisquam Est" 的提及,只有最后一个需要解释性段落 "Qui dolorem ipsum quia dolor...";然后是项目 "Ut Enim"。在这种情况下,你可能希望像这样格式化它
Neque
Porro
Quisquam Est
Qui dolorem ipsum quia dolor sit amet, consectetur, adipisci
velit, sed quia non numquam eius modi tempora incidunt ut
labore et dolore magnam aliquam quaerat voluptatem.
Ut Enim
但这同样可以是关于三个(相关或等效)项目的讨论,分别是“Neque”、“Porro”和“Quisquam Est”,后面跟着一段解释它们的段落,然后是一个新项目“Ut Enim”。在这种情况下,你可能希望以这样的格式进行
Neque
Porro
Quisquam Est
Qui dolorem ipsum quia dolor sit amet, consectetur, adipisci
velit, sed quia non numquam eius modi tempora incidunt ut
labore et dolore magnam aliquam quaerat voluptatem.
Ut Enim
但是(在可预见的未来),Pod 并没有提供任何方法让 Pod 作者区分上述“=item”集群结构所指的哪个分组。因此,格式化程序应该以这样的格式进行
Neque
Porro
Quisquam Est
Qui dolorem ipsum quia dolor sit amet, consectetur, adipisci
velit, sed quia non numquam eius modi tempora incidunt ut
labore et dolore magnam aliquam quaerat voluptatem.
Ut Enim
也就是说,项目之间以及段落之间的间距应该(至少大致)相等(尽管该间距可能远小于文本行的高度)。这使得读者可以利用(上下文)线索来判断“Qui dolorem ipsum...”段落是应用于“Quisquam Est”项目,还是应用于所有三个项目“Neque”、“Porro”和“Quisquam Est”。虽然这不是理想的情况,但这比提供可能与作者意图相悖的格式化线索要好。
数据段落通常用于内联非 Pod 数据,这些数据将在将文档渲染到特定格式时使用(通常是传递)。
=begin rtf
\par{\pard\qr\sa4500{\i Printed\~\chdate\~\chtime}\par}
=end rtf
顺便说一下,可以使用单个“=for”段落来实现完全相同的效果。
=for rtf \par{\pard\qr\sa4500{\i Printed\~\chdate\~\chtime}\par}
(尽管这在形式上不是数据段落,但它与数据段落具有相同的含义,Pod 解析器可能会将其解析为数据段落。)
数据段落的另一个示例
=begin html
I like <em>PIE</em>!
<hr>Especially pecan pie!
=end html
如果这些是普通段落,Pod 解析器会尝试将“E</em>” (在第一个段落中)扩展为格式化代码,就像“E<lt>” 或“E<eacute>” 一样。但由于这是在“=begin identifier”...”=end identifier”区域中,并且标识符“html”没有以“:”为前缀,因此该区域的内容将存储为数据段落,而不是作为普通段落进行处理(或者如果它们以空格和/或制表符开头,则作为逐字段落进行处理)。
再举一个例子:在撰写本文时,不支持“biblio”标识符,但假设编写了一些处理器来识别它作为(例如)表示书目参考文献(必然包含普通段落中的格式化代码)的一种方式。每个“biblio”标识符前面都带有冒号,这将表明“biblio”段落是用于普通处理的。
=begin :biblio
Wirth, Niklaus. 1976. I<Algorithms + Data Structures =
Programs.> Prentice-Hall, Englewood Cliffs, NJ.
=end :biblio
这将向解析器发出信号,表明此 begin...end 区域中的段落将受到正常处理,作为普通/逐字段落(尽管仍然标记为仅供理解“biblio”标识符的处理器使用)。相同的效果可以通过
=for :biblio
Wirth, Niklaus. 1976. I<Algorithms + Data Structures =
Programs.> Prentice-Hall, Englewood Cliffs, NJ.
这些标识符上的“:” 仅仅意味着“正常处理这些内容,即使结果是针对某个特殊目标”。我建议解析器 API 将“biblio”报告为目标标识符,但也报告它有一个“:” 前缀。(同样,对于上面的“html”,将“html”报告为目标标识符,并注意没有“:” 前缀。)
请注意,一个 "=begin identifier"..."=end identifier" 区域,其中identifier 以冒号开头,可以包含命令。例如
=begin :biblio
Wirth's classic is available in several editions, including:
=for comment
hm, check abebooks.com for how much used copies cost.
=over
=item
Wirth, Niklaus. 1975. I<Algorithmen und Datenstrukturen.>
Teubner, Stuttgart. [Yes, it's in German.]
=item
Wirth, Niklaus. 1976. I<Algorithms + Data Structures =
Programs.> Prentice-Hall, Englewood Cliffs, NJ.
=back
=end :biblio
但是请注意,一个 "=begin identifier"..."=end identifier" 区域,其中identifier 不以冒号开头,不应该直接包含 "=head1" ... "=head4" 命令,也不应该包含 "=over"、"=back" 或 "=item"。例如,这可能被认为是无效的
=begin somedata
This is a data paragraph.
=head1 Don't do this!
This is a data paragraph too.
=end somedata
一个 Pod 处理器可能会发出信号,表明上面的内容(特别是 "=head1" 段落)是一个错误。但是请注意,以下内容不应该被视为错误
=begin somedata
This is a data paragraph.
=cut
# Yup, this isn't Pod anymore.
sub excl { (rand() > .5) ? "hoo!" : "hah!" }
=pod
This is a data paragraph too.
=end somedata
这也同样有效
=begin someformat
This is a data paragraph.
And this is a data paragraph.
=begin someotherformat
This is a data paragraph too.
And this is a data paragraph too.
=begin :yetanotherformat
=head2 This is a command paragraph!
This is an ordinary paragraph!
And this is a verbatim paragraph!
=end :yetanotherformat
=end someotherformat
Another data paragraph!
=end someformat
上面 "=begin :yetanotherformat" ... "=end :yetanotherformat" 区域的内容不是数据段落,因为直接包含区域的标识符(":yetanotherformat")以冒号开头。在实践中,大多数包含数据段落的区域将只包含数据段落;但是,上面的嵌套在语法上是有效的 Pod,即使它很少见。但是,某些格式(如“html”)的处理程序将只接受数据段落,而不是嵌套区域;如果它们看到(针对它们的)嵌套区域或命令(除了 "=end"、"=pod" 和 "=cut"),它们可能会抱怨。
还要考虑这种有效的结构
=begin :biblio
Wirth's classic is available in several editions, including:
=over
=item
Wirth, Niklaus. 1975. I<Algorithmen und Datenstrukturen.>
Teubner, Stuttgart. [Yes, it's in German.]
=item
Wirth, Niklaus. 1976. I<Algorithms + Data Structures =
Programs.> Prentice-Hall, Englewood Cliffs, NJ.
=back
Buy buy buy!
=begin html
<img src='wirth_spokesmodeling_book.png'>
<hr>
=end html
Now now now!
=end :biblio
在那里,"=begin html"..."=end html" 区域嵌套在更大的 "=begin :biblio"..."=end :biblio" 区域内。请注意,"=begin html"..."=end html" 区域的内容是数据段落,因为直接包含区域的标识符("html")不以冒号开头。
Pod 解析器在处理一系列数据段落(在一个区域内)时,应该将它们视为一个包含空行的大的数据段落。因此,上面 "=begin html"..."=end html" 的内容可能被存储为两个数据段落(一个由 "<img src='wirth_spokesmodeling_book.png'>\n" 组成,另一个由 "<hr>\n" 组成),但应该被存储为一个数据段落(由 "<img src='wirth_spokesmodeling_book.png'>\n\n<hr>\n" 组成)。
Pod 处理器应该容忍空的 "=begin something"..."=end something" 区域,空的 "=begin :something"..."=end :something" 区域,以及无内容的 "=for something" 和 "=for :something" 段落。也就是说,这些应该被容忍。
=for html
=begin html
=end html
=begin :biblio
=end :biblio
顺便说一下,请注意,没有简单的方法来表达以类似命令开头的數據段落。例如
=begin stuff
=shazbot
=end stuff
在那里,"=shazbot" 将被解析为 Pod 命令 "shazbot",而不是数据段落 "=shazbot\n"。但是,您可以使用以下代码来表达包含 "=shazbot\n" 的数据段落
=for stuff =shazbot
这种情况可能很少见。
请注意,=end 命令必须与当前打开的 =begin 命令匹配。也就是说,它们必须正确嵌套。例如,这是有效的
=begin outer
X
=begin inner
Y
=end inner
Z
=end outer
而这是无效的
=begin outer
X
=begin inner
Y
=end outer
Z
=end inner
后者是不正确的,因为当看到 "=end outer" 命令时,当前打开的区域的格式名称是 "inner",而不是 "outer"。(碰巧 "outer" 是更高层区域的格式名称。)这是一个错误。处理器默认情况下必须将此报告为错误,并且可能会停止处理包含该错误的文档。这的一个推论是,区域不能“重叠”。也就是说,上面的后一个块不代表一个名为 "outer" 的区域,它包含 X 和 Y,与一个名为 "inner" 的区域重叠,它包含 Y 和 Z。但由于它无效(因为所有明显重叠的区域都是无效的),它不代表那个,也不代表任何东西。
同样,这也是无效的
=begin thing
=end hting
这是一个错误,因为该区域由 "thing" 打开,而 "=end" 试图关闭 "hting" [sic]。
这也是无效的
=begin thing
=end
这是无效的,因为每个 "=end" 命令都必须有一个格式名称参数。
perlpod,"PODs: 嵌入式文档" 在 perlsyn 中,podchecker
Sean M. Burke