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,513 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
require 'test/unit'
|
|
3
|
+
require 'json'
|
|
4
|
+
require 'fileutils'
|
|
5
|
+
require 'tmpdir'
|
|
6
|
+
require 'bitclust'
|
|
7
|
+
require 'bitclust/methoddatabase'
|
|
8
|
+
require 'bitclust/search_index_generator'
|
|
9
|
+
|
|
10
|
+
class TestSearchIndexGenerator < Test::Unit::TestCase
|
|
11
|
+
def setup
|
|
12
|
+
@prefix = 'db_si'
|
|
13
|
+
@base = 'tree_si'
|
|
14
|
+
@root = "#{@base}/refm/api/src"
|
|
15
|
+
setup_files
|
|
16
|
+
@db = BitClust::MethodDatabase.new(@prefix)
|
|
17
|
+
@db.init
|
|
18
|
+
@db.transaction do
|
|
19
|
+
[%w[version 3.4], %w[encoding utf-8]].each do |k, v|
|
|
20
|
+
@db.propset(k, v)
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
@db.transaction do
|
|
24
|
+
@db.update_by_stdlibtree(@root)
|
|
25
|
+
end
|
|
26
|
+
@gen = BitClust::SearchIndexGenerator.new
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def teardown
|
|
30
|
+
FileUtils.rm_r([@prefix, @base], :force => true)
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
def find_entry(index, full_name)
|
|
34
|
+
index.find { |e| e[:full_name] == full_name }
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def test_class_entry
|
|
38
|
+
index = @gen.build_index(@db)
|
|
39
|
+
e = find_entry(index, 'Foo')
|
|
40
|
+
assert_not_nil e
|
|
41
|
+
assert_equal 'Foo', e[:name]
|
|
42
|
+
assert_equal 'class', e[:type]
|
|
43
|
+
assert_equal 'class/-foo.html', e[:path]
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def test_module_entry_type
|
|
47
|
+
index = @gen.build_index(@db)
|
|
48
|
+
e = find_entry(index, 'Kernel')
|
|
49
|
+
assert_not_nil e
|
|
50
|
+
assert_equal 'module', e[:type]
|
|
51
|
+
assert_equal 'class/-kernel.html', e[:path]
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def test_instance_method_entry
|
|
55
|
+
index = @gen.build_index(@db)
|
|
56
|
+
e = find_entry(index, 'Foo#foo')
|
|
57
|
+
assert_not_nil e
|
|
58
|
+
assert_equal 'foo', e[:name]
|
|
59
|
+
assert_equal 'instance_method', e[:type]
|
|
60
|
+
assert_equal 'method/-foo/i/foo.html', e[:path]
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def test_module_function_is_class_method
|
|
64
|
+
index = @gen.build_index(@db)
|
|
65
|
+
e = find_entry(index, 'Kernel.#at_exit')
|
|
66
|
+
assert_not_nil e
|
|
67
|
+
assert_equal 'at_exit', e[:name]
|
|
68
|
+
assert_equal 'class_method', e[:type]
|
|
69
|
+
assert_equal 'method/-kernel/m/at_exit.html', e[:path]
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
# bitclust#250: Ruby 4.0 以降のドキュメントでは module function の表記を
|
|
73
|
+
# 独自の「.#」から「?.」に変える(表示のみ)。full_name は検索結果に
|
|
74
|
+
# そのまま出る表示ラベルなので変換対象だが、path(識別子)は変えない
|
|
75
|
+
def test_module_function_full_name_switches_to_question_dot_at_4_0
|
|
76
|
+
prefix = 'db_si_40'
|
|
77
|
+
base = 'tree_si_40'
|
|
78
|
+
root = "#{base}/refm/api/src"
|
|
79
|
+
FileUtils.mkdir_p("#{root}/_builtin")
|
|
80
|
+
File.write("#{root}/LIBRARIES", "_builtin\n")
|
|
81
|
+
File.write("#{root}/_builtin.rd", <<~RD)
|
|
82
|
+
description
|
|
83
|
+
|
|
84
|
+
= module Kernel
|
|
85
|
+
description
|
|
86
|
+
== Module Functions
|
|
87
|
+
--- at_exit{ ... } -> Proc
|
|
88
|
+
aaa
|
|
89
|
+
RD
|
|
90
|
+
db = BitClust::MethodDatabase.new(prefix)
|
|
91
|
+
db.init
|
|
92
|
+
db.transaction do
|
|
93
|
+
[%w[version 4.0], %w[encoding utf-8]].each { |k, v| db.propset(k, v) }
|
|
94
|
+
end
|
|
95
|
+
db.transaction { db.update_by_stdlibtree(root) }
|
|
96
|
+
|
|
97
|
+
index = BitClust::SearchIndexGenerator.new.build_index(db)
|
|
98
|
+
e = index.find { |x| x[:path] == 'method/-kernel/m/at_exit.html' }
|
|
99
|
+
assert_not_nil e
|
|
100
|
+
assert_equal 'at_exit', e[:name]
|
|
101
|
+
assert_equal 'class_method', e[:type]
|
|
102
|
+
assert_equal 'Kernel?.at_exit', e[:full_name]
|
|
103
|
+
ensure
|
|
104
|
+
FileUtils.rm_r([prefix, base], :force => true)
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
# bitclust#279: the vendored Aliki search ranker's parseQuery() rewrites
|
|
108
|
+
# every "." in the *query* to "::" (RDoc's own full_names use "::" for
|
|
109
|
+
# class methods), but BitClust keeps a literal "."/".#"/"?." in full_name
|
|
110
|
+
# for singleton methods and module functions. match_name mirrors that same
|
|
111
|
+
# rewrite on the entry side (folding "?." to ".#" first) so a
|
|
112
|
+
# search_init.js computeScore wrap can compare like-for-like without ever
|
|
113
|
+
# touching the displayed full_name. See search_index_generator.rb's header
|
|
114
|
+
# comment and theme/default/js/search_init.js.
|
|
115
|
+
|
|
116
|
+
def test_singleton_method_gets_match_name_with_double_colon
|
|
117
|
+
index = @gen.build_index(@db)
|
|
118
|
+
e = find_entry(index, 'Foo.bar')
|
|
119
|
+
assert_not_nil e
|
|
120
|
+
assert_equal 'class_method', e[:type]
|
|
121
|
+
assert_equal 'Foo::bar', e[:match_name]
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
def test_module_function_gets_match_name_with_hash_folded
|
|
125
|
+
index = @gen.build_index(@db)
|
|
126
|
+
e = find_entry(index, 'Kernel.#at_exit')
|
|
127
|
+
assert_not_nil e
|
|
128
|
+
assert_equal 'Kernel::#at_exit', e[:match_name]
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
def test_module_function_at_4_0_gets_match_name_folding_question_dot
|
|
132
|
+
# The "?." (4.0+) and ".#" (pre-4.0) spellings of the same module
|
|
133
|
+
# function must fold to the *same* match_name, so a query typed in
|
|
134
|
+
# either notation can find an index built from either notation
|
|
135
|
+
# (bitclust#250's cross-notation case).
|
|
136
|
+
prefix = 'db_si_40_match'
|
|
137
|
+
base = 'tree_si_40_match'
|
|
138
|
+
root = "#{base}/refm/api/src"
|
|
139
|
+
FileUtils.mkdir_p("#{root}/_builtin")
|
|
140
|
+
File.write("#{root}/LIBRARIES", "_builtin\n")
|
|
141
|
+
File.write("#{root}/_builtin.rd", <<~RD)
|
|
142
|
+
description
|
|
143
|
+
|
|
144
|
+
= module Kernel
|
|
145
|
+
description
|
|
146
|
+
== Module Functions
|
|
147
|
+
--- at_exit{ ... } -> Proc
|
|
148
|
+
aaa
|
|
149
|
+
RD
|
|
150
|
+
db = BitClust::MethodDatabase.new(prefix)
|
|
151
|
+
db.init
|
|
152
|
+
db.transaction do
|
|
153
|
+
[%w[version 4.0], %w[encoding utf-8]].each { |k, v| db.propset(k, v) }
|
|
154
|
+
end
|
|
155
|
+
db.transaction { db.update_by_stdlibtree(root) }
|
|
156
|
+
|
|
157
|
+
index = BitClust::SearchIndexGenerator.new.build_index(db)
|
|
158
|
+
e = index.find { |x| x[:path] == 'method/-kernel/m/at_exit.html' }
|
|
159
|
+
assert_not_nil e
|
|
160
|
+
assert_equal 'Kernel?.at_exit', e[:full_name]
|
|
161
|
+
assert_equal 'Kernel::#at_exit', e[:match_name]
|
|
162
|
+
ensure
|
|
163
|
+
FileUtils.rm_r([prefix, base], :force => true)
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
def test_instance_method_entry_has_no_match_name
|
|
167
|
+
index = @gen.build_index(@db)
|
|
168
|
+
e = find_entry(index, 'Foo#foo')
|
|
169
|
+
assert_not_nil e
|
|
170
|
+
assert_nil e[:match_name]
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
def test_constant_entry_has_no_match_name
|
|
174
|
+
index = @gen.build_index(@db)
|
|
175
|
+
e = find_entry(index, 'Foo::AAA')
|
|
176
|
+
assert_not_nil e
|
|
177
|
+
assert_nil e[:match_name]
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
def test_special_variable_entry_has_no_match_name
|
|
181
|
+
# Guards against a regression of issue #194: "$." already contains a
|
|
182
|
+
# literal "." (from the sigil-less variable name), so if it picked up a
|
|
183
|
+
# match_name too, it would collide with the "$"-prefix handling
|
|
184
|
+
# search_init.js already has (which keeps "$"-queries literal and never
|
|
185
|
+
# goes through the "." -> "::" rewrite at all).
|
|
186
|
+
index = @gen.build_index(@db)
|
|
187
|
+
e = find_entry(index, '$;')
|
|
188
|
+
assert_not_nil e
|
|
189
|
+
assert_nil e[:match_name]
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
def test_merge_preserves_match_name
|
|
193
|
+
e = { name: 'bar', full_name: 'Foo.bar', match_name: 'Foo::bar',
|
|
194
|
+
type: 'class_method', path: 'method/-foo/s/bar.html' }
|
|
195
|
+
merged = BitClust::SearchIndexGenerator.merge([['3.4', [e]]])
|
|
196
|
+
assert_equal 'Foo::bar', merged[0][:match_name]
|
|
197
|
+
end
|
|
198
|
+
|
|
199
|
+
def test_constant_entry
|
|
200
|
+
index = @gen.build_index(@db)
|
|
201
|
+
e = find_entry(index, 'Foo::AAA')
|
|
202
|
+
assert_not_nil e
|
|
203
|
+
assert_equal 'AAA', e[:name]
|
|
204
|
+
assert_equal 'constant', e[:type]
|
|
205
|
+
assert_equal 'method/-foo/c/-a-a-a.html', e[:path]
|
|
206
|
+
end
|
|
207
|
+
|
|
208
|
+
def test_special_variable_keeps_its_sigil_in_name
|
|
209
|
+
# A special variable's "$" is part of how it is written and is the only
|
|
210
|
+
# thing distinguishing it (there is no owning class to qualify it), so it
|
|
211
|
+
# must stay in +name+ for a "$;"-style query to match. See issue #194.
|
|
212
|
+
#
|
|
213
|
+
# The +name+/+type+ assertions below are what issue #194 is about. The
|
|
214
|
+
# +path+ assertion is secondary and filesystem-dependent: @gen defaults to
|
|
215
|
+
# fs_casesensitive: false, so the path is built by encodename_fs ("Kernel"
|
|
216
|
+
# -> "-kernel", ";" -> "=3b"). It is fine to ignore ONLY the path failure if
|
|
217
|
+
# it broke because the fs encoding scheme changed or a case-sensitive build
|
|
218
|
+
# (fs_casesensitive: true, giving "method/Kernel/v/...") is in use -- as long
|
|
219
|
+
# as name/type still hold. A name/type failure is a real regression.
|
|
220
|
+
index = @gen.build_index(@db)
|
|
221
|
+
e = find_entry(index, '$;')
|
|
222
|
+
assert_not_nil e
|
|
223
|
+
assert_equal '$;', e[:name]
|
|
224
|
+
assert_equal 'variable', e[:type]
|
|
225
|
+
assert_equal 'method/-kernel/v/=3b.html', e[:path],
|
|
226
|
+
'filesystem-encoded path (fs_casesensitive: false); ' \
|
|
227
|
+
'ignore only this failure if just the fs encoding/casing changed'
|
|
228
|
+
end
|
|
229
|
+
|
|
230
|
+
def test_special_variable_word_name_keeps_its_sigil
|
|
231
|
+
index = @gen.build_index(@db)
|
|
232
|
+
e = find_entry(index, '$stdout')
|
|
233
|
+
assert_not_nil e
|
|
234
|
+
assert_equal '$stdout', e[:name]
|
|
235
|
+
assert_equal 'variable', e[:type]
|
|
236
|
+
end
|
|
237
|
+
|
|
238
|
+
def test_same_method_name_in_two_classes
|
|
239
|
+
index = @gen.build_index(@db)
|
|
240
|
+
assert_not_nil find_entry(index, 'Foo#foo')
|
|
241
|
+
assert_not_nil find_entry(index, 'Bar#foo')
|
|
242
|
+
end
|
|
243
|
+
|
|
244
|
+
def test_no_duplicate_paths
|
|
245
|
+
index = @gen.build_index(@db)
|
|
246
|
+
paths = index.map { |e| e[:path] }
|
|
247
|
+
assert_equal paths.uniq.size, paths.size, 'index must not contain duplicate paths'
|
|
248
|
+
end
|
|
249
|
+
|
|
250
|
+
def test_document_entry_uses_title_and_slug
|
|
251
|
+
index = @gen.build_index(@db)
|
|
252
|
+
e = index.find { |x| x[:type] == 'document' && x[:path] == 'doc/glossary.html' }
|
|
253
|
+
assert_not_nil e
|
|
254
|
+
assert_equal 'Ruby用語集 (glossary)', e[:full_name]
|
|
255
|
+
assert_equal 'Ruby用語集 (glossary)', e[:name]
|
|
256
|
+
end
|
|
257
|
+
|
|
258
|
+
# {#id}-anchored doc headings (rurema/doctree#2352: keywords like
|
|
259
|
+
# defined?/undef/alias aren't methods, so they never show up in the
|
|
260
|
+
# class/method-derived index -- they only show up via their doc page
|
|
261
|
+
# heading). These need a native md doc tree (copy_doc_md), which is a
|
|
262
|
+
# different ingestion path than the RD @root fixture set up in #setup, so
|
|
263
|
+
# they build their own tiny db per case (mirrors test_copy_doc_md.rb).
|
|
264
|
+
|
|
265
|
+
def build_md_doc_index(files)
|
|
266
|
+
Dir.mktmpdir do |dir|
|
|
267
|
+
files.each do |relpath, content|
|
|
268
|
+
path = File.join(dir, 'manual', 'doc', relpath)
|
|
269
|
+
FileUtils.mkdir_p(File.dirname(path))
|
|
270
|
+
File.write(path, content)
|
|
271
|
+
end
|
|
272
|
+
FileUtils.mkdir_p(File.join(dir, 'manual', 'api'))
|
|
273
|
+
|
|
274
|
+
prefix = File.join(dir, 'db')
|
|
275
|
+
db = BitClust::MethodDatabase.new(prefix)
|
|
276
|
+
db.init
|
|
277
|
+
db.transaction do
|
|
278
|
+
db.propset('version', '3.4')
|
|
279
|
+
db.propset('encoding', 'utf-8')
|
|
280
|
+
end
|
|
281
|
+
db.transaction do
|
|
282
|
+
db.instance_variable_set(:@md_root, File.join(dir, 'manual', 'api'))
|
|
283
|
+
db.__send__(:copy_doc_md)
|
|
284
|
+
end
|
|
285
|
+
# Reopen (like test_copy_doc_md.rb) rather than reuse the writer db,
|
|
286
|
+
# so the index is built from what was actually persisted.
|
|
287
|
+
db2 = BitClust::MethodDatabase.new(prefix)
|
|
288
|
+
BitClust::SearchIndexGenerator.new.build_index(db2)
|
|
289
|
+
end
|
|
290
|
+
end
|
|
291
|
+
|
|
292
|
+
def test_document_heading_entry_for_anchored_heading
|
|
293
|
+
index = build_md_doc_index(
|
|
294
|
+
'spec/def.md' => <<~MD
|
|
295
|
+
# クラス/メソッドの定義
|
|
296
|
+
|
|
297
|
+
本文。
|
|
298
|
+
|
|
299
|
+
#### alias {#alias}
|
|
300
|
+
|
|
301
|
+
alias の説明。
|
|
302
|
+
|
|
303
|
+
#### undef {#undef}
|
|
304
|
+
|
|
305
|
+
undef の説明。
|
|
306
|
+
MD
|
|
307
|
+
)
|
|
308
|
+
e = index.find { |x| x[:type] == 'heading' && x[:name] == 'alias' }
|
|
309
|
+
assert_not_nil e
|
|
310
|
+
assert_equal 'alias (クラス/メソッドの定義)', e[:full_name]
|
|
311
|
+
assert_equal 'doc/spec=2fdef.html#alias', e[:path]
|
|
312
|
+
|
|
313
|
+
e2 = index.find { |x| x[:type] == 'heading' && x[:name] == 'undef' }
|
|
314
|
+
assert_not_nil e2
|
|
315
|
+
assert_equal 'doc/spec=2fdef.html#undef', e2[:path]
|
|
316
|
+
end
|
|
317
|
+
|
|
318
|
+
def test_heading_without_anchor_is_not_indexed
|
|
319
|
+
index = build_md_doc_index(
|
|
320
|
+
'spec/def.md' => <<~MD
|
|
321
|
+
# クラス/メソッドの定義
|
|
322
|
+
|
|
323
|
+
#### 見出し
|
|
324
|
+
|
|
325
|
+
本文。
|
|
326
|
+
MD
|
|
327
|
+
)
|
|
328
|
+
assert_nil index.find { |x| x[:type] == 'heading' }
|
|
329
|
+
end
|
|
330
|
+
|
|
331
|
+
def test_heading_inside_fenced_code_is_not_mistaken_for_a_heading
|
|
332
|
+
# A "# ..." line at column 0 inside a ```ruby sample must not be
|
|
333
|
+
# misdetected as an h1 just because it starts with "#".
|
|
334
|
+
index = build_md_doc_index(
|
|
335
|
+
'spec/control.md' => <<~MD
|
|
336
|
+
# 制御構造
|
|
337
|
+
|
|
338
|
+
#### if {#if}
|
|
339
|
+
|
|
340
|
+
```ruby
|
|
341
|
+
# this is not a heading
|
|
342
|
+
if true
|
|
343
|
+
1
|
|
344
|
+
end
|
|
345
|
+
```
|
|
346
|
+
MD
|
|
347
|
+
)
|
|
348
|
+
headings = index.select { |x| x[:type] == 'heading' }
|
|
349
|
+
assert_equal 1, headings.size
|
|
350
|
+
assert_equal 'if', headings[0][:name]
|
|
351
|
+
end
|
|
352
|
+
|
|
353
|
+
def test_heading_label_strips_inline_code_span_backticks
|
|
354
|
+
index = build_md_doc_index(
|
|
355
|
+
'spec/comment.md' => <<~MD
|
|
356
|
+
# コメント
|
|
357
|
+
|
|
358
|
+
### 文字列リテラルの凍結(`frozen_string_literal`) {#frozen_string_literal}
|
|
359
|
+
|
|
360
|
+
本文。
|
|
361
|
+
MD
|
|
362
|
+
)
|
|
363
|
+
e = index.find { |x| x[:type] == 'heading' }
|
|
364
|
+
assert_not_nil e
|
|
365
|
+
assert_equal '文字列リテラルの凍結(frozen_string_literal)', e[:name]
|
|
366
|
+
end
|
|
367
|
+
|
|
368
|
+
def test_to_js_format
|
|
369
|
+
js = @gen.to_js(@db)
|
|
370
|
+
assert_match(/\Avar search_data = \{/, js)
|
|
371
|
+
assert(js.end_with?(';'), 'to_js output must end with a semicolon')
|
|
372
|
+
|
|
373
|
+
json = js.sub(/\Avar search_data = /, '').sub(/;\z/, '')
|
|
374
|
+
data = JSON.parse(json)
|
|
375
|
+
assert_kind_of Array, data['index']
|
|
376
|
+
assert(data['index'].any? { |e| e['full_name'] == 'Foo#foo' })
|
|
377
|
+
end
|
|
378
|
+
|
|
379
|
+
# 全バージョン対応の検索ページ用: 版ごとの index を versions タグ付きで統合する
|
|
380
|
+
|
|
381
|
+
def entry(over = {})
|
|
382
|
+
{ name: 'Foo', full_name: 'Foo', type: 'class', path: 'class/-foo.html' }.merge(over)
|
|
383
|
+
end
|
|
384
|
+
|
|
385
|
+
def test_merge_dedupes_identical_entries_across_versions
|
|
386
|
+
merged = BitClust::SearchIndexGenerator.merge(
|
|
387
|
+
[['3.4', [entry]], ['3.0', [entry]]])
|
|
388
|
+
assert_equal 1, merged.size
|
|
389
|
+
assert_equal %w[3.0 3.4], merged[0][:versions]
|
|
390
|
+
assert_equal 'Foo', merged[0][:full_name]
|
|
391
|
+
end
|
|
392
|
+
|
|
393
|
+
def test_merge_sorts_versions_numerically
|
|
394
|
+
# "3.10" は文字列比較だと "3.4" より前に来てしまう
|
|
395
|
+
merged = BitClust::SearchIndexGenerator.merge(
|
|
396
|
+
[['4.1', [entry]], ['3.10', [entry]], ['3.4', [entry]]])
|
|
397
|
+
assert_equal %w[3.4 3.10 4.1], merged[0][:versions]
|
|
398
|
+
end
|
|
399
|
+
|
|
400
|
+
def test_merge_keeps_entries_with_different_paths_separate
|
|
401
|
+
a = entry(full_name: 'X#x', name: 'x', type: 'instance_method',
|
|
402
|
+
path: 'method/-x/i/x.html')
|
|
403
|
+
b = a.merge(path: 'method/=x/i/x.html')
|
|
404
|
+
merged = BitClust::SearchIndexGenerator.merge([['3.4', [a]], ['4.1', [b]]])
|
|
405
|
+
assert_equal 2, merged.size
|
|
406
|
+
assert_equal [['3.4'], ['4.1']], merged.map { |e| e[:versions] }
|
|
407
|
+
end
|
|
408
|
+
|
|
409
|
+
def test_merge_orders_entries_by_first_appearance_in_version_order
|
|
410
|
+
# 入力順に依らず「昇順の版を走査して最初に現れた順」で安定させる
|
|
411
|
+
# (generated-documents にコミットされる出力の diff を安定させるため)
|
|
412
|
+
a = entry(full_name: 'A', name: 'A', path: 'class/-a.html')
|
|
413
|
+
b = entry(full_name: 'B', name: 'B', path: 'class/-b.html')
|
|
414
|
+
merged = BitClust::SearchIndexGenerator.merge(
|
|
415
|
+
[['3.4', [a, b]], ['3.0', [b]]])
|
|
416
|
+
assert_equal %w[B A], merged.map { |e| e[:full_name] }
|
|
417
|
+
end
|
|
418
|
+
|
|
419
|
+
def test_merge_folds_module_function_display_to_question_dot
|
|
420
|
+
# bitclust#279 コメント対応: 統合ページ(/ja/search/)で同じ module
|
|
421
|
+
# function が "Kernel.#open"(4.0 より前の版)と "Kernel?.open"
|
|
422
|
+
# (4.0 以降)の2行に分かれて出るのはわかりにくい。表示は現行表記の
|
|
423
|
+
# "?." に畳んで1エントリに合流させる(name/type/path/match_name は
|
|
424
|
+
# 表記に依らず同一なので、full_name さえ畳めばキーが一致する)。
|
|
425
|
+
# 単一版ページの表示はその版の表記のまま(build_index 側は触らない)。
|
|
426
|
+
pre40 = { name: 'open', full_name: 'Kernel.#open', type: 'class_method',
|
|
427
|
+
path: 'method/-kernel/m/open.html', match_name: 'Kernel::#open' }
|
|
428
|
+
post40 = { name: 'open', full_name: 'Kernel?.open', type: 'class_method',
|
|
429
|
+
path: 'method/-kernel/m/open.html', match_name: 'Kernel::#open' }
|
|
430
|
+
merged = BitClust::SearchIndexGenerator.merge(
|
|
431
|
+
[['3.4', [pre40]], ['4.0', [post40]]])
|
|
432
|
+
assert_equal 1, merged.size
|
|
433
|
+
assert_equal 'Kernel?.open', merged[0][:full_name]
|
|
434
|
+
assert_equal %w[3.4 4.0], merged[0][:versions]
|
|
435
|
+
assert_equal 'Kernel::#open', merged[0][:match_name]
|
|
436
|
+
end
|
|
437
|
+
|
|
438
|
+
def test_merge_folds_display_even_when_only_old_notation_exists
|
|
439
|
+
# 4.0 以降に存在しないまま消えたメソッドでも、統合ページの表示は
|
|
440
|
+
# "?." に揃える(znz さんの依頼は「?. だけ出てくるように」)
|
|
441
|
+
pre40 = { name: 'gone', full_name: 'Kernel.#gone', type: 'class_method',
|
|
442
|
+
path: 'method/-kernel/m/gone.html', match_name: 'Kernel::#gone' }
|
|
443
|
+
merged = BitClust::SearchIndexGenerator.merge([['3.4', [pre40]]])
|
|
444
|
+
assert_equal 'Kernel?.gone', merged[0][:full_name]
|
|
445
|
+
end
|
|
446
|
+
|
|
447
|
+
def test_merge_keeps_dot_hash_in_entries_without_match_name
|
|
448
|
+
# ".#" を字面に含んでいても match_name を持たないエントリ(散文
|
|
449
|
+
# 見出しなど)は表示を畳まない — 見出しはページ本文の字面と一致
|
|
450
|
+
# していることに意味がある
|
|
451
|
+
heading = { name: '.#', full_name: '.# (プログラム・文・式)', type: 'heading',
|
|
452
|
+
path: 'doc/symref.html#dot-hash' }
|
|
453
|
+
merged = BitClust::SearchIndexGenerator.merge([['3.4', [heading]]])
|
|
454
|
+
assert_equal '.# (プログラム・文・式)', merged[0][:full_name]
|
|
455
|
+
end
|
|
456
|
+
|
|
457
|
+
def test_merged_js_format
|
|
458
|
+
js = BitClust::SearchIndexGenerator.merged_js([['3.4', [entry]]])
|
|
459
|
+
assert_match(/\Avar search_data = \{/, js)
|
|
460
|
+
assert(js.end_with?(';'))
|
|
461
|
+
data = JSON.parse(js.sub(/\Avar search_data = /, '').sub(/;\z/, ''))
|
|
462
|
+
assert_equal ['3.4'], data['index'][0]['versions']
|
|
463
|
+
assert_equal 'Foo', data['index'][0]['full_name']
|
|
464
|
+
end
|
|
465
|
+
|
|
466
|
+
private
|
|
467
|
+
|
|
468
|
+
def setup_files
|
|
469
|
+
FileUtils.mkdir_p("#{@root}/_builtin")
|
|
470
|
+
|
|
471
|
+
File.open("#{@root}/LIBRARIES", 'w+') do |file|
|
|
472
|
+
file.puts '_builtin'
|
|
473
|
+
end
|
|
474
|
+
|
|
475
|
+
File.open("#{@root}/_builtin.rd", 'w+') do |file|
|
|
476
|
+
file.puts <<'HERE'
|
|
477
|
+
description
|
|
478
|
+
|
|
479
|
+
= class Foo < Object
|
|
480
|
+
description
|
|
481
|
+
== Singleton Methods
|
|
482
|
+
--- bar
|
|
483
|
+
== Instance Methods
|
|
484
|
+
--- foo
|
|
485
|
+
== Constants
|
|
486
|
+
--- AAA
|
|
487
|
+
= class Bar < Object
|
|
488
|
+
== Instance Methods
|
|
489
|
+
--- foo
|
|
490
|
+
= module Kernel
|
|
491
|
+
description
|
|
492
|
+
== Module Functions
|
|
493
|
+
--- at_exit{ ... } -> Proc
|
|
494
|
+
aaa
|
|
495
|
+
== Special Variables
|
|
496
|
+
--- $; -> String | nil
|
|
497
|
+
区切り文字。
|
|
498
|
+
--- $stdout -> IO
|
|
499
|
+
標準出力。
|
|
500
|
+
|
|
501
|
+
HERE
|
|
502
|
+
end
|
|
503
|
+
|
|
504
|
+
# Prose doc pages are loaded from <stdlibtree>/../../doc/**/*.rd
|
|
505
|
+
docdir = "#{@base}/refm/doc"
|
|
506
|
+
FileUtils.mkdir_p(docdir)
|
|
507
|
+
File.open("#{docdir}/glossary.rd", 'w+') do |file|
|
|
508
|
+
file.puts '= Ruby用語集'
|
|
509
|
+
file.puts
|
|
510
|
+
file.puts '用語の説明。'
|
|
511
|
+
end
|
|
512
|
+
end
|
|
513
|
+
end
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
require 'test/unit'
|
|
2
|
+
require 'bitclust'
|
|
3
|
+
require 'bitclust/screen'
|
|
4
|
+
|
|
5
|
+
# Covers data/bitclust/template/search: the dynamic CGI search-results page
|
|
6
|
+
# rendered by `bitclust server`'s /search endpoint (SearchScreen). Distinct
|
|
7
|
+
# from the static client-side search index (SearchIndexGenerator, covered by
|
|
8
|
+
# test_search_index_generator.rb) -- this one builds its "Kernel.#mf"-style
|
|
9
|
+
# label directly in the template from klass.name + typemark + signature.
|
|
10
|
+
#
|
|
11
|
+
# bitclust#250: Ruby 4.0 以降のドキュメントでは module function の表記を
|
|
12
|
+
# 独自の「.#」から「?.」に変える(表示のみ、識別子は変えない)。
|
|
13
|
+
class TestSearchScreenModuleFunctionDisplay < Test::Unit::TestCase
|
|
14
|
+
SRC = <<'HERE'
|
|
15
|
+
= module Kernel
|
|
16
|
+
description
|
|
17
|
+
== Module Functions
|
|
18
|
+
--- mf
|
|
19
|
+
|
|
20
|
+
説明
|
|
21
|
+
HERE
|
|
22
|
+
|
|
23
|
+
def render(version)
|
|
24
|
+
_lib, db = BitClust::RRDParser.parse(SRC, 'testlib', {'version' => version})
|
|
25
|
+
entry = db.get_method(BitClust::MethodSpec.parse('Kernel.#mf'))
|
|
26
|
+
datadir = File.expand_path('../data/bitclust', __dir__)
|
|
27
|
+
manager = BitClust::ScreenManager.new(
|
|
28
|
+
:templatedir => "#{datadir}/template",
|
|
29
|
+
:catalogdir => "#{datadir}/catalog",
|
|
30
|
+
:encoding => 'utf-8',
|
|
31
|
+
:default_encoding => 'utf-8',
|
|
32
|
+
:base_url => '',
|
|
33
|
+
:target_version => version
|
|
34
|
+
)
|
|
35
|
+
manager.search_screen([entry], :database => db, :q => 'mf', :elapsed_time => 0.0).body
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def test_module_function_shows_dot_hash_before_4_0
|
|
39
|
+
html = render('3.4')
|
|
40
|
+
assert_include(html, 'Kernel.#mf')
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def test_module_function_switches_to_question_dot_at_4_0
|
|
44
|
+
html = render('4.0')
|
|
45
|
+
assert_include(html, 'Kernel?.mf')
|
|
46
|
+
assert_not_include(html, 'Kernel.#mf')
|
|
47
|
+
end
|
|
48
|
+
end
|
data/test/test_searcher.rb
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
require "test/unit"
|
|
2
2
|
require "bitclust"
|
|
3
3
|
require "bitclust/searcher"
|
|
4
|
+
require "fileutils"
|
|
5
|
+
require "tmpdir"
|
|
4
6
|
|
|
5
7
|
class TestTerminalView < Test::Unit::TestCase
|
|
6
8
|
include BitClust
|
|
@@ -19,3 +21,133 @@ class TestTerminalView < Test::Unit::TestCase
|
|
|
19
21
|
assert_empty err
|
|
20
22
|
end
|
|
21
23
|
end
|
|
24
|
+
|
|
25
|
+
class TestSearcherWindowsDrivePath < Test::Unit::TestCase
|
|
26
|
+
include BitClust
|
|
27
|
+
|
|
28
|
+
ENV_KEYS = %w[REFE2_SERVER BITCLUST_SERVER REFE2_DATADIR BITCLUST_DATADIR]
|
|
29
|
+
|
|
30
|
+
def setup
|
|
31
|
+
@saved_env = {}
|
|
32
|
+
ENV_KEYS.each {|key| @saved_env[key] = ENV.delete(key) }
|
|
33
|
+
@saved_dir = Dir.pwd
|
|
34
|
+
@searcher = Searcher.new
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def teardown
|
|
38
|
+
Dir.chdir(@saved_dir)
|
|
39
|
+
ENV_KEYS.each do |key|
|
|
40
|
+
if @saved_env[key]
|
|
41
|
+
ENV[key] = @saved_env[key]
|
|
42
|
+
else
|
|
43
|
+
ENV.delete(key)
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def test_windows_drive_path_predicate
|
|
49
|
+
assert_true @searcher.send(:windows_drive_path?, "G:/Users/foo/.bitclust/db-2.2.0")
|
|
50
|
+
assert_true @searcher.send(:windows_drive_path?, 'C:\Users\foo\.bitclust\db-2.2.0')
|
|
51
|
+
assert_false @searcher.send(:windows_drive_path?, "/home/foo/.bitclust/db-2.2.0")
|
|
52
|
+
assert_false @searcher.send(:windows_drive_path?, "druby://localhost:10001")
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def test_drive_path_uri_keeps_drive_letter
|
|
56
|
+
uri = @searcher.send(:drive_path_uri, "G:/Users/foo/.bitclust/db-2.2.0")
|
|
57
|
+
assert_equal "file", uri.scheme
|
|
58
|
+
assert_equal "G:/Users/foo/.bitclust/db-2.2.0", uri.path
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def test_find_dblocation_keeps_windows_drive_letter
|
|
62
|
+
with_fake_datadir("G:/Users/foo/.bitclust/db-2.2.0") do |relative_path|
|
|
63
|
+
ENV["BITCLUST_DATADIR"] = relative_path
|
|
64
|
+
location = @searcher.send(:find_dblocation)
|
|
65
|
+
assert_equal "file", location.scheme
|
|
66
|
+
assert_equal relative_path, location.path
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def test_find_dblocation_keeps_unix_absolute_path
|
|
71
|
+
Dir.mktmpdir do |dir|
|
|
72
|
+
datadir = File.join(dir, ".bitclust", "db-2.2.0")
|
|
73
|
+
FileUtils.mkdir_p(datadir)
|
|
74
|
+
FileUtils.touch(File.join(datadir, "properties"))
|
|
75
|
+
ENV["BITCLUST_DATADIR"] = datadir
|
|
76
|
+
location = @searcher.send(:find_dblocation)
|
|
77
|
+
assert_equal "file", location.scheme
|
|
78
|
+
assert_equal datadir, location.path
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def test_database_option_keeps_windows_drive_letter
|
|
83
|
+
@searcher.parser.parse!(["--database=G:/Users/foo/.bitclust/db-2.2.0"])
|
|
84
|
+
dblocation = @searcher.instance_variable_get(:@dblocation)
|
|
85
|
+
assert_equal "file", dblocation.scheme
|
|
86
|
+
assert_equal "G:/Users/foo/.bitclust/db-2.2.0", dblocation.path
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
private
|
|
90
|
+
|
|
91
|
+
# datadir/properties を tmpdir 内に作り、tmpdir へ chdir したうえで
|
|
92
|
+
# datadir までの相対パス(ドライブレターを含む)を渡す。":" は Unix の
|
|
93
|
+
# ファイル名として有効な文字なので、Linux 上でも "G:" というディレク
|
|
94
|
+
# トリを作ってドライブレター付きパスの再現ができる
|
|
95
|
+
def with_fake_datadir(relative_path)
|
|
96
|
+
Dir.mktmpdir do |dir|
|
|
97
|
+
datadir = File.join(dir, *relative_path.split("/"))
|
|
98
|
+
FileUtils.mkdir_p(datadir)
|
|
99
|
+
FileUtils.touch(File.join(datadir, "properties"))
|
|
100
|
+
Dir.chdir(dir) do
|
|
101
|
+
yield relative_path
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
# refe の module_function 表示(bitclust#297)。
|
|
108
|
+
# HTML 側(#282)と同じく、DB のバージョンが 4.0 以降なら
|
|
109
|
+
# "Foo.#baz" ではなく "Foo?.baz" と表示する。
|
|
110
|
+
class TestSearcherModuleFunctionDisplay < Test::Unit::TestCase
|
|
111
|
+
include BitClust
|
|
112
|
+
|
|
113
|
+
def record_for(version)
|
|
114
|
+
db = MethodDatabase.dummy("version" => version)
|
|
115
|
+
spec = MethodSpec.parse("Foo.#baz")
|
|
116
|
+
SearchResult::Record.new(db, spec, spec)
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
def test_names_folds_module_function_typemark_for_40
|
|
120
|
+
assert_equal ["Foo?.baz"], record_for("4.0").names
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
def test_names_keeps_typemark_before_40
|
|
124
|
+
assert_equal ["Foo.#baz"], record_for("3.4").names
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
def test_names_without_db_version_keeps_typemark
|
|
128
|
+
spec = MethodSpec.parse("Foo.#baz")
|
|
129
|
+
assert_equal ["Foo.#baz"], SearchResult::Record.new(nil, spec, spec).names
|
|
130
|
+
end
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
# refe のクエリ側も 4.0 以降の表示形式 "Foo?.baz" を受け付ける(bitclust#297)
|
|
134
|
+
class TestSearcherModuleFunctionQuery < Test::Unit::TestCase
|
|
135
|
+
include BitClust
|
|
136
|
+
|
|
137
|
+
def parse(pat)
|
|
138
|
+
Searcher.new.send(:parse_method_spec_pattern, pat)
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
def test_question_dot_pattern
|
|
142
|
+
assert_equal ["Foo", ".#", "baz"], parse("Foo?.baz")
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
def test_dot_hash_pattern_still_works
|
|
146
|
+
assert_equal ["Foo", ".#", "baz"], parse("Foo.#baz")
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
def test_predicate_method_names_unaffected
|
|
150
|
+
assert_equal ["Foo", "#", "empty?"], parse("Foo#empty?")
|
|
151
|
+
assert_equal ["Foo", ".", "b?"], parse("Foo.b?")
|
|
152
|
+
end
|
|
153
|
+
end
|