Module: VivlioStarter::CLI::Build::MathTextRenderer
- Defined in:
- lib/vivlio_starter/cli/build/math_text_renderer.rb
Overview
LaTeX 単純サブセット → HTML テキスト変換器(Kindle 数式テキスト化)
Constant Summary collapse
- SYMBOLS =
名前付き記号コマンド(\times 等)→ Unicode。§3.1 の記号行。
{ 'times' => '×', 'cdot' => '⋅', 'pm' => '±', 'mp' => '∓', 'approx' => '≈', 'neq' => '≠', 'leq' => '≤', 'geq' => '≥', 'le' => '≤', 'ge' => '≥', 'sim' => '∼', 'propto' => '∝', 'infty' => '∞', 'll' => '≪', 'gg' => '≫', 'langle' => '⟨', 'rangle' => '⟩', 'ldots' => '…', 'cdots' => '…', 'dots' => '…' }.freeze
- GREEK =
ギリシャ文字コマンド → Unicode(立体=イタリックにしない・§3.1)。
{ 'alpha' => 'α', 'beta' => 'β', 'gamma' => 'γ', 'delta' => 'δ', 'epsilon' => 'ε', 'varepsilon' => 'ε', 'zeta' => 'ζ', 'eta' => 'η', 'theta' => 'θ', 'vartheta' => 'ϑ', 'iota' => 'ι', 'kappa' => 'κ', 'lambda' => 'λ', 'mu' => 'μ', 'nu' => 'ν', 'xi' => 'ξ', 'omicron' => 'ο', 'pi' => 'π', 'varpi' => 'ϖ', 'rho' => 'ρ', 'varrho' => 'ϱ', 'sigma' => 'σ', 'varsigma' => 'ς', 'tau' => 'τ', 'upsilon' => 'υ', 'phi' => 'φ', 'varphi' => 'ϕ', 'chi' => 'χ', 'psi' => 'ψ', 'omega' => 'ω', 'Gamma' => 'Γ', 'Delta' => 'Δ', 'Theta' => 'Θ', 'Lambda' => 'Λ', 'Xi' => 'Ξ', 'Pi' => 'Π', 'Sigma' => 'Σ', 'Upsilon' => 'Υ', 'Phi' => 'Φ', 'Psi' => 'Ψ', 'Omega' => 'Ω' }.freeze
- OPERATORS =
そのまま通す演算子・区切り(§3.1)。< > & は出力時にエスケープする。
%r{[+\-=/<>()\[\]|,.:;!]}
Class Method Summary collapse
-
.consume_atom(scanner, upright:, allow_script:, allow_frac:) ⇒ Object
1 アトムを消費して HTML 片を返す(空白は '' か ' ')。未知トークンは nil。.
-
.consume_brace_group(scanner, upright:, allow_script:, allow_frac:) ⇒ Object
'{ … }' を必須で読み、中身の run を返す(透過)。閉じ '}' が無ければ nil。.
-
.consume_command(scanner, upright:, allow_frac:) ⇒ Object
\command を消費する。\ は消費済みで、続く名前/記号を読む。.
-
.consume_group_or_token(scanner, upright:, allow_script:, allow_frac:) ⇒ Object
上/下付き・\frac の引数('…' グループ or 単一アトム)。先行空白は読み飛ばす。.
-
.consume_run(scanner, upright:, allow_script:, allow_frac:, stop_at_brace:) ⇒ Object
トークン列を消費して HTML を組む。stop_at_brace 時はトップレベルの '}' で停止(消費しない)。 1 つでも解釈不能なトークンがあれば nil(=式全体を拒否)。.
-
.dispatch_named_command(name, scanner, allow_frac:) ⇒ Object
英字コマンドの振り分け(\text/\mathrm・\frac・空白語・記号/ギリシャ表)。未知は nil。.
-
.escape_html(str) ⇒ Object
出力の HTML 予約文字をエスケープする(< > & のみ。" は属性化しないので不要)。.
-
.render(latex) ⇒ String?
LaTeX(デリミタ除去済み)を HTML テキストへ変換する。.
-
.wrap_script(scanner, tag, upright:, allow_script:, allow_frac:) ⇒ Object
上/下付き(/)。2 段入れ子は許さない(引数を allow_script: false で読む)。.
Class Method Details
.consume_atom(scanner, upright:, allow_script:, allow_frac:) ⇒ Object
1 アトムを消費して HTML 片を返す(空白は '' か ' ')。未知トークンは nil。
90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 |
# File 'lib/vivlio_starter/cli/build/math_text_renderer.rb', line 90 def consume_atom(scanner, upright:, allow_script:, allow_frac:) if scanner.scan(/\s+/) upright ? ' ' : '' # 数式空白は無視、\text 等の立体テキスト内は保持 elsif (letters = scanner.scan(/[A-Za-z]+/)) upright ? escape_html(letters) : "<i>#{escape_html(letters)}</i>" elsif (digits = scanner.scan(/[0-9]+/)) digits elsif scanner.scan(/\^/) wrap_script(scanner, 'sup', upright:, allow_script:, allow_frac:) elsif scanner.scan(/_/) wrap_script(scanner, 'sub', upright:, allow_script:, allow_frac:) elsif scanner.check(/\{/) consume_brace_group(scanner, upright:, allow_script:, allow_frac:) # 透過グループ elsif scanner.scan(/\\/) consume_command(scanner, upright:, allow_frac:) elsif (op = scanner.scan(OPERATORS)) escape_html(op) end end |
.consume_brace_group(scanner, upright:, allow_script:, allow_frac:) ⇒ Object
'{ … }' を必須で読み、中身の run を返す(透過)。閉じ '}' が無ければ nil。
161 162 163 164 165 166 167 168 169 |
# File 'lib/vivlio_starter/cli/build/math_text_renderer.rb', line 161 def consume_brace_group(scanner, upright:, allow_script:, allow_frac:) scanner.skip(/\s+/) return nil unless scanner.scan(/\{/) inner = consume_run(scanner, upright:, allow_script:, allow_frac:, stop_at_brace: true) return nil if inner.nil? || !scanner.scan(/\}/) inner end |
.consume_command(scanner, upright:, allow_frac:) ⇒ Object
\command を消費する。\ は消費済みで、続く名前/記号を読む。
119 120 121 122 123 124 125 126 127 128 129 130 |
# File 'lib/vivlio_starter/cli/build/math_text_renderer.rb', line 119 def consume_command(scanner, upright:, allow_frac:) if (name = scanner.scan(/[A-Za-z]+/)) dispatch_named_command(name, scanner, allow_frac:) elsif scanner.scan(/,/) # \, 細空白 " " elsif scanner.scan(/[;:]/) # \; \: 通常空白 ' ' elsif (esc = scanner.scan(/[%&#_{}$]/)) # \% \& \# \_ \{ \} \$ リテラル escape_html(esc) end # \\ やその他の記号は nil(拒否) end |
.consume_group_or_token(scanner, upright:, allow_script:, allow_frac:) ⇒ Object
上/下付き・\frac の引数('…' グループ or 単一アトム)。先行空白は読み飛ばす。
151 152 153 154 155 156 157 158 |
# File 'lib/vivlio_starter/cli/build/math_text_renderer.rb', line 151 def consume_group_or_token(scanner, upright:, allow_script:, allow_frac:) scanner.skip(/\s+/) if scanner.check(/\{/) consume_brace_group(scanner, upright:, allow_script:, allow_frac:) else consume_atom(scanner, upright:, allow_script:, allow_frac:) end end |
.consume_run(scanner, upright:, allow_script:, allow_frac:, stop_at_brace:) ⇒ Object
トークン列を消費して HTML を組む。stop_at_brace 時はトップレベルの '}' で停止(消費しない)。 1 つでも解釈不能なトークンがあれば nil(=式全体を拒否)。
76 77 78 79 80 81 82 83 84 85 86 87 |
# File 'lib/vivlio_starter/cli/build/math_text_renderer.rb', line 76 def consume_run(scanner, upright:, allow_script:, allow_frac:, stop_at_brace:) buf = +'' until scanner.eos? break if stop_at_brace && scanner.check(/\}/) piece = consume_atom(scanner, upright:, allow_script:, allow_frac:) return nil if piece.nil? buf << piece end buf end |
.dispatch_named_command(name, scanner, allow_frac:) ⇒ Object
英字コマンドの振り分け(\text/\mathrm・\frac・空白語・記号/ギリシャ表)。未知は nil。
133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 |
# File 'lib/vivlio_starter/cli/build/math_text_renderer.rb', line 133 def dispatch_named_command(name, scanner, allow_frac:) case name when 'text', 'mathrm' consume_brace_group(scanner, upright: true, allow_script: false, allow_frac: false) when 'frac' return nil unless allow_frac numer = consume_brace_group(scanner, upright: false, allow_script: true, allow_frac: false) denom = numer && consume_brace_group(scanner, upright: false, allow_script: true, allow_frac: false) denom && "#{numer}/#{denom}" when 'quad', 'qquad' ' ' else SYMBOLS[name] || GREEK[name] end end |
.escape_html(str) ⇒ Object
出力の HTML 予約文字をエスケープする(< > & のみ。" は属性化しないので不要)。
172 |
# File 'lib/vivlio_starter/cli/build/math_text_renderer.rb', line 172 def escape_html(str) = str.gsub('&', '&').gsub('<', '<').gsub('>', '>') |
.render(latex) ⇒ String?
LaTeX(デリミタ除去済み)を HTML テキストへ変換する。
63 64 65 66 67 68 69 70 71 72 |
# File 'lib/vivlio_starter/cli/build/math_text_renderer.rb', line 63 def render(latex) src = latex.to_s return nil if src.strip.empty? scanner = StringScanner.new(src) html = consume_run(scanner, upright: false, allow_script: true, allow_frac: true, stop_at_brace: false) return nil if html.nil? || !scanner.eos? # 未消費が残る=解釈できないトークンがあった html end |
.wrap_script(scanner, tag, upright:, allow_script:, allow_frac:) ⇒ Object
上/下付き(/)。2 段入れ子は許さない(引数を allow_script: false で読む)。
111 112 113 114 115 116 |
# File 'lib/vivlio_starter/cli/build/math_text_renderer.rb', line 111 def wrap_script(scanner, tag, upright:, allow_script:, allow_frac:) return nil unless allow_script arg = consume_group_or_token(scanner, upright:, allow_script: false, allow_frac:) arg && "<#{tag}>#{arg}</#{tag}>" end |