bitclust-core 1.3.0 → 1.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/Gemfile +3 -0
- data/README.md +65 -0
- data/Rakefile +32 -0
- data/data/bitclust/catalog/ja_JP.UTF-8 +19 -1
- data/data/bitclust/searchpage/index.html +90 -0
- data/data/bitclust/template/class +69 -8
- data/data/bitclust/template/function +2 -2
- data/data/bitclust/template/layout +11 -3
- data/data/bitclust/template/method +2 -2
- data/data/bitclust/template/search +1 -1
- data/data/bitclust/template.epub/class +22 -1
- data/data/bitclust/template.epub/function +2 -2
- data/data/bitclust/template.epub/layout +1 -3
- data/data/bitclust/template.epub/method +2 -2
- data/data/bitclust/template.lillia/class +26 -5
- data/data/bitclust/template.lillia/layout +1 -3
- data/data/bitclust/template.lillia/method +2 -2
- data/data/bitclust/template.offline/class +48 -4
- data/data/bitclust/template.offline/function +2 -2
- data/data/bitclust/template.offline/layout +27 -3
- data/data/bitclust/template.offline/method +2 -2
- data/lib/bitclust/app.rb +16 -17
- data/lib/bitclust/capi_converter.rb +20 -0
- data/lib/bitclust/classentry.rb +67 -17
- data/lib/bitclust/compat.rb +2 -2
- data/lib/bitclust/completion.rb +58 -27
- data/lib/bitclust/crossrubyutils.rb +8 -5
- data/lib/bitclust/database.rb +28 -8
- data/lib/bitclust/doc_converter.rb +63 -0
- data/lib/bitclust/docentry.rb +1 -1
- data/lib/bitclust/entity_splitter.rb +221 -0
- data/lib/bitclust/entry.rb +47 -7
- data/lib/bitclust/functiondatabase.rb +13 -1
- data/lib/bitclust/functionentry.rb +5 -1
- data/lib/bitclust/functionreferenceparser.rb +4 -4
- data/lib/bitclust/generators/epub.rb +10 -3
- data/lib/bitclust/htmlutils.rb +1 -1
- data/lib/bitclust/include_graph.rb +375 -0
- data/lib/bitclust/include_pruner.rb +144 -0
- data/lib/bitclust/interface.rb +1 -1
- data/lib/bitclust/libraryentry.rb +8 -7
- data/lib/bitclust/lineinput.rb +7 -5
- data/lib/bitclust/link_checker.rb +179 -0
- data/lib/bitclust/markdown_bridge.rb +186 -0
- data/lib/bitclust/markdown_orchestrator.rb +267 -0
- data/lib/bitclust/markdown_to_rrd.rb +824 -0
- data/lib/bitclust/markdown_tree.rb +217 -0
- data/lib/bitclust/mdcompiler.rb +883 -0
- data/lib/bitclust/mdparser.rb +347 -0
- data/lib/bitclust/messagecatalog.rb +3 -3
- data/lib/bitclust/method_since_calculator.rb +117 -0
- data/lib/bitclust/methoddatabase.rb +124 -14
- data/lib/bitclust/methodentry.rb +125 -7
- data/lib/bitclust/methodid.rb +12 -11
- data/lib/bitclust/methodsignature.rb +10 -4
- data/lib/bitclust/nameutils.rb +41 -22
- data/lib/bitclust/preprocessor.rb +66 -29
- data/lib/bitclust/rdcompiler.rb +195 -95
- data/lib/bitclust/refsdatabase.rb +23 -8
- data/lib/bitclust/reloadable_request_handler.rb +72 -0
- data/lib/bitclust/requesthandler.rb +21 -16
- data/lib/bitclust/ridatabase.rb +10 -4
- data/lib/bitclust/rrd_to_markdown.rb +925 -0
- data/lib/bitclust/rrdparser.rb +196 -30
- data/lib/bitclust/runner.rb +17 -2
- data/lib/bitclust/screen.rb +80 -11
- data/lib/bitclust/search_index_generator.rb +288 -0
- data/lib/bitclust/searcher.rb +69 -20
- data/lib/bitclust/simplesearcher.rb +24 -12
- data/lib/bitclust/subcommand.rb +7 -1
- data/lib/bitclust/subcommands/ancestors_command.rb +9 -2
- data/lib/bitclust/subcommands/checklink_command.rb +54 -0
- data/lib/bitclust/subcommands/chm_command.rb +15 -7
- data/lib/bitclust/subcommands/classes_command.rb +5 -0
- data/lib/bitclust/subcommands/extract_command.rb +5 -0
- data/lib/bitclust/subcommands/htmlfile_command.rb +21 -7
- data/lib/bitclust/subcommands/init_command.rb +4 -1
- data/lib/bitclust/subcommands/list_command.rb +12 -4
- data/lib/bitclust/subcommands/lookup_command.rb +28 -9
- data/lib/bitclust/subcommands/methods_command.rb +10 -2
- data/lib/bitclust/subcommands/methodsince_command.rb +80 -0
- data/lib/bitclust/subcommands/preproc_command.rb +5 -0
- data/lib/bitclust/subcommands/property_command.rb +2 -1
- data/lib/bitclust/subcommands/searchpage_command.rb +102 -0
- data/lib/bitclust/subcommands/server_command.rb +10 -8
- data/lib/bitclust/subcommands/setup_command.rb +24 -10
- data/lib/bitclust/subcommands/statichtml_command.rb +129 -6
- data/lib/bitclust/subcommands/update_command.rb +110 -2
- data/lib/bitclust/syntax_highlighter.rb +48 -4
- data/lib/bitclust/textutils.rb +3 -3
- data/lib/bitclust/version.rb +1 -1
- data/lib/bitclust/version_badges.rb +90 -0
- data/lib/bitclust/whole_file_gate.rb +137 -0
- data/test/test_app.rb +269 -0
- data/test/test_bitclust.rb +2 -0
- data/test/test_capi_converter.rb +91 -0
- data/test/test_class_screen.rb +413 -0
- data/test/test_copy_doc_md.rb +53 -0
- data/test/test_doc_converter.rb +78 -0
- data/test/test_entity_splitter.rb +231 -0
- data/test/test_entry.rb +207 -2
- data/test/test_eol_warning.rb +43 -0
- data/test/test_functionreferenceparser.rb +11 -0
- data/test/test_include_graph.rb +640 -0
- data/test/test_include_pruner.rb +133 -0
- data/test/test_link_checker.rb +114 -0
- data/test/test_lookup_command.rb +135 -0
- data/test/test_markdown_bridge.rb +217 -0
- data/test/test_markdown_orchestrator.rb +478 -0
- data/test/test_markdown_to_rrd.rb +757 -0
- data/test/test_markdown_tree.rb +369 -0
- data/test/test_mdcompiler.rb +1276 -0
- data/test/test_mdparser.rb +538 -0
- data/test/test_method_screen.rb +166 -0
- data/test/test_method_since_calculator.rb +290 -0
- data/test/test_methoddatabase.rb +16 -0
- data/test/test_methodentry.rb +328 -0
- data/test/test_methodsignature.rb +3 -1
- data/test/test_methodsince_command.rb +168 -0
- data/test/test_nameutils.rb +22 -0
- data/test/test_preprocessor.rb +215 -0
- data/test/test_rdcompiler.rb +401 -30
- data/test/test_refsdatabase.rb +32 -0
- data/test/test_rrd_to_markdown.rb +968 -0
- data/test/test_rrdparser.rb +295 -2
- data/test/test_run_ruby_wasm.rb +54 -0
- data/test/test_run_worker_prelude.rb +83 -0
- data/test/test_runner.rb +51 -0
- data/test/test_search_index_generator.rb +513 -0
- data/test/test_search_screen.rb +48 -0
- data/test/test_searcher.rb +132 -0
- data/test/test_searchpage_command.rb +167 -0
- data/test/test_simplesearcher.rb +28 -0
- data/test/test_statichtml_command.rb +204 -0
- data/test/test_syntax_highlighter.rb +60 -0
- data/test/test_whole_file_gate.rb +175 -0
- data/theme/default/js/NOTICE +42 -0
- data/theme/default/js/run-worker.js +111 -0
- data/theme/default/js/run.js +350 -0
- data/theme/default/js/search_controller.js +134 -0
- data/theme/default/js/search_init.js +176 -0
- data/theme/default/js/search_navigation.js +110 -0
- data/theme/default/js/search_page.js +202 -0
- data/theme/default/js/search_ranker.js +244 -0
- data/theme/default/script.js +91 -18
- data/theme/default/search.css +149 -0
- data/theme/default/style.css +193 -21
- data/theme/default/syntax-highlight.css +8 -0
- data/theme/lillia/style.css +45 -1
- metadata +161 -20
- data/README +0 -32
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
require 'test/unit'
|
|
3
|
+
require 'json'
|
|
4
|
+
require 'fileutils'
|
|
5
|
+
require 'bitclust'
|
|
6
|
+
require 'bitclust/methoddatabase'
|
|
7
|
+
require 'bitclust/subcommands/searchpage_command'
|
|
8
|
+
|
|
9
|
+
# searchpage サブコマンド: 複数バージョンの DB から /ja/search/ 置換用の
|
|
10
|
+
# 静的検索ページ一式(index.html + 統合 search_data.js + JS/CSS アセット)を
|
|
11
|
+
# 生成する。rurema-search(サーバ常駐の全文検索)のリタイア先。
|
|
12
|
+
#
|
|
13
|
+
# テストリスト:
|
|
14
|
+
# [x] 統合 index: 全版共通エントリは versions に全版、片方だけのものはその版のみ
|
|
15
|
+
# [x] index.html に search_versions(昇順)と検索 UI の要素が埋まる
|
|
16
|
+
# [x] vendored JS + NOTICE + search_page.js + search.css がコピーされる
|
|
17
|
+
# [x] ページ専用 UI なので search_init.js(ページ内ボックス用)は含めない
|
|
18
|
+
# [x] DB を持たない引数なし呼び出しはエラー
|
|
19
|
+
# [x] グローバル --database 不要(needs_database? が false)
|
|
20
|
+
class TestSearchpageCommand < Test::Unit::TestCase
|
|
21
|
+
def setup
|
|
22
|
+
@tmpdir = "searchpage_test_tmp"
|
|
23
|
+
FileUtils.rm_rf(@tmpdir)
|
|
24
|
+
@db34 = build_db('3.4', <<~'RD')
|
|
25
|
+
description
|
|
26
|
+
|
|
27
|
+
= class Foo < Object
|
|
28
|
+
== Instance Methods
|
|
29
|
+
--- foo
|
|
30
|
+
RD
|
|
31
|
+
@db41 = build_db('4.1', <<~'RD')
|
|
32
|
+
description
|
|
33
|
+
|
|
34
|
+
= class Foo < Object
|
|
35
|
+
== Instance Methods
|
|
36
|
+
--- foo
|
|
37
|
+
--- bar
|
|
38
|
+
RD
|
|
39
|
+
@out = "#{@tmpdir}/out"
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def teardown
|
|
43
|
+
FileUtils.rm_rf(@tmpdir)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def build_db(version, builtin_rd)
|
|
47
|
+
root = "#{@tmpdir}/tree-#{version}/refm/api/src"
|
|
48
|
+
FileUtils.mkdir_p("#{root}/_builtin")
|
|
49
|
+
File.write("#{root}/LIBRARIES", "_builtin\n")
|
|
50
|
+
File.write("#{root}/_builtin.rd", builtin_rd)
|
|
51
|
+
prefix = "#{@tmpdir}/db-#{version}"
|
|
52
|
+
db = BitClust::MethodDatabase.new(prefix)
|
|
53
|
+
db.init
|
|
54
|
+
db.transaction do
|
|
55
|
+
db.propset('version', version)
|
|
56
|
+
db.propset('encoding', 'utf-8')
|
|
57
|
+
end
|
|
58
|
+
db.transaction do
|
|
59
|
+
db.update_by_stdlibtree(root)
|
|
60
|
+
end
|
|
61
|
+
prefix
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
def run_command(argv)
|
|
65
|
+
cmd = BitClust::Subcommands::SearchpageCommand.new
|
|
66
|
+
cmd.parse(argv)
|
|
67
|
+
cmd.exec(argv, { prefix: nil, capi: false })
|
|
68
|
+
cmd
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def test_needs_no_global_database_option
|
|
72
|
+
cmd = BitClust::Subcommands::SearchpageCommand.new
|
|
73
|
+
assert_false cmd.needs_database?
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def test_merged_index_versions
|
|
77
|
+
run_command(["--outputdir=#{@out}", @db41, @db34])
|
|
78
|
+
js = File.read("#{@out}/js/search_data.js")
|
|
79
|
+
assert_match(/\Avar search_data = \{/, js)
|
|
80
|
+
data = JSON.parse(js.sub(/\Avar search_data = /, '').sub(/;\z/, ''))
|
|
81
|
+
foo = data['index'].find { |e| e['full_name'] == 'Foo#foo' }
|
|
82
|
+
bar = data['index'].find { |e| e['full_name'] == 'Foo#bar' }
|
|
83
|
+
klass = data['index'].find { |e| e['full_name'] == 'Foo' }
|
|
84
|
+
assert_equal %w[3.4 4.1], foo['versions']
|
|
85
|
+
assert_equal %w[4.1], bar['versions']
|
|
86
|
+
assert_equal %w[3.4 4.1], klass['versions']
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
def test_merged_index_shows_module_functions_as_question_dot_only
|
|
90
|
+
# bitclust#279 コメント対応: 版によって表示が ".#"(4.0 より前)と
|
|
91
|
+
# "?."(4.0 以降)に割れる module function は、統合ページでは "?."
|
|
92
|
+
# 表記の1エントリに合流させる(両表記が併記されるとわかりにくい)
|
|
93
|
+
db33 = build_db('3.3', <<~'RD')
|
|
94
|
+
description
|
|
95
|
+
|
|
96
|
+
= module Kernel
|
|
97
|
+
== Module Functions
|
|
98
|
+
--- at_exit{ ... } -> Proc
|
|
99
|
+
aaa
|
|
100
|
+
RD
|
|
101
|
+
db40 = build_db('4.0', <<~'RD')
|
|
102
|
+
description
|
|
103
|
+
|
|
104
|
+
= module Kernel
|
|
105
|
+
== Module Functions
|
|
106
|
+
--- at_exit{ ... } -> Proc
|
|
107
|
+
aaa
|
|
108
|
+
RD
|
|
109
|
+
run_command(["--outputdir=#{@out}", db40, db33])
|
|
110
|
+
js = File.read("#{@out}/js/search_data.js")
|
|
111
|
+
data = JSON.parse(js.sub(/\Avar search_data = /, '').sub(/;\z/, ''))
|
|
112
|
+
entries = data['index'].select { |e| e['name'] == 'at_exit' }
|
|
113
|
+
assert_equal ['Kernel?.at_exit'], entries.map { |e| e['full_name'] }
|
|
114
|
+
assert_equal %w[3.3 4.0], entries[0]['versions']
|
|
115
|
+
assert_not_match(/Kernel\.#/, js)
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
def test_index_html_embeds_versions_and_ui
|
|
119
|
+
run_command(["--outputdir=#{@out}", @db41, @db34])
|
|
120
|
+
html = File.read("#{@out}/index.html")
|
|
121
|
+
assert_match(/var search_versions = \["3\.4","4\.1"\];/, html)
|
|
122
|
+
assert_match(/var search_version_base = "\.\.\/";/, html)
|
|
123
|
+
assert_match(/id="search-field"/, html)
|
|
124
|
+
assert_match(/id="search-results"/, html)
|
|
125
|
+
assert_match(%r{js/search_data\.js}, html)
|
|
126
|
+
assert_match(%r{js/search_page\.js}, html)
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
def test_assets_are_copied
|
|
130
|
+
run_command(["--outputdir=#{@out}", @db41, @db34])
|
|
131
|
+
%w[search_navigation.js search_ranker.js search_controller.js
|
|
132
|
+
search_page.js NOTICE].each do |f|
|
|
133
|
+
assert File.exist?("#{@out}/js/#{f}"), "js/#{f} not copied"
|
|
134
|
+
end
|
|
135
|
+
assert File.exist?("#{@out}/search.css")
|
|
136
|
+
# ページ内ドロップダウン用の search_init.js はこのページでは使わない
|
|
137
|
+
assert_false File.exist?("#{@out}/js/search_init.js")
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
def test_no_database_arguments_is_an_error
|
|
141
|
+
cmd = BitClust::Subcommands::SearchpageCommand.new
|
|
142
|
+
argv = ["--outputdir=#{@out}"]
|
|
143
|
+
cmd.parse(argv)
|
|
144
|
+
assert_raise(SystemExit) do
|
|
145
|
+
capture_stderr { cmd.exec(argv, { prefix: nil, capi: false }) }
|
|
146
|
+
end
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
def test_missing_outputdir_is_an_error
|
|
150
|
+
cmd = BitClust::Subcommands::SearchpageCommand.new
|
|
151
|
+
argv = [@db34]
|
|
152
|
+
cmd.parse(argv)
|
|
153
|
+
assert_raise(SystemExit) do
|
|
154
|
+
capture_stderr { cmd.exec(argv, { prefix: nil, capi: false }) }
|
|
155
|
+
end
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
private
|
|
159
|
+
|
|
160
|
+
def capture_stderr
|
|
161
|
+
orig = $stderr
|
|
162
|
+
$stderr = StringIO.new
|
|
163
|
+
yield
|
|
164
|
+
ensure
|
|
165
|
+
$stderr = orig
|
|
166
|
+
end
|
|
167
|
+
end
|
data/test/test_simplesearcher.rb
CHANGED
|
@@ -15,6 +15,12 @@ class TestSearcher < Test::Unit::TestCase
|
|
|
15
15
|
== Class Methods
|
|
16
16
|
--- bar
|
|
17
17
|
= reopen Kernel
|
|
18
|
+
== Module Functions
|
|
19
|
+
--- open
|
|
20
|
+
|
|
21
|
+
== Instance Methods
|
|
22
|
+
--- puts
|
|
23
|
+
|
|
18
24
|
== Special Variables
|
|
19
25
|
--- $spespe
|
|
20
26
|
|
|
@@ -45,4 +51,26 @@ HERE
|
|
|
45
51
|
assert_equal([], search_pattern(@db, " "), 'space')
|
|
46
52
|
assert_equal([], search_pattern(@db, ""), 'blank')
|
|
47
53
|
end
|
|
54
|
+
|
|
55
|
+
# bitclust#250 follow-up: the dynamic server's /search accepts free-text
|
|
56
|
+
# queries, and a module function may be typed in either notation --
|
|
57
|
+
# "Kernel.#open" (bitclust's own internal spec-string form, still what
|
|
58
|
+
# docs for Ruby < 4.0 display) or "Kernel?.open" (what docs for Ruby >=
|
|
59
|
+
# 4.0 display since #277). Both must resolve to the same method,
|
|
60
|
+
# regardless of which notation the *query* uses -- the query parser has
|
|
61
|
+
# no idea (and shouldn't need to know) which doc version the user is
|
|
62
|
+
# thinking of.
|
|
63
|
+
def test_module_function_query_notation
|
|
64
|
+
[['Kernel?.open', 'open'], # new (>=4.0 display) notation
|
|
65
|
+
['Kernel.#open', 'open'], # existing (bitclust-internal) notation: regression check
|
|
66
|
+
['?.open', 'open'], # bare module-function marker, no class name
|
|
67
|
+
['Kernel#puts', 'puts'], # instance method: unaffected by the "?." change
|
|
68
|
+
].each{|q, expected|
|
|
69
|
+
ret = search_pattern(@db, q)
|
|
70
|
+
assert_not_equal([], ret, q)
|
|
71
|
+
assert_equal(expected, ret[0].name, q)
|
|
72
|
+
}
|
|
73
|
+
# Singleton-method dot notation ('Hoge.h' => 'hoge' in test_simple_search
|
|
74
|
+
# above) is also unaffected; kept there rather than duplicated here.
|
|
75
|
+
end
|
|
48
76
|
end
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
require 'test/unit'
|
|
2
|
+
require 'tmpdir'
|
|
3
|
+
require 'stringio'
|
|
4
|
+
require 'bitclust'
|
|
5
|
+
require 'bitclust/subcommands/statichtml_command'
|
|
6
|
+
|
|
7
|
+
class TestStatichtmlURLMapperEx < Test::Unit::TestCase
|
|
8
|
+
def setup
|
|
9
|
+
@urlmapper = BitClust::Subcommands::StatichtmlCommand::URLMapperEx.new(
|
|
10
|
+
:suffix => 'html',
|
|
11
|
+
:edit_base_url => 'https://github.com/rurema/doctree/edit/master',
|
|
12
|
+
)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
# The edit URL must not contain a line number, so that shifting source lines
|
|
16
|
+
# does not churn the generated HTML diff.
|
|
17
|
+
def test_edit_url_has_no_line_number
|
|
18
|
+
location = BitClust::Location.new('refm/api/src/_builtin/Array', 42)
|
|
19
|
+
assert_equal('https://github.com/rurema/doctree/edit/master/refm/api/src/_builtin/Array',
|
|
20
|
+
@urlmapper.edit_url(location))
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# A location restored from the database has no line number (nil); the edit URL
|
|
24
|
+
# must still be a clean file link without a trailing "#L".
|
|
25
|
+
def test_edit_url_without_line_in_location
|
|
26
|
+
location = BitClust::Location.new('refm/api/src/_builtin/Array', nil)
|
|
27
|
+
assert_equal('https://github.com/rurema/doctree/edit/master/refm/api/src/_builtin/Array',
|
|
28
|
+
@urlmapper.edit_url(location))
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
class TestStatichtmlRunRubyWasm < Test::Unit::TestCase
|
|
33
|
+
def build_command(themedir, outputdir)
|
|
34
|
+
cmd = BitClust::Subcommands::StatichtmlCommand.new
|
|
35
|
+
cmd.instance_variable_set(:@manager_config, { :themedir => Pathname.new(themedir) })
|
|
36
|
+
cmd.instance_variable_set(:@outputdir, Pathname.new(outputdir))
|
|
37
|
+
cmd.instance_variable_set(:@verbose, false)
|
|
38
|
+
cmd
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
def test_option_defaults_to_nil
|
|
42
|
+
cmd = BitClust::Subcommands::StatichtmlCommand.new
|
|
43
|
+
assert_nil(cmd.instance_variable_get(:@run_ruby_wasm))
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def test_option_is_parsed
|
|
47
|
+
url = 'https://cdn.jsdelivr.net/npm/@ruby/3.4-wasm-wasi@2.9.3-2.9.4/dist/ruby+stdlib.wasm'
|
|
48
|
+
cmd = BitClust::Subcommands::StatichtmlCommand.new
|
|
49
|
+
cmd.parse(["--run-ruby-wasm=#{url}"])
|
|
50
|
+
assert_equal(url, cmd.instance_variable_get(:@run_ruby_wasm))
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
def test_run_js_is_copied
|
|
54
|
+
Dir.mktmpdir do |dir|
|
|
55
|
+
themedir = File.join(dir, 'theme')
|
|
56
|
+
outputdir = File.join(dir, 'out')
|
|
57
|
+
FileUtils.mkdir_p(File.join(themedir, 'js'))
|
|
58
|
+
FileUtils.mkdir_p(outputdir)
|
|
59
|
+
File.write(File.join(themedir, 'js', 'run.js'), "// run\n")
|
|
60
|
+
File.write(File.join(themedir, 'js', 'run-worker.js'), "// worker\n")
|
|
61
|
+
cmd = build_command(themedir, outputdir)
|
|
62
|
+
cmd.send(:copy_run_ruby_wasm_script)
|
|
63
|
+
assert_true(File.file?(File.join(outputdir, 'js', 'run.js')))
|
|
64
|
+
assert_true(File.file?(File.join(outputdir, 'js', 'run-worker.js')))
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def test_theme_without_run_js_is_tolerated
|
|
69
|
+
Dir.mktmpdir do |dir|
|
|
70
|
+
themedir = File.join(dir, 'theme')
|
|
71
|
+
outputdir = File.join(dir, 'out')
|
|
72
|
+
FileUtils.mkdir_p(themedir)
|
|
73
|
+
FileUtils.mkdir_p(outputdir)
|
|
74
|
+
cmd = build_command(themedir, outputdir)
|
|
75
|
+
orig_stderr, $stderr = $stderr, StringIO.new
|
|
76
|
+
begin
|
|
77
|
+
assert_nothing_raised { cmd.send(:copy_run_ruby_wasm_script) }
|
|
78
|
+
assert_match(/run\.js not found/, $stderr.string)
|
|
79
|
+
assert_match(/run-worker\.js not found/, $stderr.string)
|
|
80
|
+
ensure
|
|
81
|
+
$stderr = orig_stderr
|
|
82
|
+
end
|
|
83
|
+
assert_false(File.exist?(File.join(outputdir, 'js', 'run.js')))
|
|
84
|
+
assert_false(File.exist?(File.join(outputdir, 'js', 'run-worker.js')))
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
# A themedir with run.js but not yet upgraded with run-worker.js (or vice
|
|
89
|
+
# versa) should still copy whichever file it does have, rather than
|
|
90
|
+
# aborting or silently skipping both.
|
|
91
|
+
def test_partial_theme_copies_what_it_has
|
|
92
|
+
Dir.mktmpdir do |dir|
|
|
93
|
+
themedir = File.join(dir, 'theme')
|
|
94
|
+
outputdir = File.join(dir, 'out')
|
|
95
|
+
FileUtils.mkdir_p(File.join(themedir, 'js'))
|
|
96
|
+
FileUtils.mkdir_p(outputdir)
|
|
97
|
+
File.write(File.join(themedir, 'js', 'run.js'), "// run\n")
|
|
98
|
+
cmd = build_command(themedir, outputdir)
|
|
99
|
+
orig_stderr, $stderr = $stderr, StringIO.new
|
|
100
|
+
begin
|
|
101
|
+
cmd.send(:copy_run_ruby_wasm_script)
|
|
102
|
+
assert_match(/run-worker\.js not found/, $stderr.string)
|
|
103
|
+
ensure
|
|
104
|
+
$stderr = orig_stderr
|
|
105
|
+
end
|
|
106
|
+
assert_true(File.file?(File.join(outputdir, 'js', 'run.js')))
|
|
107
|
+
assert_false(File.exist?(File.join(outputdir, 'js', 'run-worker.js')))
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
class TestStatichtmlSitemap < Test::Unit::TestCase
|
|
113
|
+
def build_command(outputdir)
|
|
114
|
+
cmd = BitClust::Subcommands::StatichtmlCommand.new
|
|
115
|
+
cmd.instance_variable_set(:@outputdir, Pathname.new(outputdir))
|
|
116
|
+
cmd.instance_variable_set(:@verbose, false)
|
|
117
|
+
cmd
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
def test_option_defaults_to_nil
|
|
121
|
+
cmd = BitClust::Subcommands::StatichtmlCommand.new
|
|
122
|
+
assert_nil(cmd.instance_variable_get(:@sitemap_baseurl))
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
def test_option_is_parsed
|
|
126
|
+
cmd = BitClust::Subcommands::StatichtmlCommand.new
|
|
127
|
+
cmd.parse(['--sitemap-baseurl=https://docs.ruby-lang.org/ja/3.4/'])
|
|
128
|
+
assert_equal('https://docs.ruby-lang.org/ja/3.4/',
|
|
129
|
+
cmd.instance_variable_get(:@sitemap_baseurl))
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
def test_record_sitemap_path_is_noop_without_baseurl
|
|
133
|
+
Dir.mktmpdir do |dir|
|
|
134
|
+
cmd = build_command(dir)
|
|
135
|
+
cmd.send(:record_sitemap_path, Pathname.new(dir) + 'class' + 'String.html')
|
|
136
|
+
assert_empty(cmd.instance_variable_get(:@sitemap_paths))
|
|
137
|
+
end
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
def test_record_sitemap_path_keeps_relative_path
|
|
141
|
+
Dir.mktmpdir do |dir|
|
|
142
|
+
cmd = build_command(dir)
|
|
143
|
+
cmd.instance_variable_set(:@sitemap_baseurl, 'https://docs.ruby-lang.org/ja/3.4/')
|
|
144
|
+
cmd.send(:record_sitemap_path, Pathname.new(dir) + 'class' + 'String.html')
|
|
145
|
+
assert_equal(%w[class/String.html], cmd.instance_variable_get(:@sitemap_paths))
|
|
146
|
+
end
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
def test_create_sitemap_writes_loc_urls
|
|
150
|
+
Dir.mktmpdir do |dir|
|
|
151
|
+
cmd = build_command(dir)
|
|
152
|
+
cmd.instance_variable_set(:@sitemap_paths,
|
|
153
|
+
['class/String.html', 'method/String/i/upcase.html'])
|
|
154
|
+
cmd.send(:create_sitemap, Pathname.new(dir), 'https://docs.ruby-lang.org/ja/3.4/')
|
|
155
|
+
xml = File.read(File.join(dir, 'sitemap.xml'))
|
|
156
|
+
assert_match(%r{\A<\?xml version="1\.0" encoding="UTF-8"\?>\n}, xml)
|
|
157
|
+
assert_match(%r{<urlset xmlns="http://www\.sitemaps\.org/schemas/sitemap/0\.9">}, xml)
|
|
158
|
+
assert_match(%r{<url><loc>https://docs\.ruby-lang\.org/ja/3\.4/class/String\.html</loc></url>}, xml)
|
|
159
|
+
assert_match(%r{<url><loc>https://docs\.ruby-lang\.org/ja/3\.4/method/String/i/upcase\.html</loc></url>}, xml)
|
|
160
|
+
assert_match(%r{</urlset>\n\z}, xml)
|
|
161
|
+
end
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
def test_create_sitemap_adds_trailing_slash_to_baseurl
|
|
165
|
+
Dir.mktmpdir do |dir|
|
|
166
|
+
cmd = build_command(dir)
|
|
167
|
+
cmd.instance_variable_set(:@sitemap_paths, ['class/String.html'])
|
|
168
|
+
cmd.send(:create_sitemap, Pathname.new(dir), 'https://docs.ruby-lang.org/ja/3.4')
|
|
169
|
+
xml = File.read(File.join(dir, 'sitemap.xml'))
|
|
170
|
+
assert_match(%r{<loc>https://docs\.ruby-lang\.org/ja/3\.4/class/String\.html</loc>}, xml)
|
|
171
|
+
end
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
def test_create_sitemap_escapes_special_characters
|
|
175
|
+
Dir.mktmpdir do |dir|
|
|
176
|
+
cmd = build_command(dir)
|
|
177
|
+
cmd.instance_variable_set(:@sitemap_paths, ['method/String/i/=3d=3d.html'])
|
|
178
|
+
cmd.send(:create_sitemap, Pathname.new(dir), 'https://example.com/a&b/')
|
|
179
|
+
xml = File.read(File.join(dir, 'sitemap.xml'))
|
|
180
|
+
assert_match(%r{<loc>https://example\.com/a&b/method/String/i/=3d=3d\.html</loc>}, xml)
|
|
181
|
+
assert_not_match(/a&b/, xml)
|
|
182
|
+
end
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
def test_create_sitemap_warns_and_truncates_beyond_limit
|
|
186
|
+
Dir.mktmpdir do |dir|
|
|
187
|
+
cmd = build_command(dir)
|
|
188
|
+
limit = BitClust::Subcommands::StatichtmlCommand::MAX_SITEMAP_URLS
|
|
189
|
+
paths = (1..(limit + 1)).map {|i| "class/C#{i}.html" }
|
|
190
|
+
cmd.instance_variable_set(:@sitemap_paths, paths)
|
|
191
|
+
orig_stderr, $stderr = $stderr, StringIO.new
|
|
192
|
+
begin
|
|
193
|
+
cmd.send(:create_sitemap, Pathname.new(dir), 'https://example.com/')
|
|
194
|
+
assert_match(/warning:.*#{limit}/, $stderr.string)
|
|
195
|
+
ensure
|
|
196
|
+
$stderr = orig_stderr
|
|
197
|
+
end
|
|
198
|
+
xml = File.read(File.join(dir, 'sitemap.xml'))
|
|
199
|
+
assert_equal(limit, xml.scan('<url>').size)
|
|
200
|
+
assert_match(%r{<loc>https://example\.com/class/C1\.html</loc>}, xml)
|
|
201
|
+
assert_not_match(/C#{limit + 1}\.html/, xml)
|
|
202
|
+
end
|
|
203
|
+
end
|
|
204
|
+
end
|
|
@@ -82,4 +82,64 @@ class TestSyntaxHighlighter < Test::Unit::TestCase
|
|
|
82
82
|
END
|
|
83
83
|
assert_equal(expected, highlight(source))
|
|
84
84
|
end
|
|
85
|
+
|
|
86
|
+
test 'symbol const' do
|
|
87
|
+
source = <<~END
|
|
88
|
+
class Foo
|
|
89
|
+
def to_hash
|
|
90
|
+
{:Bar => 'a',
|
|
91
|
+
:Baz => 'b'
|
|
92
|
+
}
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
END
|
|
96
|
+
expected = <<~END
|
|
97
|
+
<span class="k">class</span> <span class="nn"></span><span class="o"></span><span class="nc">Foo</span>
|
|
98
|
+
<span class="k">def</span> <span class="nf">to_hash</span>
|
|
99
|
+
<span class="p">{</span><span class="ss">:Bar</span> <span class="o">=></span> <span class="s1">'a'</span>,
|
|
100
|
+
<span class="ss">:Baz</span> <span class="o">=></span> <span class="s1">'b'</span>
|
|
101
|
+
<span class="p">}</span>
|
|
102
|
+
<span class="k">end</span>
|
|
103
|
+
<span class="k">end</span>
|
|
104
|
+
END
|
|
105
|
+
assert_equal(expected, highlight(source))
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
test 'symbol list' do
|
|
109
|
+
source = <<~END
|
|
110
|
+
%i[hellow world].each {|s| p s }
|
|
111
|
+
END
|
|
112
|
+
expected = <<~END
|
|
113
|
+
<span class="ss">%i[hellow world]</span><span class="p">.</span><span class="nf">each</span> <span class="p">{</span><span class="o">|</span>s<span class="o">|</span> <span class="nb">p</span> s <span class="p">}</span>
|
|
114
|
+
END
|
|
115
|
+
assert_equal(expected, highlight(source))
|
|
116
|
+
|
|
117
|
+
source = <<~END
|
|
118
|
+
%I[hellow world].each {|s| p s }
|
|
119
|
+
END
|
|
120
|
+
expected = <<~END
|
|
121
|
+
<span class="ss">%I[hellow world]</span><span class="p">.</span><span class="nf">each</span> <span class="p">{</span><span class="o">|</span>s<span class="o">|</span> <span class="nb">p</span> s <span class="p">}</span>
|
|
122
|
+
END
|
|
123
|
+
assert_equal(expected, highlight(source))
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
test 'one liner module' do
|
|
127
|
+
source = <<~END
|
|
128
|
+
module Foo; end
|
|
129
|
+
END
|
|
130
|
+
expected = <<~END
|
|
131
|
+
<span class="k">module</span> <span class="nn">Foo</span>; <span class="k">end</span>
|
|
132
|
+
END
|
|
133
|
+
assert_equal(expected, highlight(source))
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
test 'one liner class' do
|
|
137
|
+
source = <<~END
|
|
138
|
+
class Foo; end
|
|
139
|
+
END
|
|
140
|
+
expected = <<~END
|
|
141
|
+
<span class="k">class</span> <span class="nn"></span><span class="o"></span><span class="nc">Foo</span>; <span class="k">end</span>
|
|
142
|
+
END
|
|
143
|
+
assert_equal(expected, highlight(source))
|
|
144
|
+
end
|
|
85
145
|
end
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'test/unit'
|
|
4
|
+
|
|
5
|
+
require 'bitclust/whole_file_gate'
|
|
6
|
+
require 'bitclust/include_graph'
|
|
7
|
+
|
|
8
|
+
# WholeFileGate: ファイル全体を包む単一の版ゲート(#@else 無し)を検出し、
|
|
9
|
+
# スコープの下で不要(常に真)または front matter の since/until で表現できる場合に
|
|
10
|
+
# ゲート行を外す(O4)。表現できないもの(#@else 付き、スコープ外)は据え置き。
|
|
11
|
+
#
|
|
12
|
+
# テストリスト:
|
|
13
|
+
# [x] ゲートで始まらないファイル → detect nil
|
|
14
|
+
# [x] #@end の後に内容が続く(部分ゲート)→ nil
|
|
15
|
+
# [x] ファイル全体を包む #@since/#@until/#@if → Condition
|
|
16
|
+
# [x] トップレベルに #@else がある(fiddle.rd)→ nil
|
|
17
|
+
# [x] 内部にネストしたゲート・#@samplecode があっても正しく対応を取る(rss.rd)
|
|
18
|
+
# [x] 先頭の空行はスキップして判定、#@end の後の空行は許容
|
|
19
|
+
# [x] unwrap: 開き/閉じ行を除去し、先頭に残る空行は削る(doctree 正規化と整合)
|
|
20
|
+
# [x] unwrap_for_scope: スコープ内で常に真の since → [unwrapped, {}]
|
|
21
|
+
# [x] unwrap_for_scope: in-scope の until(fiber/set)→ [unwrapped, {until: v}]
|
|
22
|
+
# [x] unwrap_for_scope: in-scope の since → [unwrapped, {since: v}]
|
|
23
|
+
# [x] unwrap_for_scope: スコープ外(until 2.7.0 等)→ nil(据え置き)
|
|
24
|
+
# [x] unwrap_for_scope: 常に真と証明できる #@if(version >= "X", X <= 下限)→ [unwrapped, {}]
|
|
25
|
+
# [x] unwrap_for_scope: その他の #@if 条件 → nil(据え置き)
|
|
26
|
+
class TestWholeFileGate < Test::Unit::TestCase
|
|
27
|
+
def scope
|
|
28
|
+
BitClust::IncludeGraph::Scope.new("3.0", "4.2")
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def detect(src)
|
|
32
|
+
BitClust::WholeFileGate.detect(src)
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def unwrap_for_scope(src)
|
|
36
|
+
BitClust::WholeFileGate.unwrap_for_scope(src, scope)
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def test_detect_returns_nil_without_gate
|
|
40
|
+
assert_nil detect("category Math\n\n本文。\n")
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def test_detect_returns_nil_for_partial_gate
|
|
44
|
+
# cgi/util.rd: 先頭ゲートがファイル途中で閉じる
|
|
45
|
+
assert_nil detect("\#@since 1.9.1\n本文。\n\#@end\n続き。\n")
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def test_detect_whole_file_since
|
|
49
|
+
cond = detect("\#@since 1.9.1\n本文。\n\#@end\n")
|
|
50
|
+
assert_equal :since, cond.kind
|
|
51
|
+
assert_equal "1.9.1", cond.version
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def test_detect_whole_file_if
|
|
55
|
+
cond = detect("\#@if (version >= \"1.8.2\")\n本文。\n\#@end\n")
|
|
56
|
+
assert_equal :if, cond.kind
|
|
57
|
+
assert_equal '(version >= "1.8.2")', cond.version
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
def test_detect_returns_nil_with_top_level_else
|
|
61
|
+
# fiddle.rd: #@until 2.0.0 ... #@else ... #@end
|
|
62
|
+
assert_nil detect("\#@until 2.0.0\n古い。\n\#@else\n新しい。\n\#@end\n")
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
def test_detect_handles_nested_gates_and_samplecode
|
|
66
|
+
src = "\#@since 1.9.1\n\#@until 3.0\n本文。\n\#@end\n\#@samplecode\ncode\n\#@end\n\#@end\n"
|
|
67
|
+
cond = detect(src)
|
|
68
|
+
assert_equal :since, cond.kind
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def test_detect_skips_leading_and_trailing_blanks
|
|
72
|
+
cond = detect("\n\#@since 1.9.1\n本文。\n\#@end\n\n")
|
|
73
|
+
assert_equal :since, cond.kind
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def test_unwrap_for_scope_vacuous_since
|
|
77
|
+
# cmath.rd / _builtin/Encoding: #@since 1.9.1(+直後の空行)で全体が包まれる
|
|
78
|
+
src = "\#@since 1.9.1\n\ncategory Math\n\n本文。\n\#@end\n"
|
|
79
|
+
unwrapped, gate = unwrap_for_scope(src)
|
|
80
|
+
assert_equal "category Math\n\n本文。\n", unwrapped
|
|
81
|
+
assert_equal({}, gate)
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
def test_unwrap_for_scope_in_scope_until
|
|
85
|
+
# fiber.rd: #@until 3.1
|
|
86
|
+
src = "\#@until 3.1\n本文。\n\n\#@end\n"
|
|
87
|
+
unwrapped, gate = unwrap_for_scope(src)
|
|
88
|
+
assert_equal "本文。\n\n", unwrapped
|
|
89
|
+
assert_equal({ until: "3.1" }, gate)
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def test_unwrap_for_scope_in_scope_since
|
|
93
|
+
src = "\#@since 3.2\n本文。\n\#@end\n"
|
|
94
|
+
unwrapped, gate = unwrap_for_scope(src)
|
|
95
|
+
assert_equal "本文。\n", unwrapped
|
|
96
|
+
assert_equal({ since: "3.2" }, gate)
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
def test_unwrap_for_scope_leaves_out_of_scope_file
|
|
100
|
+
# profile.rd / irb/slex.rd: until 2.7.0 は [3.0,4.2) の対象外
|
|
101
|
+
assert_nil unwrap_for_scope("\#@until 2.7.0\n本文。\n\#@end\n")
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
def test_unwrap_for_scope_provably_true_if
|
|
105
|
+
# rss.rd: (version >= "1.8.2") はスコープ下限 3.0 以下なので常に真
|
|
106
|
+
src = "\#@if (version >= \"1.8.2\")\n本文。\n\#@end\n"
|
|
107
|
+
unwrapped, gate = unwrap_for_scope(src)
|
|
108
|
+
assert_equal "本文。\n", unwrapped
|
|
109
|
+
assert_equal({}, gate)
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
def test_unwrap_for_scope_leaves_unprovable_if
|
|
113
|
+
assert_nil unwrap_for_scope("\#@if (version == \"3.1\")\n本文。\n\#@end\n")
|
|
114
|
+
assert_nil unwrap_for_scope("\#@if (version >= \"3.1\")\n本文。\n\#@end\n")
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
def test_unwrap_for_scope_returns_nil_without_whole_file_gate
|
|
118
|
+
assert_nil unwrap_for_scope("category Math\n\n本文。\n")
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
# ---- regate_metadata: 据え置きゲートのメタデータ領域を独立ゲートに分離 ----
|
|
122
|
+
# 旧版サルベージで据え置かれた library ルートの全体ゲート(rubygems.rd の
|
|
123
|
+
# #@since 1.9.1 等)は、メタデータが本文に埋もれると native パースが
|
|
124
|
+
# front matter から読めない。意味等価な正規形(メタデータブロック + 本文ブロック、
|
|
125
|
+
# それぞれ同じゲートで包む)に書き換えることで、既存のゲート対応
|
|
126
|
+
# メタデータ収集器がそのまま front matter 化できる
|
|
127
|
+
|
|
128
|
+
def regate(src)
|
|
129
|
+
BitClust::WholeFileGate.regate_metadata(src)
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
def test_regate_metadata_splits_metadata_and_body
|
|
133
|
+
# 種別(category/require/sublibrary)ごとに独立のゲートブロックへ分ける
|
|
134
|
+
# (メタデータ収集器の「#@ ブロックは単一種のみ」の制約に合わせる)
|
|
135
|
+
src = "\#@since 1.9.1\n" \
|
|
136
|
+
"require rubygems/defaults\n" \
|
|
137
|
+
"require rubygems/version\n" \
|
|
138
|
+
"\n" \
|
|
139
|
+
"sublibrary rubygems/gem_runner\n" \
|
|
140
|
+
"\n" \
|
|
141
|
+
"本文。\n" \
|
|
142
|
+
"\#@end\n"
|
|
143
|
+
expected = "\#@since 1.9.1\n" \
|
|
144
|
+
"require rubygems/defaults\n" \
|
|
145
|
+
"require rubygems/version\n" \
|
|
146
|
+
"\#@end\n" \
|
|
147
|
+
"\n" \
|
|
148
|
+
"\#@since 1.9.1\n" \
|
|
149
|
+
"sublibrary rubygems/gem_runner\n" \
|
|
150
|
+
"\#@end\n" \
|
|
151
|
+
"\n" \
|
|
152
|
+
"\#@since 1.9.1\n" \
|
|
153
|
+
"本文。\n" \
|
|
154
|
+
"\#@end\n"
|
|
155
|
+
assert_equal expected, regate(src)
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
def test_regate_metadata_skips_leading_blank_in_gate
|
|
159
|
+
src = "\#@since 1.9.1\n\ncategory Math\n\n本文。\n\#@end\n"
|
|
160
|
+
expected = "\#@since 1.9.1\ncategory Math\n\#@end\n\n\#@since 1.9.1\n本文。\n\#@end\n"
|
|
161
|
+
assert_equal expected, regate(src)
|
|
162
|
+
end
|
|
163
|
+
|
|
164
|
+
def test_regate_metadata_returns_nil_without_metadata
|
|
165
|
+
assert_nil regate("\#@since 1.9.1\n本文。\n\#@end\n")
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
def test_regate_metadata_returns_nil_without_body
|
|
169
|
+
assert_nil regate("\#@since 1.9.1\nrequire foo\n\#@end\n")
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
def test_regate_metadata_returns_nil_without_whole_file_gate
|
|
173
|
+
assert_nil regate("require foo\n\n本文。\n")
|
|
174
|
+
end
|
|
175
|
+
end
|