Module: VivlioStarter::CLI::PreProcessCommands::DataRender

Defined in:
lib/vivlio_starter/cli/pre_process/data_render.rb,
lib/vivlio_starter/cli/pre_process/data_render/singularize.rb,
lib/vivlio_starter/cli/pre_process/data_render/template_compiler.rb,
lib/vivlio_starter/cli/pre_process/data_render/query_stream_parser.rb

Overview

QueryStream 記法を展開してMarkdownを生成するモジュール 実処理は query-stream gem に委譲する

Defined Under Namespace

Modules: QueryStreamParser, Singularize, TemplateCompiler

Class Method Summary collapse

Class Method Details

.line_from_location(location) ⇒ Integer?

QueryStream の location("21-images.md:42")から行番号だけを取り出す。 章はコールバック側で source_filename を使うため、ここでは行のみを見る。

Returns:

  • (Integer, nil)


120
121
122
# File 'lib/vivlio_starter/cli/pre_process/data_render.rb', line 120

def line_from_location(location)
  location.to_s[/:(\d+)\z/, 1]&.to_i
end

.process(content, source_filename: nil, chapter_slug: nil, data_dir: Common.data_dir, templates_dir: Common::TEMPLATES_DIR) ⇒ String

Markdown コンテンツ内の QueryStream 記法をすべて展開する

Parameters:

  • content (String)

    Markdown コンテンツ

  • source_filename (String) (defaults to: nil)

    エラー報告用のソースファイル名

  • chapter_slug (String, nil) (defaults to: nil)

    章スラッグ(データ画像の章ローカル探索に使う。nil ならデータ画像解決なし)

  • data_dir (String) (defaults to: Common.data_dir)

    データディレクトリのパス

  • templates_dir (String) (defaults to: Common::TEMPLATES_DIR)

    テンプレートディレクトリのパス

Returns:

  • (String)

    展開後の Markdown コンテンツ



35
36
37
38
39
40
41
42
43
44
45
46
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
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
# File 'lib/vivlio_starter/cli/pre_process/data_render.rb', line 35

def process(content, source_filename: nil, chapter_slug: nil, data_dir: Common.data_dir,
            templates_dir: Common::TEMPLATES_DIR)
  # gem 側はログを出力しないため、on_error / on_warning コールバックでメッセージを構成する。
  # Common.log_error / log_warn が 🔴 / 🟡 の絵文字プレフィックスを付与するため、
  # コールバック側ではプレフィックスを付けない。
  # 章別サマリーへの記録(preflight-chapter-summary-spec.md §2.2)。
  # 章は処理中のファイルそのもの、行は location("file:line")から取る
  # (location を持たない一般エラー・警告もあるため respond_to? で確かめる)。
  record_issue = lambda do |severity, subject|
    location = subject.respond_to?(:location) ? subject.location : nil
    IssueRegistry.record(
      chapter: source_filename, line: line_from_location(location),
      severity:, category: :query_stream, message: subject.message
    )
  end

  on_error = lambda do |error|
    record_issue.call(:error, error)
    case error
    in QueryStream::TemplateNotFoundError => e
      # location は "filename:line" 形式
      detail_lines = ["雛形の場所: #{e.template_path}"]
      detail_lines << "ヒント: #{e.hint}" if e.hint
      Common.log_error(
        "#{e.location} - 雛形ファイル '#{File.basename(e.template_path)}' が見つかりません(記法: #{e.query}",
        detail: detail_lines.join("\n")
      )
    in QueryStream::DataNotFoundError => e
      Common.log_error(
        "#{e.location} - データファイルが見つかりません(記法: #{e.query}",
        detail: "データの場所: #{e.expected_path}"
      )
    in QueryStream::UnknownKeyError => e
      Common.log_error(
        "#{e.location} - 雛形に無いキーが書かれています: =#{e.key_path}",
        detail: unknown_key_detail(e)
      )
    else
      Common.log_error("QueryStream 展開エラー: #{error.message}")
    end
  end

  on_warning = lambda do |warning|
    record_issue.call(:warn, warning)
    case warning
    in QueryStream::NoResultWarning => w
      Common.log_warn(
        "#{w.location} - 一件検索で該当レコードが見つかりません(記法: #{w.query}"
      )
    in QueryStream::AmbiguousQueryWarning => w
      Common.log_warn(
        "#{w.location} - 一件検索で複数件ヒット(#{w.count} 件)。条件を明示してください(記法: #{w.query}"
      )
    else
      Common.log_warn("QueryStream 警告: #{warning.message}")
    end
  end

  # QueryStream 展開結果内の素ファイル名画像を data/ 配下から解決する後段フィルタ。
  # gem は画像を知らないため、この post_render で vivlio-starter 固有の解決を担う(spec §3.3)。
  # chapter_slug が無い(単体テスト等)ときは解決を行わず素通しする。
  post_render = nil
  if chapter_slug
    post_render = lambda do |text, ctx|
      DataImageResolver.rewrite(text, ctx, chapter_slug:)
    rescue StandardError => e
      Common.log_warn("データ画像の解決に失敗しました: #{e.class}: #{e.message}")
      text
    end
  end

  QueryStream.render(
    content,
    source_filename:,
    data_dir:,
    templates_dir:,
    on_error:,
    on_warning:,
    post_render:
  )
end

.unknown_key_detail(error) ⇒ String

雛形の打ち間違いをどう直せばよいかを著者へ示す。 gem が持つのは素材(無いキー・使えるキー・雛形のパス)までで、そこから 「もしかして」を組み立てられるのは、著者向けの言葉づかいを担うこちら側だけである。 ドット記法(=author.name)は先頭のキーだけが検証対象なので、候補も先頭で探す。

Parameters:

  • error (QueryStream::UnknownKeyError)

Returns:

  • (String)


130
131
132
133
134
135
136
137
138
139
140
141
# File 'lib/vivlio_starter/cli/pre_process/data_render.rb', line 130

def unknown_key_detail(error)
  keys = error.available_keys.map(&:to_s)
  root = error.key_path.to_s.split('.').first
  near = DidYouMean::SpellChecker.new(dictionary: keys).correct(root).first

  detail = []
  # 記法の位置(見出し行の location)ではなく雛形を直すので、開くべきファイルを名指しする
  detail << "直す場所: #{error.template_path}" if error.template_path
  detail << "→ もしかして: =#{root} ではなく =#{near} ではありませんか?" if near
  detail << "この雛形で使えるキー: #{keys.join(', ')}"
  detail.join("\n")
end