Class: VivlioStarter::CLI::UnifiedTermsManager

Inherits:
Object
  • Object
show all
Defined in:
lib/vivlio_starter/cli/index/unified_terms_manager.rb

Constant Summary collapse

UNIFIED_FILE =
'config/index_glossary_terms.yml'

Instance Method Summary collapse

Constructor Details

#initializeUnifiedTermsManager

Returns a new instance of UnifiedTermsManager.



32
33
34
# File 'lib/vivlio_starter/cli/index/unified_terms_manager.rb', line 32

def initialize
  @cache = nil
end

Instance Method Details

#clear_cache!Object

キャッシュをクリア



281
282
283
# File 'lib/vivlio_starter/cli/index/unified_terms_manager.rb', line 281

def clear_cache!
  @cache = nil
end

#find_term(name) ⇒ Hash?

用語を名前で検索

Parameters:

  • name (String)

    用語名

Returns:

  • (Hash, nil)


80
# File 'lib/vivlio_starter/cli/index/unified_terms_manager.rb', line 80

def find_term(name) = load_terms.find { it['term'] == name }

#follow_scanned_chapters(old_basename, new_basename) ⇒ Object

scanned_chapters を追随させる。 record_scanned_chapters! は「実在する章との積」を取るので、原稿ファイルが 移動済みなら旧章名はそこで自然に落ちる。新章名を渡すだけでよい。



273
274
275
276
277
278
# File 'lib/vivlio_starter/cli/index/unified_terms_manager.rb', line 273

def follow_scanned_chapters(old_basename, new_basename)
  scanned = scanned_chapters
  return unless scanned&.include?(old_basename)

  record_scanned_chapters!([new_basename])
end

#glossary_term_namesObject

用語集対象の用語名



75
# File 'lib/vivlio_starter/cli/index/unified_terms_manager.rb', line 75

def glossary_term_names = glossary_terms.map { it['term'] }

#glossary_termsObject

flags に g を含む用語(用語集対象)



66
# File 'lib/vivlio_starter/cli/index/unified_terms_manager.rb', line 66

def glossary_terms = load_terms.select { glossary_flag?(it['flags']) }

#index_term_namesObject

索引対象の用語名



72
# File 'lib/vivlio_starter/cli/index/unified_terms_manager.rb', line 72

def index_term_names = index_terms.map { it['term'] }

#index_termsObject

flags に i を含む用語(索引対象)



63
# File 'lib/vivlio_starter/cli/index/unified_terms_manager.rb', line 63

def index_terms = load_terms.select { index_flag?(it['flags']) }

#load_termsArray<Hash>

全用語を読み込み

Returns:

  • (Array<Hash>)

    用語のリスト



40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
# File 'lib/vivlio_starter/cli/index/unified_terms_manager.rb', line 40

def load_terms
  return @cache if @cache

  unless File.exist?(UNIFIED_FILE)
    @cache = []
    return @cache
  end

  begin
    data = YAML.load_file(UNIFIED_FILE, symbolize_names: false)
    terms = data['terms'] || []
    # 後方互換: flags 未設定のエントリは用語集由来とみなし 'g' を付与
    terms.each { it['flags'] ||= 'g' }
    @cache = terms
  rescue StandardError => e
    Common.log_warn("#{UNIFIED_FILE} の読み込みに失敗: #{e.message}")
    @cache = []
  end

  @cache
end

#merge_terms!(new_terms, flags: 'i', source: 'auto_extracted') ⇒ Array<String>

用語をマージして保存 同名の用語が既存の場合は更新、なければ追加

Parameters:

  • new_terms (Array<Hash>)

    追加する用語

  • flags (String) (defaults to: 'i')

    デフォルトの flags ('i', 'g', 'ig')

  • source (String) (defaults to: 'auto_extracted')

    登録元

