Module: VivlioStarter::CLI::PostProcessCommands::ReplacementRules
- Defined in:
- lib/vivlio_starter/cli/post_process/replacement_rules.rb
Overview
旧 config/post_replace_list.yml の組み込み置換ルール。 適用エンジンは HtmlReplacer(保護モード・退避機構)を共用する。
各ルールの正規表現は旧 YAML の f 文字列と source が一致するよう
%r...m で記述している(/m は旧実装の Regexp.new(str, MULTILINE) 相当)。
置換文字列の $1〜$9 はエンジン側 replace_with_captures が手動展開するため
そのまま維持する(Ruby の \1 へ書き換えない)。
Defined Under Namespace
Classes: Rule
Constant Summary collapse
- CONTAINER_RULES =
[ # :::{.class} 記法(Pandoc 拡張風)を <div class="..."> に変換(開始)。 # 複数クラス {.a .b .c} にも対応(先頭の . は任意、以降の . は後段ルールで除去)。 Rule.new(%r{:{3,}\s*\{\.?([a-z0-9.\-_\s]+)\}}m, '<div class="$1">', :text_only), # 複数クラス指定で残った " ." を " " に整理(最大 4 クラスまで対応するため 3 回)。 Rule.new(%r{(<div class="[^"]*?) \.}m, '$1 ', :tag_aware), Rule.new(%r{(<div class="[^"]*?) \.}m, '$1 ', :tag_aware), Rule.new(%r{(<div class="[^"]*?) \.}m, '$1 ', :tag_aware), # ::: ブロック終端を </div> に変換(終了)。 Rule.new(%r{:{3,}}m, '</div>', :text_only) ].freeze
- PAGEBREAK_RULES =
を改ページ用の
に。 [ Rule.new(%r{<hr>}m, '<hr class="pagebreak">', :tag_aware) ].freeze
- SPACING_MACRO_RULES =
余白・改ページのプラグマ系マクロ。単位付きを先に適用する (単位なしルールが先に走ると数値だけ拾って単位が残るため)。 単位なしの既定は @vspace が mm・@hspace が em(水平方向は文字数感覚が自然なため 意図的に非対称。at-directive-tier1-spec.md §1.5)。
[ Rule.new(%r{@vspace:(-?[\d.]+(?:lh|rem|em|mm|cm|pt|px))}m, '<div style="margin-top:$1"></div>', :text_only), Rule.new(%r{@vspace:(-?[\d.]+)}m, '<div style="margin-top:$1mm"></div>', :text_only), Rule.new(%r{@hspace:(-?[\d.]+(?:lh|rem|em|mm|cm|pt|px))}m, '<span class="vs-hspace" style="margin-left:$1"></span>', :text_only), Rule.new(%r{@hspace:(-?[\d.]+)}m, '<span class="vs-hspace" style="margin-left:$1em"></span>', :text_only), # 引数付きを先に。裸形の否定先読み (?!:) は必須——これが無いと不正引数 # (@pagebreak:left 等)の @pagebreak 部分だけが置換され ":left" が紙面に残る。 # 不正形は丸ごと素通しし、前処理(MarkdownPreprocessor)の検知に委ねる。 Rule.new(%r{@pagebreak:(recto|verso)\b}m, '<div class="vs-break-$1"></div>', :text_only), Rule.new(%r{@pagebreak\b(?!:)}m, '<div class="vs-break-page"></div>', :text_only) ].freeze
- LIST_DECORATION_RULES =
リストの先頭記号を装飾クラスに(▶=青コメ / 囲み数字=赤コメ)。
[ Rule.new(%r{<li[^>]*>▶}m, '<li class="aokome">', :tag_aware), Rule.new(%r{<li[^>]*>([❶-❿⓫-⓴]+)}m, '<li class="akakome"><span>$1</span>', :tag_aware) ].freeze
- CODE_HEADING_RULES =
コード見出し(h6)を装飾クラス付きに(span は Nokogiri の自動補完で閉じる)。
[ Rule.new(%r{<h6([^>]*)>}m, '<h6$1 class="codetitle"><span>', :tag_aware) ].freeze
- KBD_RULES =
〘〙 を ... に。
[ Rule.new(%r{〘}m, '<kbd>', :text_only), Rule.new(%r{〙}m, '</kbd>', :text_only) ].freeze
- PARAGRAPH_CLEANUP_RULES =
p/div/svg/image/hr のねじれ修正と空段落除去(順序厳守・15 ルール)。 後段ルールは前段の結果に依存するため並びを変えないこと。
[ # p が余分に div を囲っているのを除去(div 先頭を裸に)。 Rule.new(%r{<p>(<div class="[^"]+">)</p>}m, '$1', :tag_aware), # p と div の並び修正。 Rule.new(%r{<p></div></p>}m, '</div>', :tag_aware), Rule.new(%r{<p></div>}m, '</div>', :tag_aware), Rule.new(%r{</div></p>}m, '</div>', :tag_aware), # div の直後に余分な </p> が来た場合の修正。 Rule.new(%r{(<div class="[^"]+">)</p>}m, '$1', :tag_aware), # <p>(<div ...>) の余分な p を除去(前後の空白・改行を許容)。 Rule.new(%r{<p>\s*(<div class="[^"]+">)}m, '$1', :tag_aware), # hr の前後の余分な p / </p> を除去。 Rule.new(%r{(<hr class="[^"]+">)</p>}m, '$1', :tag_aware), Rule.new(%r{<p>(<hr class="[^"]+">)}m, '$1', :tag_aware), # <svg> / <image> を p が囲っているだけの場合、p を除去。 Rule.new(%r{<p>(<svg [^>]+>)</p>}m, '$1', :tag_aware), Rule.new(%r{<p>(<image [^>]+>)}m, '$1', :tag_aware), Rule.new(%r{(<image [^>]+>)</p>}m, '$1', :tag_aware), Rule.new(%r{<p>(</svg>)}m, '$1', :tag_aware), Rule.new(%r{(</svg>)</p>}m, '$1', :tag_aware), # 空段落を除去(素 / 空白 / nbsp・ゼロ幅・双方向制御記号のみ)。 Rule.new(%r{<p></p>}m, '', :tag_aware), Rule.new(%r{<p>\s*</p>}m, '', :tag_aware), Rule.new( %r{<p>(?:\s|\u{00A0}|\u{200B}|\u{200C}|\u{200D}|\u{2060}|\u{FEFF}|\u{180E}|\u{200E}|\u{200F}| | | )*</p>}m, '', :tag_aware ) ].freeze
- SPACING_CLASS_RULES =
段落末の aki / aki2 をクラス化。
[ Rule.new(%r{<p>((?:(?!</p>).)*?)\{\.aki\}\s*</p>}m, '<p class="aki">$1</p>', :tag_aware), Rule.new(%r{<p>((?:(?!</p>).)*?)\{\.aki2\}\s*</p>}m, '<p class="aki2">$1</p>', :tag_aware) ].freeze
- ALL =
旧 yml の記載順そのまま(順序変更禁止: 後段ルールは前段の結果に依存する)。
(CONTAINER_RULES + PAGEBREAK_RULES + SPACING_MACRO_RULES + LIST_DECORATION_RULES + CODE_HEADING_RULES + KBD_RULES + PARAGRAPH_CLEANUP_RULES + SPACING_CLASS_RULES).freeze
Class Method Summary collapse
-
.apply_builtin!(html_file) ⇒ Hash
組み込みルール一式を適用する(旧 process_html_file(file, yaml_rules) 相当)。.
-
.sanitize_value(value) ⇒ Object
置換エンジンは $1〜$9 を手動展開するため、値中の
$を無害化しつつ HTML エスケープする。. -
.value_macro_rules(cfg = Common.configured? ? Common::CONFIG : nil) ⇒ Object
ビルド時定数マクロ(at-directive-tier1-spec.md §2.3)。 値が CONFIG・ビルド時刻に依存するため frozen 定数 ALL には入れず、適用時に組み立てる (定数にすると reload_configuration! 後に stale な値を差し込んでしまう)。
\bにより @titlepage のような続き文字には反応しない。.
Class Method Details
.apply_builtin!(html_file) ⇒ Hash
組み込みルール一式を適用する(旧 process_html_file(file, yaml_rules) 相当)。
140 |
# File 'lib/vivlio_starter/cli/post_process/replacement_rules.rb', line 140 def apply_builtin!(html_file) = HtmlReplacer.process_html_file(html_file, ALL + value_macro_rules) |
.sanitize_value(value) ⇒ Object
置換エンジンは $1〜$9 を手動展開するため、値中の $ を無害化しつつ HTML エスケープする。
136 |
# File 'lib/vivlio_starter/cli/post_process/replacement_rules.rb', line 136 def sanitize_value(value) = CGI.escapeHTML(value.to_s).gsub('$', '$') |
.value_macro_rules(cfg = Common.configured? ? Common::CONFIG : nil) ⇒ Object
ビルド時定数マクロ(at-directive-tier1-spec.md §2.3)。
値が CONFIG・ビルド時刻に依存するため frozen 定数 ALL には入れず、適用時に組み立てる
(定数にすると reload_configuration! 後に stale な値を差し込んでしまう)。
\b により @titlepage のような続き文字には反応しない。
124 125 126 127 128 129 130 131 132 133 |
# File 'lib/vivlio_starter/cli/post_process/replacement_rules.rb', line 124 def value_macro_rules(cfg = Common.configured? ? Common::CONFIG : nil) # 日付だけは CONFIG に依らないので、プロジェクト外(CONFIG 未ロード)でも展開する。 rules = [Rule.new(%r{@today\b}m, Time.now.strftime('%Y年%-m月%-d日'), :text_only)] return rules unless cfg rules.unshift( Rule.new(%r{@version\b}m, sanitize_value(cfg.project.version), :text_only), Rule.new(%r{@title\b}m, sanitize_value(cfg.book.main_title), :text_only) ) end |