【问题标题】:Global include in restructured text重组文本中的全局包含
【发布时间】:2012-05-18 00:33:46
【问题描述】:

我正在为我的博客/网站使用 reStructuredText,并且我想添加一个全局包含文件。我可以访问并很高兴更改用于生成 html 输出的设置文件,但我无法弄清楚两者的语法:

  1. 向解析器添加默认包含文件
  2. 在 python 中使用 docutils 在 python 中定义指令/内联角色等

我尝试阅读源代码和文档,但发现有点难以理解。我希望我只是错过了一些非常明显的事情,但我想做类似以下的事情(第一部分就是已经存在的——你可以看到rest of the file in the jekyll-rst plugin source (links right to it)

import sys
from docutils.core import publish_parts
from optparse import OptionParser
from docutils.frontend import OptionParser as DocutilsOptionParser
from docutils.parsers.rst import Parser

# sets up a writer that is then called to parse rst pages repeatedly
def transform(writer=None, part=None):
    p = OptionParser(add_help_option=False)

    # Collect all the command line options
    docutils_parser = DocutilsOptionParser(components=(writer, Parser()))
    for group in docutils_parser.option_groups:
        p.add_option_group(group.title, None).add_options(group.option_list)

    p.add_option('--part', default=part)

    opts, args = p.parse_args()


# ... more settings, etc

# then I just tell the parser/writer to process specified file X.rst every time
# (or alternately a python file defining more roles...but nicer if in rst)

有没有简单的方法来做到这一点?最好定义一个文件 defaults.rst 并每次都加载。

编辑:这里有一些我希望能够全局包含的示例(自定义指令也很好,但我可能会在代码中编写它们)

.. role:: raw-html(raw)
   :format: html

.. |common-substitution| replace:: apples and orange

.. |another common substitution| replace:: etc

【问题讨论】:

    标签: python jekyll restructuredtext docutils hyde


    【解决方案1】:

    我不太确定我是否理解这个问题。例如,您想在某个文件中定义一些替换,并在所有其他 reStructuredText 文件中使用这些替换,还是想在输出文件中包含一些常见的 HTML?你能澄清你的问题吗?

    如果您想要的是前者,您可以使用include 指令,正如我在this answer 中概述的那样。

    或者,如果您希望在生成的输出中包含一些常见的 HTML,请尝试复制和编辑包含在模块 path/to/docutils/writers/html4css1/ 中的 template.txt 文件。您可以在此文件中包含任意 HTML 元素并修改 Docutils 生成的 HTML 的布局。这些方法都不需要您修改 Docuitls 源代码,这始终是一个优势。

    编辑:我不认为可以使用 Docuitls 设置标志来设置包含文件。但是,如果您可以使用 Sphinx,它基于 Docuitls 但有很多扩展,那么这个包有一个设置 rst_prolog,它完全可以满足您的需求(参见 this answer)。 rst_prolog 是:

    一个 reStructuredText 字符串,将包含在每个读取的源文件的开头。

    【讨论】:

    • 我确实了解包含文件的工作原理,但我不想在我在站点中生成的每个文档的顶部添加明确的包含行。我还希望能够在不同的包含文件之间切换,而不必更改我生成的每个文档。对我来说,这相当于设置解析器/编写器时设置标志和选项。
    • 我正在考虑的另一件事是在 Python 中定义一个自定义角色,然后注册它。
    • 这是一个非常有帮助的答案,所以我会接受它,然后尝试一个新问题,改写得更具体。非常感谢您花时间回答!
    【解决方案2】:

    我需要完全相同的东西:一种将一些全局 reStructuredText 文件自动导入到每篇 reStructuredText 文章中的方法,而不必每次都手动指定它们。

    这个问题的一个解决方案是以下插件:

    import os
    from pelican import signals
    from pelican.readers import RstReader
    
    
    class RstReaderWrapper(RstReader):
          enabled = RstReader.enabled
          file_extensions = ['rst']
    
          class FileInput(RstReader.FileInput):
              def __init__(self, *args, **kwargs):
                  RstReader.FileInput_.__init__(self, *args, **kwargs)
                  self.source = RstReaderWrapper.SourceWrapper(self.source)
    
          # Hook into RstReader
          RstReader.FileInput_ = RstReader.FileInput
          RstReader.FileInput = FileInput
    
          class SourceWrapper():
              """
                  Mimics and wraps the result of a call to `open`
              """
              content_to_prepend = None
    
              def __init__(self, source):
                  self.source = source
    
              def read(self):
                  content = self.source.read()
                  if self.content_to_prepend is not None:
                      content = "{}\n{}".format(self.content_to_prepend, content)
                  return content
    
              def close(self):
                  self.source.close()
    
    
    def process_settings(pelicanobj):
          include_files = pelicanobj.settings.get('RST_GLOBAL_INCLUDES', []) or []
          base_path = pelicanobj.settings.get('PATH', ".")
    
          def read(fn):
              with open(os.path.join(base_path, fn), 'r') as res:
                  content = res.read()
                  return ".. INLCUSION FROM {}\n{}\n".format(fn, content)
    
          inclusion = "".join(map(read, include_files)) if include_files else None
          RstReaderWrapper.SourceWrapper.content_to_prepend = inclusion
    
    
    def register():
    signals.initialized.connect(process_settings)
    

    简而言之:

    • 从上面的代码创建一个插件(最好从 GitHub 克隆 repository
    • 导入插件(在pelicanconf.py中适配PLUGINS
    • 通过在pelicanconf.py 中设置变量RST_GLOBAL_INCLUDES 来定义要包含的RST 文件列表(项目根目录的相对路径)

    请注意,pelican 和 docutils 的设计都不允许这样做。既没有提供在处理开始之前提供对源文件原始内容的干净访问的信号,也没有可能拦截以“正常方式”读取文件的框架(如子类化、更改硬编码配置等) . 该插件将RstReader 的内部类FileInput 子类化,并将RstReader.FileInput 的类引用设置 为子类。还通过SourceWrapper 模拟python 文件对象。 不过,这种方法对我很有效,在日常工作流程中并不繁琐。

    我知道这个问题是 2012 年的,但我认为这个答案对其他人仍然有帮助。

    【讨论】:

      猜你喜欢
      • 2012-08-16
      • 1970-01-01
      • 2011-01-17
      • 1970-01-01
      • 2020-01-10
      • 1970-01-01
      • 1970-01-01
      • 2020-05-26
      • 1970-01-01
      相关资源
      最近更新 更多