From eaba7c661436e0455f178bb2be9f97d327b3d09c Mon Sep 17 00:00:00 2001 From: Kazuhiro NISHIYAMA Date: Thu, 23 Jul 2026 09:10:53 +0900 Subject: [PATCH] =?UTF-8?q?[m:]=20=E5=8F=82=E7=85=A7=E3=81=AE=E3=83=87?= =?UTF-8?q?=E3=83=95=E3=82=A9=E3=83=AB=E3=83=88=E3=83=A9=E3=83=99=E3=83=AB?= =?UTF-8?q?=E3=82=92=204.0=20=E4=BB=A5=E9=99=8D=E3=81=AF=20=3F.=20?= =?UTF-8?q?=E8=A1=A8=E7=A4=BA=E3=81=AB=E3=81=99=E3=82=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit fix #282 [[m:...]] のデフォルトラベル(参照の記載文字列)が module function で 常に ".#" のまま表示され、#277 で "?." 化した見出しと 4.0 以降の ページ内で表記が混在していた。Markdown ソースに [m:Kernel?.x] と 書いても markdown_to_rrd の convert_md_ref_to_rrd が MethodSpec 互換の ため ".#" へ正規化するので、記載表記に依らず発生する。 choke point は RDCompiler#bracket_link の 'm' 分岐1箇所(MDCompiler の インライン参照も restore_inline 経由でここに合流する)。デフォルト ラベルを新設の display_spec で畳む: spec が ".#" を含む場合のみ、DB の version が 4.0 以上なら NameUtils.display_typemark で "?." に置換 (#250/#277 と同じ選択規則)。spec・URL・アンカーキーは不変、明示 ラベルには触れない。reference_link の「spec/見出し」ラベルの spec 側 (現 doctree に用例の無い理論エッジ)も同じ規則で畳む。 テスト: rd の版別ラベル(3.4/4.0/4.1)・他 typemark とスペシャル変数の 不変・ref:m: の見出し連結、md の [m:Kernel?.x]/[m:Kernel.#x] 両表記 (3.4/4.0)。全テスト 17805 件・steep・JS テスト green。ミニ markdowntree の実描画で 3.4=".#"・4.0="?." と URL 不変を確認。 Co-Authored-By: Claude Fable 5 --- lib/bitclust/rdcompiler.rb | 19 ++++++++++++++++-- sig/bitclust/rdcompiler.rbs | 2 ++ test/test_mdcompiler.rb | 17 ++++++++++++++++ test/test_rdcompiler.rb | 39 +++++++++++++++++++++++++++++++++++++ 4 files changed, 75 insertions(+), 2 deletions(-) diff --git a/lib/bitclust/rdcompiler.rb b/lib/bitclust/rdcompiler.rb index 23a070f..0b88930 100644 --- a/lib/bitclust/rdcompiler.rb +++ b/lib/bitclust/rdcompiler.rb @@ -500,7 +500,7 @@ def bracket_link(link, label = nil, frag = nil) when 'c' protect(link) { class_link(arg, label, frag) } when 'm' - protect(link) { method_link(complete_spec(arg), label || arg, frag) } + protect(link) { method_link(complete_spec(arg), label || display_spec(arg), frag) } when 'f' protect(link) { case arg @@ -554,7 +554,9 @@ def reference_link(arg) when 'c' title, t, id = name, ClassEntry.type_id.to_s, name when 'm' - title, t, id = name, MethodEntry.type_id.to_s, name + # 表示側(title)のみ display_spec で畳む。id は refs テーブルの + # キーなので記載どおり(bitclust#282) + title, t, id = display_spec(name), MethodEntry.type_id.to_s, name when 'd' title, t, id = @option[:database].get_doc(name).title, DocEntry.type_id.to_s, name else @@ -654,6 +656,19 @@ def complete_spec(spec0) end end + # bitclust#282: [[m:...]] のデフォルトラベル(参照の記載文字列)は表示 + # 専用なので、module function の ".#" は DB バージョンが 4.0 以降なら + # "?." で表示する(#250/#277 の display_typemark と同じ選択規則。 + # Markdown ソースの [m:Kernel?.x] も inline 復元時に ".#" へ正規化されて + # ここに来るため、どちらの表記で書かれていても見出し表記と一致する)。 + # spec・URL・アンカーキーは不変。明示ラベル(label 引数)には触れない + def display_spec(spec) + return spec unless spec.include?('.#') + db = @option[:database] + version = db ? db.propget('version') : nil + spec.sub('.#', NameUtils.display_typemark('.#', version)) + end + def seems_code(text) # FIXME escape_html(text) diff --git a/sig/bitclust/rdcompiler.rbs b/sig/bitclust/rdcompiler.rbs index fde70e7..45357d7 100644 --- a/sig/bitclust/rdcompiler.rbs +++ b/sig/bitclust/rdcompiler.rbs @@ -168,6 +168,8 @@ module BitClust def complete_spec: (String spec0) -> String + def display_spec: (String spec) -> String + def seems_code: (String text) -> String def string: (String str) -> void diff --git a/test/test_mdcompiler.rb b/test/test_mdcompiler.rb index c89a6c9..c68ddf5 100644 --- a/test/test_mdcompiler.rb +++ b/test/test_mdcompiler.rb @@ -1014,6 +1014,23 @@ def test_no_warning_for_fenced_code_block err = capture_stderr { @md.compile("```ruby\n x = 1\n```\n") } assert_equal('', err) end + + def test_md_ref_module_function_display_typemark + # bitclust#282: Markdown ソースの [m:Kernel?.at_exit] は inline 復元時に + # ".#" へ正規化される(RRD の MethodSpec 互換)が、表示ラベルは DB + # バージョンが 4.0 以降なら "?." に戻す。3.4 以前は ".#" のまま。 + # どちらの表記で書かれていても、ページの見出し表記と常に一致する + src = "### def m(v) -> String\n\n" \ + "[m:Kernel?.at_exit] と [m:Kernel.#at_exit] を参照。\n" + { '3.4' => 'Kernel.#at_exit', '4.0' => 'Kernel?.at_exit' }.each do |version, label| + db = BitClust::MethodDatabase.dummy("version" => version) + md = BitClust::MDCompiler.new(@u, 1, { :database => db }) + html = compile_method(md, src) + assert_equal(2, html.scan(">#{label}").size, + "version=#{version}\n#{html}") + end + end + end # lang 指定付きコードブロックのハイライト(ruby は Ripper ベースの diff --git a/test/test_rdcompiler.rb b/test/test_rdcompiler.rb index ae074c6..17b462f 100644 --- a/test/test_rdcompiler.rb +++ b/test/test_rdcompiler.rb @@ -938,6 +938,45 @@ def test_bracket_link(data) assert_equal(expected, @c.send(:compile_text, target), target) end + # bitclust#282: 参照のデフォルトラベル(記載どおりの spec 文字列)も + # 表示専用なので、module function の ".#" は DB バージョンが 4.0 以降 + # なら "?." で表示する(#250/#277 の display_typemark と同じ選択規則)。 + # URL・アンカー(識別子)は変えない。 + data("pre-4.0 keeps .#" => ['3.4', 'Kernel.#at_exit'], + "4.0 shows ?." => ['4.0', 'Kernel?.at_exit'], + "4.1 shows ?." => ['4.1', 'Kernel?.at_exit']) + def test_bracket_link_module_function_display(data) + version, label = data + db = BitClust::MethodDatabase.dummy("version" => version) + c = BitClust::RDCompiler.new(@u, 1, {:database => db}) + assert_equal(%Q(#{label}), + c.send(:compile_text, '[[m:Kernel.#at_exit]]')) + end + + def test_reference_link_module_function_title_display + # refs テーブルに見出しがある場合の「spec/見出し」ラベルの spec 側も + # 4.0 以降は "?." 表示にする(doctree に現時点で用例は無い理論エッジ + # だが、デフォルトラベルと同じ選択規則で一貫させる) + refs = Object.new + def refs.[](type, id, frag) = '深掘り' + db = BitClust::MethodDatabase.dummy("version" => "4.0") + stub(db).refs { refs } + c = BitClust::RDCompiler.new(@u, 1, {:database => db}) + assert_equal(%Q(Kernel?.at_exit/深掘り), + c.send(:compile_text, '[[ref:m:Kernel.#at_exit#frag]]')) + end + + def test_bracket_link_other_typemarks_unchanged_at_4_0 + db = BitClust::MethodDatabase.dummy("version" => "4.0") + c = BitClust::RDCompiler.new(@u, 1, {:database => db}) + assert_equal('String.new', + c.send(:compile_text, '[[m:String.new]]')) + assert_equal('String#dump', + c.send(:compile_text, '[[m:String#dump]]')) + assert_equal('$~', + c.send(:compile_text, '[[m:$~]]')) + end + data("library root" => ['[[lib:/]]', 'ライブラリ一覧'], "builtin library" => ['[[lib:_builtin]]', '組み込みライブラリ'], "C API root" => ['[[f:/]]', '関数一覧'])