Module: VivlioStarter::CLI::PreProcessCommands::TalkRegistry

Defined in:
lib/vivlio_starter/cli/pre_process/talk_registry.rb

Overview

config/talk.yml の読み込みと正規化

Defined Under Namespace

Classes: Character, Registry, TalkDisplay

Constant Summary collapse

DISPLAY_KEY =

表示設定を置くトップレベルの予約キー(これ以外はすべて話者とみなす)。

'display'
STYLES =

受理する表示形式。

%i[chat inline].freeze
AVATAR_MODES =

アバターの表示モード(talk-auto-avatar-spec.md §1.1)。 :on … avatar: に画像を指定した話者だけ表示 :auto … 画像があればそれ、無ければ簡易アバターを自動生成 :off … 表示しない

%i[on auto off].freeze
AVATAR_AUTO =

話者の avatar: にファイル名の代わりに書くと自動生成になる値。

'auto'
DEFAULT_DISPLAY =

組み込み既定(talk.yml に display: が無い/キーが欠けているときの値)。

TalkDisplay.new(style: :chat, name: true, avatar: :on, separator: '').freeze

Class Method Summary collapse

Class Method Details

.allowed_colorsObject



213
214
215
216
# File 'lib/vivlio_starter/cli/pre_process/talk_registry.rb', line 213

def allowed_colors
  require_relative 'frontmatter_generator'
  FrontmatterGenerator::ALLOWED_COLORS
end

.blank_to_nil(value) ⇒ Object



218
219
220
221
# File 'lib/vivlio_starter/cli/pre_process/talk_registry.rb', line 218

def blank_to_nil(value)
  s = value.to_s.strip
  s.empty? ? nil : s
end

.build_characters(raw) ⇒ Array<Character>

display: を除くトップレベルのキーをすべて話者として正規化する。

Returns:



163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
# File 'lib/vivlio_starter/cli/pre_process/talk_registry.rb', line 163

def build_characters(raw)
  # side 省略時は「出現順」で left, right, left, … と交互に割当てる(位置ベース)。
  # 明示指定は値のみ上書きし、位置カウンタ自体は全話者で進める——そうすれば
  # 一部だけ side を明示しても、残りの自動割当が出現順の交互ストライプを保つ。
  position = 0
  raw.filter_map do |key, spec|
    key = key.to_s.strip
    next if key.empty? || key == DISPLAY_KEY

    name, color, avatar, side = extract(spec, key)
    side = position.even? ? 'left' : 'right' unless %w[left right].include?(side)
    position += 1
    Character.new(key:, name:, color:, avatar:, side:)
  end
end

.build_display(raw) ⇒ Object

display: セクションを TalkDisplay へ正規化する。キーが無ければ組み込み既定を使う。



123
124
125
126
127
128
129
130
131
132
# File 'lib/vivlio_starter/cli/pre_process/talk_registry.rb', line 123

def build_display(raw)
  return DEFAULT_DISPLAY unless raw.is_a?(Hash)

  DEFAULT_DISPLAY.with(
    style: parse_style(raw['style']),
    name: parse_flag(raw, 'name', DEFAULT_DISPLAY.name),
    avatar: raw.key?('avatar') ? parse_avatar_mode(raw['avatar']) : DEFAULT_DISPLAY.avatar,
    separator: raw.key?('separator') ? raw['separator'].to_s : DEFAULT_DISPLAY.separator
  )
end

.color_valid?(value) ⇒ Boolean

ThemeValidator の色検証を流用する(遅延 require でロード循環を回避)。

Returns:

  • (Boolean)


208
209
210
211
# File 'lib/vivlio_starter/cli/pre_process/talk_registry.rb', line 208

def color_valid?(value)
  require_relative 'theme_validator'
  ThemeValidator.valid_color?(value)
end

.default_pathObject

config/talk.yml の既定パス(config ディレクトリ直下)。



99
# File 'lib/vivlio_starter/cli/pre_process/talk_registry.rb', line 99

def default_path = File.join(Common.config_dir, 'talk.yml')

.extract(spec, key) ⇒ Array(String, String, String, String)

1 エントリの値(簡易形=色文字列 / 詳細形=マップ)から属性 4 つを取り出す。

Returns:

  • (Array(String, String, String, String))

    name, color, avatar, side(未指定は nil/空)



181
182
183
184
185
186
187
188
189
190
# File 'lib/vivlio_starter/cli/pre_process/talk_registry.rb', line 181

def extract(spec, key)
  if spec.is_a?(Hash)
    name = blank_to_nil(spec['name'] || spec[:name]) || key
    [name, validate_color(spec['color'] || spec[:color], key),
     blank_to_nil(spec['avatar'] || spec[:avatar]), (spec['side'] || spec[:side]).to_s.strip.downcase]
  else
    # 簡易形: 値が色(テーマ色名 or HEX)。表示名はキー、アバターなし、side 自動。
    [key, validate_color(spec, key), nil, '']
  end
