Asciidoc для генерации отчётов к лабораторным работам


# Asciidoc. Что это вообще такое?

Asciidoc — это язык разметки текста для написания технических материалов. Он даёт инструменты для сборки документов в разных форматах, включая HTML и PDF. Написан на Ruby и позволяет настраивать генерацию документов множеством способов.

# Мой опыт

Word для меня неудобен, так как настройка шаблонов в нём довольно неочевидна и он требует подгонять стили для каждого абзаца отдельно.

Поэтому я для себя сам собрал шаблон для Asciidoc максимально приближенный к ГОСТ 7.32-2017 (Отчёт по научно-исследовательской работе), написал скрипт на Powershell, который собирает отчёт в PDF. Документы редактирую в Visual Studio Code с плагином Asciidoctor.

Шаблон доступен на Github.

# Установка Asciidoc

Для Windows я использую Chocolatey. Это удобный консольный менеджер пакетов и приложений. Инструкции по установке здесь

Затем, в терминале с правами администратора, выполните:

choco install ruby

Затем в терминале без прав администратора:

gem install asciidoctor asciidoctor-pdf

Чтобы убедиться, что установка прошла успешно, выполните

asciidoctor-pdf --version

# Настройка шаблона

Создайте файл template.adoc в какой-нибудь папке (файл общий для всех документов), и вставьте туда это:

:ministry: Министерство науки и высшего образования Российской Федерации
:fullname1: <Полное название универа (первая строка)>
:fullname2: <Полное название универа (вторая строка)>
:shortname: <Аббревиатура универа>
:cathedra1: <Название кафедры (первая строка)>
:cathedra2: <Название кафедры (вторая строка)>

:subjectFull: по дисциплине «{subject}»
:themeFull: Тема: «{theme}»

:madeBy: Выполнил
:groupFull: студент {group}

:checkedBy: Принял

:city: <Название города>

:title: {work} №{worknumber}

:doctype: book
:reproducible:
:listing-caption: Листинг
:figure-caption: Рисунок
:table-caption: Taблица
:appendix-caption: Приложение
:toc-title: Содержание
:source-highlighter: rouge
:toclevels: 2
:imagesdir: ./images

# Скрипты, изменяющие логику рендера

Эти скрипты удобно разместить рядом с шаблоном из предыдущего раздела в папке custom

# Титульная страница

Этот скрипт заменяет стандартную титульную страницу на корректную, согласно ГОСТу 7.32

class PDFConverterCustomTitlePage < (Asciidoctor::Converter.for 'pdf')
    register_for 'pdf'
  
    def ink_title_page doc

      move_cursor_to page_height * 0.9

      theme_font :title_page_subtitle do
        ink_prose doc.attributes['ministry'], align: :center, color: theme.base_font_color, line_height: 1, margin: 0
        ink_prose doc.attributes['fullname1'], align: :center, color: theme.base_font_color, line_height: 1, margin: 0
        ink_prose doc.attributes['fullname2'], align: :center, color: theme.base_font_color, line_height: 1, margin: 0
        ink_prose doc.attributes['shortname'], align: :center, color: theme.base_font_color, line_height: 1, margin: 0
        ink_prose doc.attributes['cathedra1'], align: :center, color: theme.base_font_color, line_height: 1, margin: 0
        ink_prose doc.attributes['cathedra2'], align: :center, color: theme.base_font_color, line_height: 1, margin: 0

      end

      move_cursor_to page_height * 0.5
      doctitle = doc.doctitle partition: ' | '
      theme_font :title_page do
        theme_font :title_page_title do
          ink_prose doctitle.title, align: :center, color: theme.base_font_color, line_height: 1, margin: 0
          ink_prose doc.attributes['subjectfull'], align: :center, color: theme.base_font_color, line_height: 1, margin: 0 if doc.attributes['subject']
          ink_prose doc.attributes['themefull'], align: :center, color: theme.base_font_color, line_height: 1, margin: 0
        end
      end

      move_cursor_to page_height * 0.3

      theme_font :title_page_subtitle do
        ink_prose doc.attributes['madeby'], align: :right, color: theme.base_font_color, line_height: 1, margin: 0
        ink_prose doc.attributes['groupfull'], align: :right, color: theme.base_font_color, line_height: 1, margin: 0
        ink_prose doc.attributes['author'], align: :right, color: theme.base_font_color, line_height: 1, margin: 0

        ink_prose "", align: :right

        ink_prose doc.attributes['checkedby'], align: :right, color: theme.base_font_color, line_height: 1, margin: 0
        ink_prose doc.attributes['tutorposition'], align: :right, color: theme.base_font_color, line_height: 1, margin: 0 if doc.attributes['tutorposition']
        ink_prose doc.attributes['tutorname'], align: :right, color: theme.base_font_color, line_height: 1, margin: 0

        
      end


      move_cursor_to page_height * 0.07

      theme_font :title_page_subtitle do
        ink_prose doc.attributes['city'] + " " + doc.attributes['localyear'], align: :center, color: theme.base_font_color, line_height: 1, margin: 0
      end

    end
  end
