Class: Vivlio::Starter::CLI::ReviewMarkdownGenerator

Inherits:
Object
  • Object
show all
Defined in:
lib/vivlio/starter/cli/index/review_markdown_generator.rb

Constant Summary collapse

REVIEW_FILE =

旧ファイル名との互換性のため、両方をチェック

'_index_glossary_review.md'
LEGACY_REVIEW_FILE =
'_index_review.md'

Instance Method Summary collapse

Constructor Details

#initializeReviewMarkdownGenerator

Returns a new instance of ReviewMarkdownGenerator.



39
40
41
42
# File 'lib/vivlio/starter/cli/index/review_markdown_generator.rb', line 39

def initialize
  @content = nil
  @config = load_index_config
end

Instance Method Details

#cleanup!Object

レビューファイルを削除



259
260
261
262
# File 'lib/vivlio/starter/cli/index/review_markdown_generator.rb', line 259

def cleanup!
  FileUtils.rm_f(REVIEW_FILE)
  FileUtils.rm_f(LEGACY_REVIEW_FILE)
end

#exists?Boolean

レビューファイルが存在するか

Returns:

  • (Boolean)


60
61
62
# File 'lib/vivlio/starter/cli/index/review_markdown_generator.rb', line 60

def exists?
  File.exist?(REVIEW_FILE) || File.exist?(LEGACY_REVIEW_FILE)
end

#generate!(data) ⇒ Object

レビュー用Markdownを生成

Parameters:

  • data (Hash)

    セクション別データ

    • :terms [Array<Hash>] 登録済み用語

    • :high_candidates [Array<Hash>] 推奨候補

    • :low_candidates [Array<Hash>] 一般候補

    • :rejected [Array<Hash>] 除外済みリスト



50
51
52
53
54
55
56
# File 'lib/vivlio/starter/cli/index/review_markdown_generator.rb', line 50

def generate!(data)
  content = build_markdown(data)
  File.write(REVIEW_FILE, content, encoding: 'utf-8')
  Common.log_success("レビュー用ファイルを生成しました: #{REVIEW_FILE}")
  Common.log_info('ファイルを開いて [ ] を [x] または [r] に変更してください')
  Common.log_info('完了したら: vs index:apply')
end

#parse_approvedArray<Hash>

後方互換性のため parse_approved も維持(索引用)

Returns:

  • (Array<Hash>)

    承認済み候補のリスト



117
118
119
# File 'lib/vivlio/starter/cli/index/review_markdown_generator.rb', line 117

def parse_approved
  parse_index_approved
end

#parse_glossary_approvedArray<Hash>

用語集として承認された候補を抽出(, [ig], [gi] マーク)説明文も抽出する

Returns:

  • (Array<Hash>)

    用語集候補のリスト(definition 付き)



93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
# File 'lib/vivlio/starter/cli/index/review_markdown_generator.rb', line 93

def parse_glossary_approved
  return [] unless exists?

  content = File.read(review_file_path, encoding: 'utf-8')
  approved = []

  # [g], [ig], [gi] を用語集として抽出
  parse_terms_with_definitions(content).each do |entry|
    flag = entry[:flag]
    next unless flag.match?(/^(?:g|ig|gi)$/)

    approved << {
      'term' => entry[:term],
      'yomi' => entry[:yomi],
      'definition' => entry[:definition],
      'contexts' => entry[:contexts]
    }
  end

  approved
end

#parse_glossary_rejectedArray<Hash>

用語集のみリジェクト(マーク)を抽出

Returns:

  • (Array<Hash>)

    用語集リジェクト候補のリスト



169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
# File 'lib/vivlio/starter/cli/index/review_markdown_generator.rb', line 169

def parse_glossary_rejected
  return [] unless exists?

  content = File.read(review_file_path, encoding: 'utf-8')
  rejected = []

  rejected_section_start = content.index('## 4. 除外済みリスト')
  search_content = rejected_section_start ? content[0...rejected_section_start] : content

  search_content.scan(/^- \[-g\](?: `(?:NEW!|Today)`)? \*\*(.+?)\*\* \(([^)]+)\)/) do |term, yomi|
    rejected << { 'term' => term, 'yomi' => yomi, 'kind' => 'glossary' }
  end

  rejected
