Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions doc/markdown-samples/MARKUP_SPEC.md
Original file line number Diff line number Diff line change
Expand Up @@ -463,6 +463,15 @@ nth 番目の要素を返します。
存在し、X 以降には存在しない)ことを明示する。X は `"3.2"` のように数字と
ドットのみをダブルクォートで囲んで書く。シグネチャ見出しの横に
since/until バッジとして表示される
- `since=""`(空値)— 「初出バージョンは不明(少なくとも記録が残る最古の
バージョンより前から存在する)」ことを明示し、**バッジを表示しない**。
メソッド自体は昔からあるのにリファレンスへの記載が後から追加されたために、
自動算出(`bitclust methodsince`)が記載時期を初出として誤った版を
表示してしまう場合の抑止に使う(例: `Array#collect` は Ruby 1.8 以前から
存在するが、記載は 2.4.0 のドキュメント凍結後に追加されたため
「Ruby 2.5.0 から」と誤って算出される)。
別名(複数シグネチャ)のエントリで抑止する場合は、抑止したいすべての
シグネチャ見出しの直後にそれぞれ付けること。`until=""` も同様

規則:

Expand Down
11 changes: 8 additions & 3 deletions lib/bitclust/rrdparser.rb
Original file line number Diff line number Diff line change
Expand Up @@ -513,10 +513,14 @@ def define_method(chunk)
# - since="X"/until="X"(bitclust#132 P4): シグネチャ単位で束縛され、
# そのシグネチャの名前だけに適用される。nomethod/undef と違い、
# 別名ごとに異なる値を持てる(全シグネチャ一致は要求しない)のが
# 本来の用途。X は "3.2" のように数字とドットのみ
# 本来の用途。X は "3.2" のように数字とドットのみ。
# 空値(since="")は「明示的に不明」= バッジ非表示の指定で、メソッド
# 自体は昔からあるのにドキュメント追加が遅れ、バージョンラダーからの
# 自動算出が誤った版を出す場合の抑止に使う(空文字が記録されるため
# 算出値で上書きされず、表示側も空はバッジを出さない)
METHOD_ATTRIBUTES = %w[nomethod undef]
KV_METHOD_ATTRIBUTES = %w[since until]
KV_METHOD_ATTRIBUTE_VALUE_RE = /\A\d+(?:\.\d+)*\z/
KV_METHOD_ATTRIBUTE_VALUE_RE = /\A(?:\d+(?:\.\d+)*)?\z/

# md の `### def name ...`/`### module_function def name ...`/
# `### const name`/`### gvar $name` シグネチャ行を rd 形式
Expand Down Expand Up @@ -606,7 +610,8 @@ def parse_kv_method_attribute(token, chunk)
raise ParseError,
"#{chunk.source.location}: invalid method attribute #{token.inspect} " \
"(supported: #{METHOD_ATTRIBUTES.join(', ')}, " \
"#{KV_METHOD_ATTRIBUTES.map {|k| %Q(#{k}="X") }.join('/')} where X is digits and dots, e.g. since=\"3.2\")"
"#{KV_METHOD_ATTRIBUTES.map {|k| %Q(#{k}="X") }.join('/')} where X is digits and dots, e.g. since=\"3.2\", " \
"or empty for explicitly-unknown, e.g. since=\"\")"
end
private :parse_kv_method_attribute

Expand Down
3 changes: 2 additions & 1 deletion lib/bitclust/version_badges.rb
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,8 @@ def uniform_map?(entry, map)
end

def badge_span(version, css_class, catalog_key)
return nil unless version
# 空文字は「明示的に不明」({: since=""})= バッジ非表示(bitclust#132)
return nil if version.nil? || version.empty?
%Q(<span class="#{css_class}">#{escape_html(_(catalog_key, version))}</span>)
end

Expand Down
16 changes: 16 additions & 0 deletions test/test_method_since_calculator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,13 @@ class TestMethodSinceCalculator < Test::Unit::TestCase
説明
#@end

#@since 2.0.0
--- suppressed
{: since=""}

説明
#@end

#@since 2.0.0
--- -@
#@since 3.0
Expand Down Expand Up @@ -224,6 +231,15 @@ def test_author_since_attribute_parsed_from_source_survives_apply
assert_equal '2.5', find_entry('3.0', 'i', 'overridden').since_of('overridden')
end

def test_explicit_empty_since_suppresses_computed_value
# suppressed は #@since 2.0.0 ゲートによりラダー上は 2.0.0 と算出されるが、
# {: since=""}(明示的に不明=バッジ非表示)がパース時に記録されているため
# apply は上書きしない(bitclust#132: ドキュメント追加がメソッド追加より
# 遅れて算出が誤る場合の抑止)
run_calculator('3.0')
assert_equal '', find_entry('3.0', 'i', 'suppressed').since_of('suppressed')
end

def test_apply_rejects_target_whose_version_is_not_in_ladder
build_db('4.0')
calc = BitClust::MethodSinceCalculator.new(ladder_dbs)
Expand Down
40 changes: 40 additions & 0 deletions test/test_rdcompiler.rb
Original file line number Diff line number Diff line change
Expand Up @@ -621,6 +621,46 @@ def test_method_signature_since_badge_special_variable_alias
names: ['0', 'PROGRAM_NAME'], since_map: {'PROGRAM_NAME' => '1.9.1'})
end

