Глобальное включение в реструктурированный текст

Я использую reStructuredText для своего блога/веб-сайта и хочу добавить глобальный включаемый файл. У меня есть доступ, и я рад изменить файл настроек, который я использую для создания вывода html, я просто не могу понять синтаксис:

  1. добавление включаемого файла по умолчанию в парсер
  2. определение директив/встроенных ролей и т. д. в python с помощью docutils в python

Я пытался читать исходный код и документацию, и мне было немного трудно следовать. Я надеюсь, что просто пропустил что-то сверхочевидное, но я хотел бы сделать что-то вроде следующего (первая часть — это то, что уже есть — вы можете увидеть остальная часть файла в исходном коде плагина jekyll-rst (ссылки прямо на него)

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

person Jeff Tratner    schedule 18.05.2012    source источник


Ответы (2)


Я не совсем уверен, понимаю ли я вопрос. Вы хотите определить ряд, например, замен в каком-то файле и сделать их доступными во всех других ваших файлах reStructuredText, или вы хотите включить некоторый общий HTML в свои выходные файлы? Можете уточнить свой вопрос?

Если вы хотите сделать первое, вы можете использовать include< /a>, как я описал в этом ответе.

В качестве альтернативы, если вы хотите, чтобы в сгенерированный вывод был включен некоторый общий HTML, попробуйте скопировать и отредактировать файл template.txt, который включен в модуль path/to/docutils/writers/html4css1/. В этот файл можно включать произвольные элементы HTML и изменять макет HTML, сгенерированный Docutils. Ни один из этих методов не требует изменения исходного кода Docuitls, что всегда является преимуществом.

Изменить: я не думаю, что можно установить флаг для установки включаемого файла с помощью Docuitls. Однако, если вы можете использовать Sphinx, который основан на Docuitls, но имеет множество расширений, то этот пакет имеет параметр rst_prolog, который делает именно то, что вам нужно (см. < href="https://stackoverflow.com/a/9707879/623518">этот ответ). rst_prolog это:

Строка reStructuredText, которая будет включена в начало каждого считываемого исходного файла.

person Chris    schedule 18.05.2012
comment
Я понимаю, как работают включаемые файлы, но я бы предпочел не добавлять явную включаемую строку вверху каждого документа, который я создаю на сайте. Я также хотел бы иметь возможность переключаться между различными включаемыми файлами без необходимости изменять каждый документ, который я создал. Для меня это эквивалент установки флагов и опций при настройке парсера/писателя. - person Jeff Tratner; 18.05.2012
comment
другая вещь, которую я рассматривал, заключалась в том, чтобы определить пользовательскую роль в Python, а затем зарегистрировать ее. - person Jeff Tratner; 18.05.2012
comment
это очень полезный ответ, поэтому я собираюсь принять его, а затем попробовать новый вопрос, очень перефразированный, чтобы быть более конкретным. Большое спасибо, что нашли время ответить! - person Jeff Tratner; 18.05.2012

Мне нужно было то же самое: способ автоматического импорта некоторых глобальных файлов 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)
  • Импортируйте плагин (адаптируйте PLUGINS в pelicanconf.py)
  • Определите список файлов RST (относительные пути к корню проекта) для включения, установив переменную RST_GLOBAL_INCLUDES в pelicanconf.py.

Обратите внимание, что pelican и docutils не предназначены для этого. Не предоставляется ни сигнал, который обеспечивает чистый доступ к необработанному содержимому исходного файла до начала обработки, ни возможность перехватить фреймворк, читающий файл «обычным способом» (например, создание подклассов, изменение жестко закодированной конфигурации и т. д.) . Этот подключаемый модуль создает подкласс внутреннего класса FileInput из RstReader и устанавливает ссылку на класс из RstReader.FileInput в подкласс. Также файловые объекты python эмулируются через SourceWrapper. Тем не менее, этот подход работает для меня и не является громоздким в ежедневном рабочем процессе.

Я знаю, что этот вопрос задан в 2012 году, но я думаю, что этот ответ может быть полезен другим.

person Michael Hoff    schedule 28.06.2016