end

#parse_index_approvedArray<Hash>

索引として承認された候補を抽出(, [ig], [gi], [x] マーク)

Returns:

  • (Array<Hash>)

    索引候補のリスト



75
76
77
78
79
80
81
82
83
84
85
86
87
88
# File 'lib/vivlio/starter/cli/index/review_markdown_generator.rb', line 75

def parse_index_approved
  return [] unless exists?

  content = File.read(review_file_path, encoding: 'utf-8')
  approved = []

  # [i], [ig], [gi], [x] を索引として抽出
  # 形式: - [i] `NEW!` **用語** (読み) - スコア: 123.5
  content.scan(/^- \[(?:i|ig|gi|x)\](?: `(?:NEW!|Today)`)? \*\*(.+?)\*\* \(([^)]+)\)/) do |term, yomi|
    approved << { 'term' => term, 'yomi' => yomi }
  end

  approved
end

#parse_index_rejectedArray<Hash>

索引のみリジェクト(マーク)を抽出

Returns:

  • (Array<Hash>)

    索引リジェクト候補のリスト



151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
# File 'lib/vivlio/starter/cli/index/review_markdown_generator.rb', line 151

def parse_index_rejected
  return [] unless exists?

  content = File.read(review_file_path, encoding: 'utf-8')
  rejected = []

  rejected_section_start = content.index('## 4. 除外済みリスト')
  search_content = rejected_section_start ? content[0...rejected_section_start] : content

  search_content.scan(/^- \[-i\](?: `(?:NEW!|Today)`)? \*\*(.+?)\*\* \(([^)]+)\)/) do |term, yomi|
    rejected << { 'term' => term, 'yomi' => yomi, 'kind' => 'index' }
  end

  rejected
end

#parse_rejectedArray<Hash>

Returns:

  • (Array<Hash>)

    リジェクト候補のリスト



123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
# File 'lib/vivlio/starter/cli/index/review_markdown_generator.rb', line 123

def parse_rejected
  return [] unless exists?

  content = File.read(review_file_path, encoding: 'utf-8')
  rejected = []

  # Rejectedセクション以外から [r] マークを抽出
  # Rejectedセクションの開始位置を特定
  rejected_section_start = content.index('## 4. 除外済みリスト')

  search_content = if rejected_section_start
                     content[0...rejected_section_start]
                   else
                     content
                   end

  # [r], [-ig], [-gi] を両方リジェクトとして抽出
  search_content.scan(/^- \[(?:r|-ig|-gi)\](?: `(?:NEW!|Today)`)? \*\*(.+?)\*\* \(([^)]+)\)(?: - スコア: ([\d.]+))?/) do |term, yomi, score|
    entry = { 'term' => term, 'yomi' => yomi, 'kind' => 'both' }
    entry['score'] = score.to_f if score
    rejected << entry
  end

  rejected
end

#parse_rejected_section_allArray<Hash>

Rejectedセクションの全項目を抽出(フラグ不問)Section 4 に存在する全用語を返す([ ], [i], [g], [ig] 等すべて)apply 時に index_terms/glossary_terms からの除去と rejected への同期に使用

Returns:

  • (Array<Hash>)

    全項目のリスト(flag 付き)



213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
# File 'lib/vivlio/starter/cli/index/review_markdown_generator.rb', line 213

def parse_rejected_section_all
  return [] unless exists?

  content = File.read(review_file_path, encoding: 'utf-8')
  items = []

  rejected_section_start = content.index('## 4. 除外済みリスト')
  return [] unless rejected_section_start

  rejected_content = content[rejected_section_start..]

  # フラグ部分を含めて全項目を抽出
  # [ ], [i], [g], [ig], [gi], [x], [r] 等すべてのフラグを対象
  rejected_content.scan(/^- \[([^\]]*)\](?: `(?:NEW!|Today)`)? \*\*(.+?)\*\* \(([^)]+)\)/) do |flag, term, yomi|
    items << { 'term' => term, 'yomi' => yomi, 'flag' => flag.strip }
  end

  items
end

#parse_terms_with_definitions(content) ⇒ Array<Hash>

用語と説明文をパース出現箇所リストと説明文を区別して抽出

Parameters:

  • content (String)

    Markdown内容