# since_map の空文字値は「明示的に不明」(著者が {: since=""} で指定)。
# バッジは表示しない(bitclust#132: ドキュメント追加が遅れて算出が誤る場合の抑止)
def test_method_signature_empty_since_suppresses_badge
@c = ja_catalog_compiler
src = <<'HERE'
--- hoge
foo
HERE
expected = <<'HERE'
<dt class="method-heading" id="dummy"><code>hoge</code><span class="permalink">[<a href="dummy/method/String/i/index">permalink</a>][<a href="https://docs.ruby-lang.org/en/2.0.0/String.html#method-i-index">rdoc</a>]</span></dt>
<dd class="method-description">
<p>
foo
</p>
</dd>
HERE
assert_compiled_method_source(expected, src,
names: ['hoge'], since_map: {'hoge' => ''})
end

def test_method_signature_empty_since_mixed_alias
@c = ja_catalog_compiler
src = <<'HERE'
--- hoge1
--- hoge2
bar
HERE
expected = <<'HERE'
<dt class="method-heading" id="dummy"><code>hoge1</code><span class="permalink">[<a href="dummy/method/String/i/index">permalink</a>][<a href="https://docs.ruby-lang.org/en/2.0.0/String.html#method-i-index">rdoc</a>]</span></dt>
<dt class="method-heading"><code>hoge2</code><span class="method-since-badge">Ruby 2.0.0 から</span></dt>
<dd class="method-description">
<p>
bar
</p>
</dd>
HERE
assert_compiled_method_source(expected, src,
names: ['hoge1', 'hoge2'], since_map: {'hoge1' => '', 'hoge2' => '2.0.0'})
end

def test_ulist_simple
src = <<'HERE'
* hoge1
Expand Down
34 changes: 33 additions & 1 deletion test/test_rrdparser.rb
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,38 @@ def test_since_attribute_sets_since_of_name
assert_nil(entry.until_of('test_since'))
end

# {: since=""}(空値)は「明示的に不明」の指定(bitclust#132)。メソッド自体は
# 昔からあるのにドキュメント追加が遅れ、ラダー算出が誤った版を出す場合に
# バッジを抑止する(空文字が記録され、算出値で上書きされず、表示もされない)
def test_empty_since_attribute_means_explicitly_unknown
_library, db = BitClust::RRDParser.parse(<<HERE, 'dummy')
= module Dummy
== Instance Methods
--- test_unknown
{: since=""}

説明

HERE
entry = db.get_method(BitClust::MethodSpec.parse('Dummy#test_unknown'))
assert_equal('', entry.since_of('test_unknown'))
assert_nil(entry.until_of('test_unknown'))
end

def test_empty_until_attribute_is_also_accepted
_library, db = BitClust::RRDParser.parse(<<HERE, 'dummy')
= module Dummy
== Instance Methods
--- test_unknown_until
{: until=""}

説明

HERE
entry = db.get_method(BitClust::MethodSpec.parse('Dummy#test_unknown_until'))
assert_equal('', entry.until_of('test_unknown_until'))
end

def test_until_attribute_sets_until_of_name
_library, db = BitClust::RRDParser.parse(<<HERE, 'dummy')
= module Dummy
Expand Down Expand Up @@ -119,7 +151,7 @@ def test_since_attribute_on_special_variable_uses_entry_name
end

def test_malformed_since_attribute_is_rejected
['since=2.5', 'since=""', 'since="3,2"', 'since="abc"', 'foo="1"'].each do |token|
['since=2.5', 'since="3,2"', 'since="abc"', 'foo="1"'].each do |token|
assert_raise(BitClust::ParseError, token) do
BitClust::RRDParser.parse(<<HERE, 'dummy')
= module Dummy
Expand Down
Loading