Perl と Moo で、Markdown ファイルの見出しから目次を作るツールを作る全8回の連載です。ファイルを読み込み、正規表現で見出しを抜き出し、インデントを付けただけの目次から始めます。そのあと入れ子の HTML 目次を if/else で組もうとして、見出しのレベルが飛んだだけで壊れる様子を確かめます。そこから、子を持つ見出しも持たない見出しも同じ render で描く Composite パターンに組み替え、スタックで見出しの配列からツリーを自動で組み、Markdown・HTML・JSON の3形式とリンク付きの目次まで仕上げます。
各回は前の回のコードに手を足していく作りなので、通して読むなら第1回からが早道です。このページは目次を兼ねた案内板です。入口は「どこから読むか」で、困りごとが決まっているなら「困りごとから探す」で、順に追うなら「全話一覧」で選んでください。
どこから読むか
- 第1回 — 最初から順に作るなら。Markdown を全行読み込む MarkdownReader を作る。前提は Moo のクラス定義の基礎
- 第4回 — なぜパターンが要るのかを先に見たいなら。if/else で組んだ HTML 目次が、見出しのレベルが飛んだだけで壊れる
- 第5回 — Composite パターンの組み方だけ知りたいなら。Role・Leaf・Composite の3つを作り、再帰の render で階層を描く
困りごとから探す
入れ子の HTML リストを組むと、ul の開け閉めが合わない
フラットな配列から親子関係を組み立てたい
子を持つ要素と持たない要素で、処理を書き分けている
- 第5回 — 同じ Role を実装して、どちらも render 1つで描く
出力形式を増やしたい
目次の項目を見出しへのリンクにしたい
- 第8回 — 見出しテキストからアンカー ID を作り、リンク付きの目次を出す
全話一覧
- Markdown を全行読み込むクラス(lazy)
- 正規表現で見出しのレベルとテキストを抜く(キャプチャ)
- インデント付きで目次を表示する(フラット配列)
- if/else で入れ子の HTML を組んで壊れる(条件分岐の爆発)
- 同じ render で階層を描く(Composite)
- 見出しの配列からツリーを自動で組む(スタック)
- Markdown・HTML・JSON で出力する(複数フォーマット出力)
- アンカー ID でリンク付きの目次にする(開放閉鎖原則)
前提知識
- Perl v5.36 以降の基本文法(signatures、postfix dereference など)
- Moo によるクラス定義の基礎(has)と Moo::Role(第5回から使う)
- Moo が初めてなら、先に「Mooで覚えるオブジェクト指向プログラミング」シリーズを読むとスムーズに進みます
完成するもの
Markdown ファイルを読み込んで見出しを抜き出し、見出しのツリーを組んで、Markdown のリスト・入れ子の HTML・JSON の3形式で目次を出すツールです。Markdown のリストは、見出しへのリンク付きでも出せます。追加の CPAN モジュールは Moo だけで、JSON の出力には Perl 標準の JSON::PP を使います。
