Class: VivlioStarter::CLI::Metrics::Formatter
- Inherits:
-
Object
- Object
- VivlioStarter::CLI::Metrics::Formatter
- Defined in:
- lib/vivlio_starter/cli/metrics/formatter.rb
Overview
メトリクス出力フォーマッタ
Constant Summary collapse
- BAR_WIDTH =
12- BAR_CHAR =
'#'- BAR_EMPTY_CHAR =
'.'- CHAPTER_LABEL_WIDTH =
30- SECTION_LABEL_WIDTH =
36- ELLIPSIS =
切り詰めを示す記号。
'…'- AMBIGUOUS_WIDTH_CHARS =
非 ASCII だが端末では 1 幅で描かれる記号(East Asian Width = Ambiguous)。
fullwidth_char?は「ASCII でなければ全角」という粗い判定なので、 ここを通さないと 2 桁と数えて桁がずれる。EAW=A を 1 幅と見なすのはterminal-output-notes.md§1 の方針(矢印などは端末で 1 幅が期待値)に合わせたもの。 %w[… → ← ↑ ↓ ⋯ ±].freeze
- CHAR_COUNT_WIDTH =
6- MATTR_MONOTONOUS_MAX =
「表現が単調」と評価する MATTR の上限(この値以下が単調帯)。 詳細分析の表示(#mattr_evaluation)と章別リストの品質警告 (WarningChecker#quality_warnings)が同じ値を参照することで、 「詳細では単調と出るのに警告は出ない」という乖離を構造的に防ぐ。
0.5- SNIPPET_LIMIT =
24- KANJI_LIST_TOP =
15- RHYTHM_RUN_LIMIT =
5
Instance Method Summary collapse
-
#format_basic_info(basic, vocab) ⇒ Object
基本情報セクションを生成する。 主役は本文で、コードと記法は外数としてカッコ内に添える (
chapter-volume-calibration-data.md§7.1)。文章が主でコード・記法は従、 という位置づけによる。本文は語彙分析の分母と同じ値なので vocab から採る。. -
#format_chapter_count_summary(count, total_chars) ⇒ Object
章別リスト直後の集計行(合計章数・平均文字数)を生成する。.
-
#format_chapter_line(chapter, max_chars, show_sections, extra_warnings: [], excluded: false) ⇒ Object
章行をフォーマットする(公開メソッド)。 extra_warnings は分量以外の指摘(文章の質)。分量とは算出タイミングが異なり 章構造体に入っていないため、ここで受け取って 1 行に組み立てる (metrics-quality-warnings-spec.md §2.2)。記号は系統ごとに分ける。 excluded は分量判定の対象外の章(前書き・付録・後書き)。✅ も出さない。.
-
#format_consistency(metrics) ⇒ Object
章間のばらつきセクションを生成する。高め/低めは別行(二段)で示す。.
-
#format_content_words(words) ⇒ Object
頻出内容語セクションを生成する。語・品詞は表示幅(全角=2)でそろえる。.
-
#format_detailed_analysis(vocab, readability) ⇒ Object
詳細分析セクションを生成する.
-
#format_kanji_levels(report) ⇒ Object
漢字レベル(ルビ候補)セクションを生成する。.
-
#format_long_sentences(sentences) ⇒ Object
「見直したい長い文」セクションを生成する。 章番号・行番号・字数は右詰めで桁をそろえ、縦に位置が揃うようにする。.
-
#format_sentence_rhythm(distribution, runs) ⇒ Object
文末表現のリズムセクションを生成する。連続箇所は 1 件ずつ別行で示す。.
-
#format_sentence_structure(basic) ⇒ Object
文構造セクションを生成する.
-
#initialize(config_loader) ⇒ Formatter
constructor
A new instance of Formatter.
Constructor Details
#initialize(config_loader) ⇒ Formatter
Returns a new instance of Formatter.
41 42 43 44 45 |
# File 'lib/vivlio_starter/cli/metrics/formatter.rb', line 41 def initialize(config_loader) @config = config_loader @vocabulary = config_loader.vocabulary_thresholds @labels = config_loader.labels end |
Instance Method Details
#format_basic_info(basic, vocab) ⇒ Object
基本情報セクションを生成する。
主役は本文で、コードと記法は外数としてカッコ内に添える
(chapter-volume-calibration-data.md §7.1)。文章が主でコード・記法は従、
という位置づけによる。本文は語彙分析の分母と同じ値なので vocab から採る。
57 58 59 60 61 62 63 |
# File 'lib/vivlio_starter/cli/metrics/formatter.rb', line 57 def format_basic_info(basic, vocab) <<~OUTPUT.chomp 📊 文章統計 — 基本情報 - 文字数: #{number_with_comma(vocab.total_char_count)} 文字#{char_breakdown(basic)} - 行数: #{number_with_comma(basic.lines)} 行 OUTPUT end |
#format_chapter_count_summary(count, total_chars) ⇒ Object
章別リスト直後の集計行(合計章数・平均文字数)を生成する。
48 49 50 51 |
# File 'lib/vivlio_starter/cli/metrics/formatter.rb', line 48 def format_chapter_count_summary(count, total_chars) avg = count.positive? ? (total_chars.to_f / count).round : 0 "📚 合計 #{count} 章 / 平均 #{number_with_comma(avg)} 文字" end |
#format_chapter_line(chapter, max_chars, show_sections, extra_warnings: [], excluded: false) ⇒ Object
章行をフォーマットする(公開メソッド)。 extra_warnings は分量以外の指摘(文章の質)。分量とは算出タイミングが異なり 章構造体に入っていないため、ここで受け取って 1 行に組み立てる (metrics-quality-warnings-spec.md §2.2)。記号は系統ごとに分ける。 excluded は分量判定の対象外の章(前書き・付録・後書き)。✅ も出さない。
169 170 171 172 173 174 175 176 177 178 179 180 181 |
# File 'lib/vivlio_starter/cli/metrics/formatter.rb', line 169 def format_chapter_line(chapter, max_chars, show_sections, extra_warnings: [], excluded: false) = (chapter.chars, max_chars) warning = format_advice(chapter.warning, extra_warnings, just_right: just_right?(chapter.chars, thresholds[:chapter], excluded:)) if show_sections && chapter.sections.any? format_chapter_with_sections(chapter, , warning, max_chars, excluded:) else label = padded_label(chapter_label(chapter)) char_count = format_char_count(chapter.chars) "#{label} #{} #{char_count}#{warning}" end end |
#format_consistency(metrics) ⇒ Object
章間のばらつきセクションを生成する。高め/低めは別行(二段)で示す。
154 155 156 157 158 159 160 161 162 |
# File 'lib/vivlio_starter/cli/metrics/formatter.rb', line 154 def format_consistency(metrics) lines = ['📐 章間のばらつき(本文の章のみ)', ''] metrics.each do |m| lines << "- #{m.label}: 平均 #{format_metric_value(m.mean, m.unit)} / ばらつき ±#{m.stdev.round(1)}" lines << " #{m.high_label}: #{format_outliers(m.high, m.unit)}" lines << " #{m.low_label}: #{format_outliers(m.low, m.unit)}" end lines.join("\n") end |
#format_content_words(words) ⇒ Object
頻出内容語セクションを生成する。語・品詞は表示幅(全角=2)でそろえる。
130 131 132 133 134 135 136 137 138 139 140 141 |
# File 'lib/vivlio_starter/cli/metrics/formatter.rb', line 130 def format_content_words(words) word_w = words.map { display_width(it.word) }.max pos_w = words.map { display_width(it.pos) }.max count_w = words.map { it.count.to_s.length }.max lines = ["🔤 よく使う言葉(内容語 上位#{words.size})", ''] words.each_with_index do |w, index| rank = (index + 1).to_s.rjust(2) lines << "#{rank}. #{pad_to_width(w.word, word_w)} #{pad_to_width(w.pos, pos_w)} #{w.count.to_s.rjust(count_w)}回" end lines.join("\n") end |
#format_detailed_analysis(vocab, readability) ⇒ Object
詳細分析セクションを生成する
76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 |
# File 'lib/vivlio_starter/cli/metrics/formatter.rb', line 76 def format_detailed_analysis(vocab, readability) kanji = @vocabulary[:kanji_ratio] word = @vocabulary[:word_length] <<~OUTPUT.chomp 📈 詳細分析 【語彙難度】 - 漢字比率: #{difficulty_evaluation(vocab.kanji_ratio, kanji)}(#{vocab.kanji_ratio.round(1)}%) — 理想的な範囲 #{kanji[:ideal_min]}〜#{kanji[:ideal_max]}% - 平均語長: #{difficulty_evaluation(vocab.avg_word_length, word)}(#{vocab.avg_word_length.round(1)} 文字) — 理想的な範囲 #{word[:ideal_min]}〜#{word[:ideal_max]} 文字 - 文字種構成: #{character_composition(vocab)} 【語彙多様度】 - 使用語彙数: #{number_with_comma(vocab.unique_tokens)} 語(異なり語)/ 総語数 #{number_with_comma(vocab.total_tokens)} 語 - 語彙の豊かさ: #{mattr_evaluation(vocab.mattr)}(MATTR: #{vocab.mattr.round(2)}) - 評価基準: 0.7 以上=非常に豊富、0.6〜0.7=豊富、0.5〜0.6=標準的、0.5 未満=単調 【読解難度】 - 評価: #{readability.label}(#{readability_description(readability.label)}) - スコア: #{readability.score.round(1)} 点 OUTPUT end |
#format_kanji_levels(report) ⇒ Object
漢字レベル(ルビ候補)セクションを生成する。
118 119 120 121 122 123 124 125 126 127 |
# File 'lib/vivlio_starter/cli/metrics/formatter.rb', line 118 def format_kanji_levels(report) lines = ['🈂 漢字レベル(ルビ候補)', ''] lines << "- レベル内訳: #{report.ratios.map { |label, pct| "#{label} #{pct}%" }.join(' / ')}" KanjiLevels::LIST_LABELS.each do |key, title| list = report.lists[key] lines << kanji_list_line(title, list) unless list.empty? end lines.concat(kanji_location_lines(report.locations)) lines.join("\n") end |
#format_long_sentences(sentences) ⇒ Object
「見直したい長い文」セクションを生成する。 章番号・行番号・字数は右詰めで桁をそろえ、縦に位置が揃うようにする。
102 103 104 105 106 107 108 109 110 111 112 113 |
# File 'lib/vivlio_starter/cli/metrics/formatter.rb', line 102 def format_long_sentences(sentences) num_w = column_width(sentences, &:chapter_num) line_w = column_width(sentences, &:line) len_w = column_width(sentences, &:length) lines = ["📝 見直したい長い文(ワースト#{sentences.size})", ''] sentences.each_with_index do |s, index| location = "第#{s.chapter_num.to_s.rjust(num_w)}章 L#{s.line.to_s.rjust(line_w)}(#{s.length.to_s.rjust(len_w)}字)" lines << "#{index + 1}. #{location}: #{snippet(s.text)}" end lines.join("\n") end |
#format_sentence_rhythm(distribution, runs) ⇒ Object
文末表現のリズムセクションを生成する。連続箇所は 1 件ずつ別行で示す。
146 147 148 149 150 151 |
# File 'lib/vivlio_starter/cli/metrics/formatter.rb', line 146 def format_sentence_rhythm(distribution, runs) lines = ['🎶 文末表現のリズム', ''] lines << "- 文末の内訳: #{distribution.map { |category, pct| "#{category} #{pct}%" }.join('/')}" lines << format_monotone_runs(runs) lines.join("\n") end |
#format_sentence_structure(basic) ⇒ Object
文構造セクションを生成する
66 67 68 69 70 71 72 73 |
# File 'lib/vivlio_starter/cli/metrics/formatter.rb', line 66 def format_sentence_structure(basic) <<~OUTPUT.chomp 📊 文章統計 — 文構造 - 文の数: #{basic.sentences} 文(平均 #{basic.avg_sentence_len.round(1)} 文字/文) - 節の数: #{basic.clauses} 節(平均 #{basic.avg_clause_len.round(1)} 文字/節) - 読点数: #{basic.commas} 個 OUTPUT end |