Returns:

  • (Array<Hash>)

    パース結果



268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
# File 'lib/vivlio/starter/cli/index/review_markdown_generator.rb', line 268

def parse_terms_with_definitions(content)
  results = []
  lines = content.lines
  i = 0

  while i < lines.size
    line = lines[i]

    # 用語行を検出: - [flag] **用語** (読み) - スコア: 123.5
    if line =~ /^- \[([^\]]+)\](?: `(?:NEW!|Today)`)? \*\*(.+?)\*\* \(([^)]+)\)/
      flag = Regexp.last_match(1)
      term = Regexp.last_match(2)
      yomi = Regexp.last_match(3)

      i += 1
      contexts = []
      definition_lines = []
      in_definition = false

      # 次の用語行まで走査
      while i < lines.size && lines[i] !~ /^- \[/
        current_line = lines[i]

        # 出現箇所行: "  - chapter: context"
        if current_line =~ /^  - ([^:]+): (.+)/
          chapter = Regexp.last_match(1)
          context_text = Regexp.last_match(2)
          contexts << { 'chapter' => chapter, 'context' => context_text }
          i += 1
          next
        end

        # 空行で説明文開始を判定
        if current_line.strip.empty?
          in_definition = true
          i += 1
          next
        end

        # インデントされた行は説明文
        definition_lines << Regexp.last_match(1) if in_definition && current_line =~ /^  (.+)/

        i += 1
      end

      results << {
        flag: flag,
        term: term,
        yomi: yomi,
        contexts: contexts,
        definition: definition_lines.join("\n").strip
      }
    else
      i += 1
    end
  end

  results
end

#parse_unrejectArray<Hash>

Rejectedセクションで解除マークされた候補を抽出(リジェクト解除 + 直接登録)フラグに基づいて索引・用語集に直接登録する

Returns:

  • (Array<Hash>)

    リジェクト解除候補のリスト(flag 付き)



188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
# File 'lib/vivlio/starter/cli/index/review_markdown_generator.rb', line 188

def parse_unreject
  return [] unless exists?

  content = File.read(review_file_path, encoding: 'utf-8')
  unreject = []

  # Rejectedセクションを特定
  rejected_section_start = content.index('## 4. 除外済みリスト')
  return [] unless rejected_section_start

  rejected_content = content[rejected_section_start..]

  # Rejectedセクション内で [i], [g], [ig] マークされたものを抽出
  # フラグも保持し、索引・用語集への直接登録に使用する
  rejected_content.scan(/^- \[(i|g|ig|gi|x)\](?: `(?:NEW!|Today)`)? \*\*(.+?)\*\* \(([^)]+)\)/) do |flag, term, yomi|
    unreject << { 'term' => term, 'yomi' => yomi, 'flag' => flag }
  end

  unreject
end

#parse_yomi_changesArray<Hash>

Termsセクションで読みが変更された用語を抽出

Returns:

  • (Array<Hash>)

    読み変更された用語のリスト



235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
# File 'lib/vivlio/starter/cli/index/review_markdown_generator.rb', line 235

def parse_yomi_changes
  return [] unless exists?

  content = File.read(review_file_path, encoding: 'utf-8')
  changes = []

  # Termsセクションを特定
  terms_section_start = content.index('## 1. 登録済み用語の確認')
  high_section_start = content.index('## 2. 推奨候補')

  return [] unless terms_section_start

  terms_end = high_section_start || content.length
  terms_content = content[terms_section_start...terms_end]

  # [i], [g], [ig], [x] マークされた用語の読みを抽出
  terms_content.scan(/^- \[(?:i|g|ig|gi|x)\](?: `(?:NEW!|Today)`)? \*\*(.+?)\*\* \(([^)]+)\)/) do |term, yomi|
    changes << { 'term' => term, 'yomi' => yomi }
  end

  changes
end

#review_file_pathString

実際のレビューファイルパスを取得

Returns:

  • (String)


66
67
68
69
70
71
# File 'lib/vivlio/starter/cli/index/review_markdown_generator.rb', line 66

def review_file_path
  return REVIEW_FILE if File.exist?(REVIEW_FILE)
  return LEGACY_REVIEW_FILE if File.exist?(LEGACY_REVIEW_FILE)

  REVIEW_FILE
end