Module: VivlioStarter::CLI::Lint::NotationGuard

Defined in:
lib/vivlio_starter/cli/lint/notation_guard.rb

Overview

VFM 記法の中和(lint 系専用)。

Constant Summary collapse

MACHINE_DATA_CONTAINERS =

機械データ(座標・オプション)を本文として持つコンテナ名。 記法を追加するときはここへ 1 語加えればガードが追従する。

%w[showcase].freeze
MACHINE_BLOCK_OPEN =

機械データ・ブロックの開始行(例: :::{.showcase})。 ShowcaseTransformer::BLOCK_PATTERN の開始側と揃える(行末に本文が続く :::{.showcase} foo は同 PATTERN が消費しない=ブロックではないため、 ガードもブロックとして扱わない)。

/\A:::\s*\{\s*\.(?:#{Regexp.union(MACHINE_DATA_CONTAINERS).source})\s*\}[ \t]*\r?\n?\z/
MACHINE_BLOCK_CLOSE =

機械データ・ブロックの終了行(例: :::)。

/\A:::[ \t]*\r?\n?\z/
CONTAINER_MARKER =

コンテナのマーカー行(開始・終了とも)。コロン 3 つ以上+任意の属性ブレースで 行全体が構成されるものだけをマーカーとみなす。

「:::" で始まる行」まで広げてはならない: コメントアウトされたコンテナの閉じ :::--> を空行化すると HTML コメントの --> が消え、コメントが永久に閉じず、 その中身(表・数式)を読んだ textlint が暴走する実害があった(94 章で CPU 99%)。 マーカーでないものはガードの対象外=素のまま textlint へ渡す(現状維持が正しい)。

/\A[ \t]*:{3,}[ \t]*(?:\{[^{}\n]*\})?[ \t]*\r?\n?\z/
FURIGANA =

ふりがな記法 {親文字|ふりがな}

/\{([^{}|]*)\|[^{}]*\}/
CLASS_ATTRIBUTE =

クラス属性記法 {.classname}

/\{\.[-\w]+\}/
MATH_PLACEHOLDER =

記法を中和したテキストを返す。行数は入力と必ず一致する(I1)。 数式の退避に使う目印。--fix に触られず、textlint の指摘も生まないことを実測で選んだ (インラインコード化は spaceAroundCode を誘発し、X のような 1 文字は 全角と半角の間のスペース規則に触れる)。

Returns:

  • (String)

    記法を中和した内容

'VSMATH'
MATH_PATTERNS =

数式の綴りは変換器と同じ定義を使う。ここで別に書くと、lint が守る範囲と ビルドが数式として扱う範囲がずれる。

[
  PreProcessCommands::MathTransformer::DISPLAY_DOLLAR,
  PreProcessCommands::MathTransformer::DISPLAY_BRACKET,
  PreProcessCommands::MathTransformer::INLINE_DOLLAR,
  PreProcessCommands::MathTransformer::INLINE_PAREN
].freeze

Class Method Summary collapse

Class Method Details

.blank_math(text) ⇒ Object

解析パス用: 数式を目印を残さず落とす。

mask_math の目印(VSMATH0)をそのまま残すと、スペルチェックが未知語として拾う ——Tokenizer.tokenize も記法判定を一本化するために strip_notation を通るため (実測: VSMATH => smith が本書 21 章で 5 件)。解析パスは復元しないので、 目印を置く必要がない。行数は mask_math が足した改行で保たれる。



131
132
133
134
# File 'lib/vivlio_starter/cli/lint/notation_guard.rb', line 131

def blank_math(text)
  masked, spans = mask_math(text)
  spans.keys.reduce(masked) { |acc, key| acc.sub(key, '') }
end

.mask_math(text) ⇒ Array(String, Hash)

数式を目印へ退避する。lint は数式を日本語の文として読むべきではない。

放置すると、数式の中の半角括弧が prh に「全角にせよ」と指摘され、--fix が 当たれば $(1/2)πr³$$(1/2)πr³$ になって数式が壊れる(実測)。 コードスパンは textlint が Code ノードとして飛ばすのに、数式は素の文として 読まれるための穴で、素の表記を数式として組む機能が入って表面化した。

行数は保存する(I1)——複数行のディスプレイ数式は、落とした改行を目印の後ろへ足す。

Returns:

  • (Array(String, Hash))

    退避後テキストと { 目印 => 原文 }



102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
# File 'lib/vivlio_starter/cli/lint/notation_guard.rb', line 102

def mask_math(text)
  protected_text, code = Masking.protect_code(text)
  spans = {}
  masked = MATH_PATTERNS.reduce(protected_text) do |acc, pattern|
    acc.gsub(pattern) do
      original = ::Regexp.last_match(0)
      # **桁は固定幅にする。** `VSMATH1` は `VSMATH10` の頭に一致してしまい、
      # 10 個以上の数式がある章で目印が食い違って残骸が出る(実測: 本書 92 章)。
      key = format("%s%04d", MATH_PLACEHOLDER, spans.size)
      spans[key] = original
      "#{key}#{"\n" * original.count("\n")}"
    end
  end
  [Masking.restore_code(masked, code), spans]
end

.restore_math(text, spans) ⇒ Object

mask_math で退避した数式を戻す。



119
120
121
122
123
# File 'lib/vivlio_starter/cli/lint/notation_guard.rb', line 119

def restore_math(text, spans)
  spans.reduce(text) do |acc, (key, original)|
    acc.sub(/#{Regexp.escape(key)}\n{0,#{original.count("\n")}}/) { original }
  end
end

.strip_notation(text) ⇒ Object



136
137
138
139
140
141
142
143
144
145
146
147
148
# File 'lib/vivlio_starter/cli/lint/notation_guard.rb', line 136

def strip_notation(text)
  text = blank_math(text)
  prose   = prose_lines(text)
  machine = machine_block_lines(text, prose)

  text.each_line.with_index(1).map do |line, lineno|
    if !prose.include?(lineno)          then line          # コード領域は不変
    elsif machine.include?(lineno)      then blank(line)   # G1 機械データ・ブロック
    elsif line.match?(CONTAINER_MARKER) then blank(line)   # G2 コンテナのマーカー行
    else neutralize_inline(line)                           # G3 ふりがな → G4 クラス属性
    end
  end.join
end