Титульная страница
Титульная страница

# Подпись приложения

В теме по умолчанию после номера приложения стоит двоеточие. ГОСТ этого не позволяет, поэтому напишем скрипт, который уберёт двоеточие:

require 'asciidoctor'

Asciidoctor::Extensions.register do
  tree_processor do
    process do |doc|
      (doc.find_by context: :section).each do |section|
        next unless section.sectname == 'appendix'
        section.caption = section.caption.sub ':', ''
      end
      nil
    end
  end
end

# Подпись рисунка

Аналогично заменим точку после номера рисунка на длинное тире:

class CustomFigurePdfConverter < (Asciidoctor::Converter.for 'pdf')
    register_for 'pdf'

    def convert_image node
        node.caption = node.caption.sub '. ', ' — ' if node.title?
        super
    end
end

# Тема

Настроим шрифты, отступы и прочие стили согласно ГОСТу. Это yml файл, который нужно положить в resources/themes/report-theme.yml

extends: base
font:
  catalog:
    merge: false
    Times New Roman:
      normal: times-new-roman-normal.ttf
      italic: times-new-roman-italic.ttf
      bold: times-new-roman-bold.ttf
      bold_italic: times-new-roman-bold-italic.ttf
    Jetbrains Mono:
      normal: jetbrains-mono-nerd.ttf
      italic: jetbrains-mono-nerd.ttf
      bold: jetbrains-mono-nerd.ttf
      bold_italic: jetbrains-mono-nerd.ttf
page:
  layout: portrait
  margin: 20mm 15mm 20mm 30mm
  size: A4
  numbering:
    start-at: title
base:
  font-family: Times New Roman
  font-size: 14
  hyphens: true
  line-height: 1.5

heading:
  text-align: center
  h2:
    text-transform: uppercase
    font-style: normal
  h3:
    font-style: bold

prose:
  text-indent: 1.25cm

code:
  font-family: Jetbrains Mono

codespan:
  font-family: Jetbrains Mono
  font-size: 13

caption:
  font-style: normal

footer:
  border-width: 0
  columns: =100%
  recto: &shared_footer
    center:
      content: '{page-number}'
  verso: *shared_footer

image:
  align: center
  caption:
    text-align: center

# Шрифты

Затем скачайте шрифты Times New Roman и Jetbrains Mono (есть в репозитории) и разместите их в папке resources/fonts

# Документ

Скрипт, который я приведу ниже, предполагает что файл документа называется report.adoc. В этом файле будем писать разметку документа. Шпаргалка по синтаксису.

:doctype: book

:work: Отчёт по лабораторной работе
:workNumber: 1

:subject: Название предмета
:theme: Название темы

:author: Имя автора
:group: Номер группы

:tutorPosition: Должность проверившего
:tutorName: Имя проверившего

include::<абсолютный-путь-до-template.adoc>[]

= {work}{worknumber}
:title-page:
:toc:

== Цель работы

== Выполнение работы

== Вывод

# Скрипт запуска

Для генерации отчёта используется скрипт на powershell, который я кладу в папку scripts рядом с документом. <путь-до-папки-с-шаблоном> нужно заменить на фактический путь до ресурсов шаблона.

$group = "номер-группы"
$subject = "название-предмета"
$workNumber = "номер-работы"
$author = "фамилия-автора"

$command = "asciidoctor-pdf"
$arguments = "-T <путь-до-папки-с-шаблоном>", "-r <путь-до-папки-с-шаблоном>/custom/10titlePage.rb", "-r <путь-до-папки-с-шаблоном>/custom/20appendixCustomCaption.rb", "-r <путь-до-папки-с-шаблоном>/custom/30customFigureCaption.rb", "-a pdf-fontsdir=<путь-до-папки-с-шаблоном>/resources/fonts", "-a pdf-themesdir=<путь-до-папки-с-шаблоном>/resources/themes", "report.adoc", "--theme=report", "-o '$group-$subject-$workNumber-$author.pdf'"

try {
    $process = Start-Process -FilePath $command -ArgumentList $arguments -NoNewWindow -Wait -PassThru
    if ($process.ExitCode -eq 0) {
        Write-Host "Report generated!"
    }
    else {
        throw "Error generating report. Exit code: $($process.ExitCode)"
    }
}
catch {
    Write-Error $_.Exception.Message
}

После запуска этого скрипта на выходе получим файл номер-группы-название-предмета-номер-работы-фамилия-автора.pdf.

Итоговый документ
Итоговый документ

# Вывод

Для меня asciidoc стал удобным инструментом быстрого написания красивых отчётов лабораторных работ для универа. В этой статье я поделился своим опытом организации процесса создания таких отчётов и готовым шаблоном, максимально приближенным к ГОСТ 7.32-2017