Returns:

  • (Array<String>)

    新規追加された用語名(呼び出し元の登録要約表示・R8 に使う)



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
# File 'lib/vivlio_starter/cli/index/unified_terms_manager.rb', line 90

def merge_terms!(new_terms, flags: 'i', source: 'auto_extracted')
  return [] if new_terms.nil? || new_terms.empty?

  existing = load_terms.dup
  added_names = []

  new_terms.each do |term|
    term_name = term['term'] || term[:term]
    next if term_name.nil? || term_name.empty?

    idx = existing.find_index { it['term'] == term_name }
    if idx
      # 既存用語を更新(flags をマージ、データを上書き)
      existing[idx] = merge_term_data(existing[idx], term, flags)
    else
      # 新規追加
      existing << build_term_entry(term, flags, source)
      added_names << term_name
    end
  end

  save_terms!(existing)
  Common.log_success("#{added_names.size} 件の用語を追加しました") if added_names.any?
  added_names
end

#record_scanned_chapters!(chapters) ⇒ Object

走査した章集合を和集合で記録する(R7)。 contents/ に実在する章だけ残し、改名・削除の残骸は落とす。 辞書ファイルが無いときは何もしない(空辞書を作ると「辞書なし」案内を壊すため)

Parameters:

  • chapters (Array<String>)

    今回走査した章(ベースネームまたはパス)



221
222
223
224
225
226
227
228
229
# File 'lib/vivlio_starter/cli/index/unified_terms_manager.rb', line 221

def record_scanned_chapters!(chapters)
  return unless File.exist?(UNIFIED_FILE)

  data = YAML.load_file(UNIFIED_FILE, symbolize_names: false)
  existing_files = Dir.glob(File.join(Common::CONTENTS_DIR, '*.md')).map { File.basename(it, '.md') }
  merged = ((data['scanned_chapters'] || []) | chapters.map { File.basename(it.to_s, '.md') }) & existing_files
  data['scanned_chapters'] = merged.sort
  File.write(UNIFIED_FILE, data.to_yaml, encoding: 'utf-8')
end

#remove_flag!(term_name, remove_flag) ⇒ Object

flags から特定のフラグを除去(用語自体は残す) 例: flags 'ig' から 'i' を除去 → 'g' に変更

Parameters:

  • term_name (String)

    用語名

  • remove_flag (String)

    除去するフラグ ('i' or 'g')



132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
# File 'lib/vivlio_starter/cli/index/unified_terms_manager.rb', line 132

def remove_flag!(term_name, remove_flag)
  existing = load_terms.dup
  term = existing.find { it['term'] == term_name }
  return unless term

  current = term['flags'] || ''
  new_flags = case remove_flag
              when 'i' then current.delete('i')
              when 'g' then current.delete('g')
              else current
              end

  if new_flags.empty?
    # フラグがなくなったら用語自体を削除
    existing.reject! { it['term'] == term_name }
  else
    term['flags'] = new_flags
  end

  save_terms!(existing)
end

#remove_term!(term_name) ⇒ Object

用語を削除

Parameters:

  • term_name (String)

    削除する用語名



118
119
120
121
122
123
124
125
126
# File 'lib/vivlio_starter/cli/index/unified_terms_manager.rb', line 118

def remove_term!(term_name)
  return if term_name.nil? || term_name.empty?

  existing = load_terms.dup
  original_size = existing.size
  existing.reject! { it['term'] == term_name }

  save_terms!(existing) if existing.size < original_size
end

#rename_chapter!(old_basename, new_basename) ⇒ Integer

章名の変更に辞書を追随させる(main: と scanned_chapters)。

main: は著者が下した判断=語彙の一次データなので、実在しない章を指していても 捨てられない。contexts はそもそも辞書に持たず(save_terms! を参照)、enrich が レビューのたびに本文から拾い直すので追随の対象にならない。 ここで書き換えるのは前者だけ。

Parameters:

  • old_basename (String)

    旧章名

  • new_basename (String)

    新章名

