Module: Vivlio::Starter::CLI::PreProcessCommands::CrossReferenceProcessor
- Defined in:
- lib/vivlio/starter/cli/pre_process/cross_reference_processor.rb
Overview
クロスリファレンス処理モジュールrubocop:disable Metrics/ModuleLength
Defined Under Namespace
Classes: CaptionedBlockTransformer, Label, LabelCollectorContext, ReferenceReplacer
Constant Summary collapse
- LABEL_TYPE_NAMES =
ラベル種別の日本語名
{ list: 'リスト', table: '表', fig: '図' }.freeze
- CAPTION_PATTERN =
/^\*\*\s*(.+?)\s+@([-\w]+)\s*\*\*\s*$/- RESERVED_IDS =
自動採番用の予約ID(キャプションで @auto / @omakase / @id と書くと type-chapter-N 形式に採番される)
%w[auto omakase id].freeze
- RESERVED_MACRO_IDS =
config/post_replace_list.yml のマクロ名(完全一致で予約)。これらは @ID 参照ではなくシステム予約のマクロなので、未定義のラベルIDとして警告しない。
%w[ div divend nega posi clear comment commend ].freeze
- RESERVED_MACRO_POSITION_PREFIXES =
config/post_replace_list.yml の絶対配置+SVG ガイド線マクロ接頭辞。例: @lu25,15@20,30 の ‘lu25` や、@ls40@20,20 の `ls40` など、接頭辞に続く数字列(幅/高さ指定)を丸ごと予約する。Planned 扱いのため現状はコメントアウトされているが、資料やコードサンプルで登場しても警告しないようにしておく。
%w[ lu ld ru rd ur ls rs us ds ].freeze
- IMAGE_PATTERN =
/^!\[[^\]]*\]\([^)]+\)(?:\{[^}]+\})?$/- MAIN_CHAPTER_RANGE =
PostProcessCommands::HeadingProcessor::MAIN_CHAPTER_RANGE
Class Method Summary collapse
-
.build_labels_map_with_duplicates_check(all_labels) ⇒ Hash
レポート生成.
-
.collect_labels(content, source_file, chapter_number) ⇒ Object
ラベル収集.
- .detect_block_type(lines, idx) ⇒ Object
- .display_chapter_number_for_filename(filename) ⇒ Object
- .extract_caption_label(line) ⇒ Object
-
.extract_chapter_number(filename) ⇒ Object
章番号関連.
-
.process_cross_references(chapters) ⇒ Object
Public API ===.
-
.replace_references(content, labels_map, filename = nil) ⇒ Object
参照置換.
-
.reserved_id?(label_id) ⇒ Boolean
予約IDの判定を一元化する。 RESERVED_IDS: auto / omakase / id RESERVED_MACRO_IDS: div / nega / comment など完全一致 RESERVED_MACRO_POSITION_PREFIXES: lu25 / ls40 など接頭辞+数字.
-
.transform_captioned_blocks(content, filename, labels_map) ⇒ Object
キャプション付きブロック変換.
Class Method Details
.build_labels_map_with_duplicates_check(all_labels) ⇒ Hash
レポート生成
214 215 216 217 218 219 220 221 222 223 224 225 226 |
# File 'lib/vivlio/starter/cli/pre_process/cross_reference_processor.rb', line 214 def build_labels_map_with_duplicates_check(all_labels) map = {} # IDごとに全ラベルを蓄積する(先勝ちで map に登録) all_occurrences = Hash.new { |h, k| h[k] = [] } all_labels.each do |label| all_occurrences[label.id] << label map[label.id] ||= label end duplicates_by_id = all_occurrences.select { |_, labels| labels.size > 1 } { labels_map: map, duplicates_by_id: } end |
.collect_labels(content, source_file, chapter_number) ⇒ Object
ラベル収集
136 137 138 139 |
# File 'lib/vivlio/starter/cli/pre_process/cross_reference_processor.rb', line 136 def collect_labels(content, source_file, chapter_number) collector = LabelCollectorContext.new(source_file, chapter_number) collector.collect(content) end |
.detect_block_type(lines, idx) ⇒ Object
101 102 103 104 105 106 107 108 109 |
# File 'lib/vivlio/starter/cli/pre_process/cross_reference_processor.rb', line 101 def detect_block_type(lines, idx) ((idx + 1)...lines.size).each do |index| line = lines[index].strip next if line.empty? || line.start_with?(':::{') return detect_type_from_line(line) end nil end |
.display_chapter_number_for_filename(filename) ⇒ Object
126 127 128 129 130 131 132 133 |
# File 'lib/vivlio/starter/cli/pre_process/cross_reference_processor.rb', line 126 def display_chapter_number_for_filename(filename) num = extract_chapter_number(filename).to_i return num.to_s unless MAIN_CHAPTER_RANGE.include?(num) token = File.basename(filename, File.extname(filename)) idx = main_chapter_order.index(token) idx ? (idx + 1).to_s : (num - 10).to_s end |
.extract_caption_label(line) ⇒ Object
93 94 95 96 97 98 99 |
# File 'lib/vivlio/starter/cli/pre_process/cross_reference_processor.rb', line 93 def extract_caption_label(line) match = line.match(CAPTION_PATTERN) return nil unless match { title: match[1].strip, id: match[2].strip, auto: RESERVED_IDS.include?(match[2].strip) } end |
.extract_chapter_number(filename) ⇒ Object
章番号関連
121 122 123 124 |
# File 'lib/vivlio/starter/cli/pre_process/cross_reference_processor.rb', line 121 def extract_chapter_number(filename) match = File.basename(filename, '.*').match(/^(\d+)/) match ? match[1] : '0' end |
.process_cross_references(chapters) ⇒ Object
Public API ===
80 81 82 83 84 85 86 87 88 89 90 91 |
# File 'lib/vivlio/starter/cli/pre_process/cross_reference_processor.rb', line 80 def process_cross_references(chapters) all_labels, all_errors = collect_all_labels(chapters) labels_map, duplicates = build_labels_map(all_labels) log_duplicates(duplicates, all_errors) processed = transform_all_chapters(chapters, labels_map) processed, ref_errors = replace_all_references(processed, labels_map) all_errors.concat(ref_errors) { chapters: processed, report: generate_report(all_labels), errors: all_errors, labels_count: all_labels.size } end |
.replace_references(content, labels_map, filename = nil) ⇒ Object
参照置換
207 208 209 |
# File 'lib/vivlio/starter/cli/pre_process/cross_reference_processor.rb', line 207 def replace_references(content, labels_map, filename = nil) ReferenceReplacer.new(content, labels_map, filename).replace end |
.reserved_id?(label_id) ⇒ Boolean
予約IDの判定を一元化する。RESERVED_IDS: auto / omakase / id RESERVED_MACRO_IDS: div / nega / comment など完全一致RESERVED_MACRO_POSITION_PREFIXES: lu25 / ls40 など接頭辞+数字
56 57 58 59 60 61 |
# File 'lib/vivlio/starter/cli/pre_process/cross_reference_processor.rb', line 56 def self.reserved_id?(label_id) return true if RESERVED_IDS.include?(label_id) return true if RESERVED_MACRO_IDS.include?(label_id) RESERVED_MACRO_POSITION_PREFIXES.any? { |prefix| label_id.match?(/\A#{prefix}\d*\z/) } end |
.transform_captioned_blocks(content, filename, labels_map) ⇒ Object
キャプション付きブロック変換
202 203 204 |
# File 'lib/vivlio/starter/cli/pre_process/cross_reference_processor.rb', line 202 def transform_captioned_blocks(content, filename, labels_map) CaptionedBlockTransformer.new(content, filename, labels_map).transform end |