Module: Vivlio::Starter::CLI::PreProcessCommands::DataRender::TemplateCompiler
- Defined in:
- lib/vivlio/starter/cli/pre_process/data_render/template_compiler.rb
Overview
テンプレートコンパイラモジュール
Constant Summary collapse
- VARIABLE_PATTERN =
変数展開パターン: = key(行内に出現)
/(?<!=)=\s+([a-zA-Z_][a-zA-Z0-9_]*)/- IMAGE_VAR_PATTERN =
画像記法内の変数展開パターン:  /  名前付きキャプチャで gsub ブロック内の $N 上書き問題を回避
/!\[(?<alt>[^\]]*)\]\((?:=\s*)?(?<src>[^)]+)\)(?<attr>\{[^}]*\})?/- IMAGE_EXTENSIONS =
画像の拡張子(リテラル判定用)
%w[png jpg jpeg webp gif svg].freeze
Class Method Summary collapse
-
.classify_lines(lines) ⇒ Array<Hash>
テンプレート行を分類する.
-
.contains_variable?(line) ⇒ Boolean
行に変数参照(= key)が含まれるかを判定する.
-
.expand_images(line, record) ⇒ String?
画像記法内の変数を展開する.
-
.expand_line(line, record) ⇒ String?
テンプレート行をレコードデータで展開する nil/空文字のキーがあれば行ごとスキップ(nil を返す).
-
.expand_variables(line, record) ⇒ String?
key パターンの変数を展開する.
-
.image_has_variable?(line) ⇒ Boolean
画像記法内に変数参照があるかを判定する.
-
.literal_image?(src) ⇒ Boolean
画像パスがリテラル(拡張子あり)かを判定する.
-
.render(template, records, source_filename: nil, line_number: nil) ⇒ String
テンプレートにレコード群を流し込んで Markdown を生成する.
-
.validate_template_keys!(lines, sample_record, source_filename: nil, line_number: nil) ⇒ Object
テンプレート内のキーがデータに存在するかを検証する.
Class Method Details
.classify_lines(lines) ⇒ Array<Hash>
テンプレート行を分類する
82 83 84 85 86 87 88 89 90 91 92 |
# File 'lib/vivlio/starter/cli/pre_process/data_render/template_compiler.rb', line 82 def classify_lines(lines) lines.map do |line| if line.strip.empty? { type: :blank } elsif contains_variable?(line) { type: :dynamic, content: line } else { type: :static, content: line } end end end |
.contains_variable?(line) ⇒ Boolean
行に変数参照(= key)が含まれるかを判定する
97 98 99 100 101 102 |
# File 'lib/vivlio/starter/cli/pre_process/data_render/template_compiler.rb', line 97 def contains_variable?(line) return true if line.match?(VARIABLE_PATTERN) return true if line.match?(IMAGE_VAR_PATTERN) && image_has_variable?(line) false end |
.expand_images(line, record) ⇒ String?
画像記法内の変数を展開する
145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 |
# File 'lib/vivlio/starter/cli/pre_process/data_render/template_compiler.rb', line 145 def (line, record) result = line.dup skip = false result.gsub!(IMAGE_VAR_PATTERN) do |match| md = Regexp.last_match alt = md[:alt] src = md[:src].sub(/\A=\s*/, '').strip attr = md[:attr] || '' if literal_image?(src) # 拡張子ありはリテラルとしてそのまま出力 match else # 変数として展開 value = record[src.to_sym] if value.nil? || value.to_s.strip.empty? skip = true match # gsub のブロックからは文字列を返す必要がある else "#{attr}" end end end skip ? nil : result end |
.expand_line(line, record) ⇒ String?
テンプレート行をレコードデータで展開するnil/空文字のキーがあれば行ごとスキップ(nil を返す)
127 128 129 130 131 132 133 134 135 136 137 138 139 |
# File 'lib/vivlio/starter/cli/pre_process/data_render/template_compiler.rb', line 127 def (line, record) result = line.dup # 画像記法の展開(先に処理) result = (result, record) return nil unless result # = key パターンの展開 result = (result, record) return nil unless result result end |
.expand_variables(line, record) ⇒ String?
key パターンの変数を展開する
177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 |
# File 'lib/vivlio/starter/cli/pre_process/data_render/template_compiler.rb', line 177 def (line, record) result = line.dup result.gsub!(VARIABLE_PATTERN) do |_match| key = ::Regexp.last_match(1).to_sym value = record[key] if value.nil? || value.to_s.strip.empty? return nil # 行ごとスキップ end value.to_s end result end |
.image_has_variable?(line) ⇒ Boolean
画像記法内に変数参照があるかを判定する
107 108 109 110 111 112 |
# File 'lib/vivlio/starter/cli/pre_process/data_render/template_compiler.rb', line 107 def image_has_variable?(line) line.scan(IMAGE_VAR_PATTERN).any? do |(_, src, _)| src = src.sub(/\A=\s*/, '').strip !literal_image?(src) end end |
.literal_image?(src) ⇒ Boolean
画像パスがリテラル(拡張子あり)かを判定する
117 118 119 120 |
# File 'lib/vivlio/starter/cli/pre_process/data_render/template_compiler.rb', line 117 def literal_image?(src) ext = File.extname(src).delete_prefix('.').downcase IMAGE_EXTENSIONS.include?(ext) end |
.render(template, records, source_filename: nil, line_number: nil) ⇒ String
テンプレートにレコード群を流し込んで Markdown を生成する
47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 |
# File 'lib/vivlio/starter/cli/pre_process/data_render/template_compiler.rb', line 47 def render(template, records, source_filename: nil, line_number: nil) lines = template.lines validate_template_keys!(lines, records.first, source_filename:, line_number:) if records.any? # テンプレート行を「反復行」と「静的行」に分類する # = key を含む行は反復行、含まない行は静的行 parts = classify_lines(lines) output = [] records.each_with_index do |record, idx| # レコード間に空行を挿入(最初のレコード以外) output << "\n" if idx.positive? parts.each do |part| case part in { type: :static, content: } # 静的行は最初のレコードでのみ出力 output << content if idx.zero? in { type: :dynamic, content: } # 動的行はレコードごとに展開 = (content, record) output << if in { type: :blank } # テンプレート内の空行は出力 output << "\n" end end end output.join end |
.validate_template_keys!(lines, sample_record, source_filename: nil, line_number: nil) ⇒ Object
テンプレート内のキーがデータに存在するかを検証する
198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 |
# File 'lib/vivlio/starter/cli/pre_process/data_render/template_compiler.rb', line 198 def validate_template_keys!(lines, sample_record, source_filename: nil, line_number: nil) return unless sample_record location = source_filename ? "#{source_filename}:#{line_number}" : '' available_keys = sample_record.keys lines.each do |line| # = key パターン line.scan(VARIABLE_PATTERN).each do |(key)| key_sym = key.to_sym next if available_keys.include?(key_sym) Common.log_error("テンプレートに存在しないキーが記述されています(#{location})") Common.log_error(" キー: #{key}") Common.log_error(" 利用可能なキー: #{available_keys.join(', ')}") raise DataRenderError, "テンプレートに存在しないキーが記述されています: #{key}" end # 画像記法内の変数 line.scan(IMAGE_VAR_PATTERN).each do |(_, src, _)| src = src.sub(/\A=\s*/, '').strip next if literal_image?(src) key_sym = src.to_sym next if available_keys.include?(key_sym) Common.log_error("テンプレートに存在しないキーが記述されています(#{location})") Common.log_error(" キー: #{src}") Common.log_error(" 利用可能なキー: #{available_keys.join(', ')}") raise DataRenderError, "テンプレートに存在しないキーが記述されています: #{src}" end end end |