end

.from_hash(raw) ⇒ Object

Hash(YAML 相当)から Registry を組む。テストと load から共用する。



117
118
119
120
# File 'lib/vivlio_starter/cli/pre_process/talk_registry.rb', line 117

def from_hash(raw)
  hash = raw.is_a?(Hash) ? raw : {}
  Registry.new(build_characters(hash), display: build_display(hash[DISPLAY_KEY]), present: true)
end

.load(path = default_path) ⇒ Registry

ファイルを読んで Registry を返す。存在しなければ空(present: false)。

Parameters:

  • path (String) (defaults to: default_path)

    読み込み対象(既定は default_path)

Returns:



104
105
106
107
108
# File 'lib/vivlio_starter/cli/pre_process/talk_registry.rb', line 104

def load(path = default_path)
  return Registry.new([], display: DEFAULT_DISPLAY, present: false) unless File.exist?(path)

  from_hash(read_yaml(path))
end

.parse_avatar_mode(raw) ⇒ Object

アバターの表示モードを解決する。auto を先に見てから真偽解釈する (Common.truthy? は 'auto' を偽と判定するため)。



136
137
138
139
140
141
# File 'lib/vivlio_starter/cli/pre_process/talk_registry.rb', line 136

def parse_avatar_mode(raw)
  value = raw.to_s.strip.downcase
  return :auto if value == AVATAR_AUTO

  Common.truthy?(value) ? :on : :off
end

.parse_flag(raw, key, fallback) ⇒ Object

真偽キーを解決する。キーが無ければ既定を引き継ぐ(明示 false と区別する)。



157
158
159
# File 'lib/vivlio_starter/cli/pre_process/talk_registry.rb', line 157

def parse_flag(raw, key, fallback)
  raw.key?(key) ? Common.truthy?(raw[key]) : fallback
end

.parse_style(raw) ⇒ Object

style 値を Symbol へ。未指定は既定、未知値は 🟡 で既定へフォールバック。



144
145
146
147
148
149
150
151
152
153
154
# File 'lib/vivlio_starter/cli/pre_process/talk_registry.rb', line 144

def parse_style(raw)
  value = raw.to_s.strip.downcase
  return DEFAULT_DISPLAY.style if value.empty?
  return value.to_sym if STYLES.include?(value.to_sym)

  Common.log_warn(
    "config/talk.yml: display.style '#{raw}' は不明な表示形式です。#{DEFAULT_DISPLAY.style} で続行します。",
    detail: "指定できるのは #{STYLES.join(' / ')} です"
  )
  DEFAULT_DISPLAY.style
end

.read_yaml(path) ⇒ Object

壊れた YAML は 🔴+行番号で報告し、空({})として扱う(ビルドは止めない)。



224
225
226
227
228
229
230
231
232
# File 'lib/vivlio_starter/cli/pre_process/talk_registry.rb', line 224

def read_yaml(path)
  YAML.safe_load(File.read(path, encoding: 'utf-8'), aliases: true)
rescue Psych::SyntaxError => e
  Common.log_error(
    "config/talk.yml の解析に失敗しました(#{e.line}行目付近)",
    detail: e.problem.to_s
  )
  nil
end

.reset!Object



114
# File 'lib/vivlio_starter/cli/pre_process/talk_registry.rb', line 114

def reset! = (@shared = nil)

.sharedObject

ビルド 1 回につき 1 度だけ読む共有インスタンス(前処理は章ごとに走るため)。 無効色などの警告もここで一度きりに集約される。テストは reset! で破棄する。



112
# File 'lib/vivlio_starter/cli/pre_process/talk_registry.rb', line 112

def shared = (@shared ||= load)

.validate_color(raw, key) ⇒ Object

色の妥当性を検証する。無効値は 🟡 で警告してテーマ色へフォールバック(nil を返す)。 未指定(空)は警告せず nil(=テーマアクセント色を使う)。



194
195
196
197
198
199
200
201
202
203
204
205
# File 'lib/vivlio_starter/cli/pre_process/talk_registry.rb', line 194

def validate_color(raw, key)
  value = raw.to_s.strip
  return nil if value.empty?
  return value if color_valid?(value)

  Common.log_warn(
    "config/talk.yml: キャラクター '#{key}' の色 '#{raw}' は無効です。テーマ色でビルドを続行します。",
    detail: "指定できる色: #{allowed_colors.join(' / ')}" \
            "または '#4f46e5' のような HEX(#rrggbb / #rrggbbaa)"
  )
  nil
end