競プロライブラリのページをAsciiDocで作った話
この記事は、"IQ1 Advent Calendar 2018"の13日目の記事です。
adventar.org
今回は、自分用の競プロライブラリのWebページを最近AsciiDocで作ったので、この話を書きます。競プロよりもAsciiDocメインの記事です。
tjkendev.github.io
(スマブラSPやってIQ低めてたら記事投稿が当日終わりになったけど許して)
はじめに
以前から、GitHubで競プロのライブラリとして実装をまとめていました。
しかし、まとめた実装を参照する際、以下のような問題がありました。
- コードが多くなると使いにくい
- 素早く必要なコードを探すのが難しくなる
- コード上に残したメモが読みづらい
- 特に複雑な数式が読めない
- 端末上でコピるのもめんどい
- 何も考えずボタン1つでコピーがしたい!!!!!
- 等々...
かといって、wikiやWebページをきちんと作って見やすくまとめるのは、作るのが面倒でしませんでした。
それでも最近、見やすくまとめたい欲が上がってきたので、さっくりと簡単にWebページを作ることにしました。
ここからはAsciiDocとその周りについて書いていきます。
環境準備
今回は、書きやすくてHTMLへの変換もしやすそうという気持ちで、軽量マークアップ言語であるAsciiDocでページを作ることにしました。
あと、数式を含めた軽い解説や計算量等の説明を書きたかったので、AsciiDocを拡張したAsciidoctor LaTeXを使いました。
github.com
Asciidoctor-LaTeXはgemからインストールできます。
# Asciidoctor LaTeXのインストール $ gem install asciidoctor-latex --pre
HTMLファイルへの変換はこんな感じです。
# test.adoc から test.html を生成 $ asciidoctor-latex -b html test.adoc # *.adoc から *.html を生成 $ asciidoctor-latex -b html -R ./src -D ./dst
AsciiDoc(Asciidoctor LaTeX)では上のように -R と -D オプションを使うと、src内のadocファイルを、ディレクトリ構造を保ちながらdstディレクトリにHTMLファイルを出力してくれます。
今回のように構造的なページを生成したい時に、何も考えずに変換できる便利な機能です。
ページを書く
AsciiDocはコードの状態でも読めるように書けます。
また、AsciiDocはソースコードをincludeすることができるため、ソースコードの部分と解説の部分を分離することができます。(ソースコードだけをまとめて、従来のライブラリとして扱えます)
そして、Asciidoctor LaTeXではLaTeXで書くように$$で数式を囲むと、HTML上でMathJaxを用いて表示してくれます。
- 例プログラム "ohuton.adoc"
# Asa! ## おきた! 今日も一日ねむみが $\sum_{k=1} \frac{1}{k}$ [source, python] ---- include::./ohuton-nukunuku.py[] ----
# 例プログラム "ohuton.adoc"のHTML変換 $ asciidoctor-latex -b html -a source-highlighter=highlightjs ohuton.adoc
いい感じです。
ページの見た目
でも、そのまま変換するとページの見た目がアレなので、Asciidoctor stylesheet factoryを使って見た目をよくしてます。
見た目がよくなりました。
拡張機能
ページを書いてると追加したいものが無限に出てきて、その中にはAsciiDocとして難しいことが出てきました。
- 特定ページのtitleをうまく変更したい...
- 標準ではtitleの値をある程度しか制御できない
- コードのコピーボタンを静的に追加したい...
- 静的に追加するには全てのコード付近にボタンを配置するのは手間
- JSでボタンを動的に配置するのは、後からボタンが表示されるのが気になる
- 特定のディレクトリからの相対パスが欲しい...
- 絶対パス(docfile)しか取得できない...
- 云々...
最初は、AsciiDoc標準のマクロ等で対応しようとしましたが、試している内に厳しいと感じました。
色々考えた結果、AsciiDocでは拡張機能を追加することができ、かつ拡張機能を自力で実装するのは簡単そうだったので、拡張機能を自分で実装して対応することにしました。
AsciiDocの拡張機能はRubyで書くことができます。
そして、以下の拡張機能のサンプルが存在するので、これをベースに自分で使う機能を実装しました。
github.com
拡張機能は8種類(前処理、後処理、マクロ定義、等)の拡張として実装ができます。
(例えば、相対パスの計算やtitle修正は前処理、コピーするためのボタンの配置は後処理の拡張機能として実装してます)
- 拡張機能(前処理)のシンプルな実装例 (extension.rb)
require 'asciidoctor/extensions' include Asciidoctor # 拡張機能を定義するクラス class Oyasumi < Extensions::Preprocessor def process document, reader attrs = document.attributes attrs['nukunuku'] = attrs['ohuton-name'] + "ぬくぬく" attrs['mouneyou'] = "もう寝よう" nil end end # 拡張機能の登録 Extensions.register do preprocessor Oyasumi end
実装した拡張機能は -r オプションでasciidoctor(-latex)に与えることで適用できます。
// result.adoc nukunuku = {nukunuku} mouneyou = {mouneyou}
$ asciidoctor -b html -r ./extension.rb ./result.adoc -a ohuton-name="おふとん"
拡張機能を自前で作れると、AsciiDocでいろんなことができるようになるので便利です。
AsciiDocなら任意のことができるように見えて最強に思えてきます。(IQ1的思考)
ページのデプロイ
ページはGitHub Pagesで公開しています。
ページを公開するために、はじめはmasterブランチのdocsにHTMLを生成するようにしてました。
しかし、コミットするたびにHTMLのdiffが無限に含まれたり、コミット時にデプロイ用のHTMLを生成し忘れることがあったため、あまりよいやり方ではないと思いました。
そこで、手動変換が必要なく、HTMLをmasterブランチと分離できる方法にしました。
具体的には、Travis CIを用いる方法で、
という流れでページを生成することにしました。
構築はこちらを参考にしました: Travis CIからgh-pagesにデプロイ · GitBook
現在は、masterへpush後にTravis CIでHTMLを生成し、gh-pagesブランチにpushしてページをデプロイしています。
Travis CIではgemのbundlerが使えるので、Asciidoctor LaTeXの環境構築は難しくなかったです。
Travis CIでは、HTML変換とデプロイの結果が出力されています。
https://travis-ci.org/tjkendev/procon-library
まとめ
AsciiDocでライブラリページを作りました。
簡単によい感じのライブラリページが作れるようになったと思います。