Глобальное включение в реструктурированный текст
Я использую reStructuredText для своего блога / веб-сайта и хочу добавить глобальный включаемый файл. У меня есть доступ и я рад изменить файл настроек, который я использую для генерации вывода html, я просто не могу понять синтаксис для:
- добавление включаемого файла по умолчанию в анализатор
- определение директивы / inline-ролей и т. д. в python с документами в 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
2 ответа
Я не совсем уверен, понимаю ли я вопрос. Хотите ли вы определить, например, несколько замен в каком-то файле, и они будут доступны во всех ваших других файлах reStructuredText, или вы хотите включить какой-нибудь общий HTML в ваши выходные файлы? Вы можете уточнить свой вопрос?
Если это первое, что вы хотите сделать, вы можете использовать include
Директива, как я обрисую в этом ответе.
В качестве альтернативы, если вы хотите, чтобы какой-то общий HTML-код был включен в сгенерированный вывод, попробуйте скопировать и отредактировать template.txt
файл, который включен в модуль path/to/docutils/writers/html4css1/
, Вы можете включить в этот файл произвольные элементы HTML и изменить макет HTML, сгенерированный Docutils. Ни один из этих методов не требует от вас изменения исходного кода Docuitls, что всегда является преимуществом.
Редактировать: я не думаю, что можно установить флаг для установки включаемого файла с помощью Docuitls. Однако, если вы можете использовать Sphinx, который основан на Docuitls, но имеет множество расширений, то этот пакет имеет настройку rst_prolog
который делает именно то, что вам нужно (см. этот ответ). rst_prolog
является:
Строка reStructuredText, которая будет включена в начало каждого исходного файла, который читается.
Мне нужно было то же самое: способ, чтобы некоторые глобальные файлы 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
Обратите внимание, что пеликан и документы не предназначены для этого. Не предоставляется ни один сигнал, который обеспечивает чистый доступ к необработанному содержимому исходного файла до начала обработки, а также нет возможности перехватить структуру, считывающую файл "обычным способом" (например, создание подклассов, изменение жестко заданной конфигурации и т. Д.), Этот плагин подклассов внутреннего класса FileInput
из RstReader
и устанавливает ссылку на класс RstReader.FileInput
в подкласс. Также объекты файла Python эмулируются через SourceWrapper
, Тем не менее, этот подход работает для меня и не является громоздким в повседневной работе.
Я знаю, что этот вопрос с 2012 года, но я думаю, что этот ответ все еще может быть полезным для других.