Returns:

  • (Integer)

    main: を書き換えた語数(0 なら書き換えなし)



241
242
243
244
245
246
247
248
# File 'lib/vivlio_starter/cli/index/unified_terms_manager.rb', line 241

def rename_chapter!(old_basename, new_basename)
  changed = rename_main_references(old_basename, new_basename)
  follow_scanned_chapters(old_basename, new_basename)
  return 0 if changed.zero?

  Common.log_info("索引辞書の主要参照を更新: #{old_basename}#{new_basename}#{changed} 語)")
  changed
end

#rename_main_references(old_basename, new_basename) ⇒ Object

main: の章名を差し替える。単一指定は単一のまま戻す(著者が書いた形を保つ)。



251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
# File 'lib/vivlio_starter/cli/index/unified_terms_manager.rb', line 251

def rename_main_references(old_basename, new_basename)
  terms = load_terms
  changed = 0

  terms.each do |term|
    next unless term['main']

    before = Array(term['main'])
    after = before.map { it == old_basename ? new_basename : it }
    next if after == before

    term['main'] = term['main'].is_a?(Array) ? after : after.first
    changed += 1
  end

  save_terms!(terms) if changed.positive?
  changed
end

#scanned_chaptersArray<String>?

index:auto が走査した章集合(辞書トップレベル) キーが無い旧辞書・辞書なしでは nil(呼び出し側は判定をスキップする)

Returns:

  • (Array<String>, nil)


208
209
210
211
212
213
214
215
# File 'lib/vivlio_starter/cli/index/unified_terms_manager.rb', line 208

def scanned_chapters
  return nil unless File.exist?(UNIFIED_FILE)

  data = YAML.load_file(UNIFIED_FILE, symbolize_names: false)
  data['scanned_chapters']
rescue StandardError
  nil
end

#term_namesObject

全用語名



69
# File 'lib/vivlio_starter/cli/index/unified_terms_manager.rb', line 69

def term_names = load_terms.map { it['term'] }

#update_definition!(term_name, definition) ⇒ Object

説明文を更新

Parameters:

  • term_name (String)

    用語名

  • definition (String)

    説明文



192
193
194
195
196
197
198
199
200
201
# File 'lib/vivlio_starter/cli/index/unified_terms_manager.rb', line 192

def update_definition!(term_name, definition)
  existing = load_terms.dup
  term = existing.find { it['term'] == term_name }
  return false unless term

  term['definition'] = definition
  term['updated_at'] = Time.now.strftime('%Y-%m-%d %H:%M:%S')
  save_terms!(existing)
  true
end

#update_flags!(term_name, new_flags) ⇒ Object

flags を更新

Parameters:

  • term_name (String)

    用語名

  • new_flags (String)

    新しい flags



157
158
159
160
161
162
163
164
# File 'lib/vivlio_starter/cli/index/unified_terms_manager.rb', line 157

def update_flags!(term_name, new_flags)
  existing = load_terms.dup
  term = existing.find { it['term'] == term_name }
  return unless term

  term['flags'] = new_flags
  save_terms!(existing)
end

#update_yomi!(yomi_changes) ⇒ Object

読みを更新

Parameters:

  • yomi_changes (Array<Hash>)

    読み変更のリスト



168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
# File 'lib/vivlio_starter/cli/index/unified_terms_manager.rb', line 168

def update_yomi!(yomi_changes)
  return if yomi_changes.nil? || yomi_changes.empty?

  existing = load_terms.dup
  updated_count = 0

  yomi_changes.each do |change|
    term = existing.find { it['term'] == change['term'] }
    next unless term
    next if term['yomi'] == change['yomi']

    term['yomi'] = change['yomi']
    updated_count += 1
  end

  return unless updated_count.positive?

  save_terms!(existing)
  Common.log_info("#{updated_count} 件の読みを更新しました")
end