bitclust-core 0.5.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.
Files changed (127) hide show
  1. data/ChangeLog +2907 -0
  2. data/Gemfile +7 -0
  3. data/README +21 -0
  4. data/Rakefile +20 -0
  5. data/bin/bitclust +14 -0
  6. data/bin/refe +36 -0
  7. data/bitclust-dev.gemspec +33 -0
  8. data/bitclust.gemspec +30 -0
  9. data/config.in +23 -0
  10. data/config.ru +48 -0
  11. data/config.ru.sample +31 -0
  12. data/data/bitclust/catalog/ja_JP.EUC-JP +78 -0
  13. data/data/bitclust/catalog/ja_JP.UTF-8 +78 -0
  14. data/data/bitclust/template.lillia/class +98 -0
  15. data/data/bitclust/template.lillia/class-index +28 -0
  16. data/data/bitclust/template.lillia/doc +48 -0
  17. data/data/bitclust/template.lillia/layout +19 -0
  18. data/data/bitclust/template.lillia/library +129 -0
  19. data/data/bitclust/template.lillia/library-index +32 -0
  20. data/data/bitclust/template.lillia/method +20 -0
  21. data/data/bitclust/template.lillia/rd_file +6 -0
  22. data/data/bitclust/template.offline/class +67 -0
  23. data/data/bitclust/template.offline/class-index +28 -0
  24. data/data/bitclust/template.offline/doc +13 -0
  25. data/data/bitclust/template.offline/function +22 -0
  26. data/data/bitclust/template.offline/function-index +24 -0
  27. data/data/bitclust/template.offline/layout +18 -0
  28. data/data/bitclust/template.offline/library +87 -0
  29. data/data/bitclust/template.offline/library-index +32 -0
  30. data/data/bitclust/template.offline/method +21 -0
  31. data/data/bitclust/template.offline/rd_file +6 -0
  32. data/data/bitclust/template/class +133 -0
  33. data/data/bitclust/template/class-index +30 -0
  34. data/data/bitclust/template/doc +14 -0
  35. data/data/bitclust/template/function +21 -0
  36. data/data/bitclust/template/function-index +25 -0
  37. data/data/bitclust/template/layout +19 -0
  38. data/data/bitclust/template/library +89 -0
  39. data/data/bitclust/template/library-index +35 -0
  40. data/data/bitclust/template/method +24 -0
  41. data/data/bitclust/template/opensearchdescription +10 -0
  42. data/data/bitclust/template/search +57 -0
  43. data/lib/bitclust.rb +9 -0
  44. data/lib/bitclust/app.rb +129 -0
  45. data/lib/bitclust/classentry.rb +425 -0
  46. data/lib/bitclust/compat.rb +39 -0
  47. data/lib/bitclust/completion.rb +531 -0
  48. data/lib/bitclust/crossrubyutils.rb +91 -0
  49. data/lib/bitclust/database.rb +181 -0
  50. data/lib/bitclust/docentry.rb +83 -0
  51. data/lib/bitclust/entry.rb +223 -0
  52. data/lib/bitclust/exception.rb +38 -0
  53. data/lib/bitclust/functiondatabase.rb +115 -0
  54. data/lib/bitclust/functionentry.rb +81 -0
  55. data/lib/bitclust/functionreferenceparser.rb +76 -0
  56. data/lib/bitclust/htmlutils.rb +80 -0
  57. data/lib/bitclust/interface.rb +87 -0
  58. data/lib/bitclust/libraryentry.rb +211 -0
  59. data/lib/bitclust/lineinput.rb +165 -0
  60. data/lib/bitclust/messagecatalog.rb +95 -0
  61. data/lib/bitclust/methoddatabase.rb +401 -0
  62. data/lib/bitclust/methodentry.rb +202 -0
  63. data/lib/bitclust/methodid.rb +209 -0
  64. data/lib/bitclust/methodsignature.rb +82 -0
  65. data/lib/bitclust/nameutils.rb +236 -0
  66. data/lib/bitclust/parseutils.rb +60 -0
  67. data/lib/bitclust/preprocessor.rb +273 -0
  68. data/lib/bitclust/rdcompiler.rb +507 -0
  69. data/lib/bitclust/refsdatabase.rb +66 -0
  70. data/lib/bitclust/requesthandler.rb +330 -0
  71. data/lib/bitclust/ridatabase.rb +349 -0
  72. data/lib/bitclust/rrdparser.rb +522 -0
  73. data/lib/bitclust/runner.rb +143 -0
  74. data/lib/bitclust/screen.rb +554 -0
  75. data/lib/bitclust/searcher.rb +518 -0
  76. data/lib/bitclust/server.rb +59 -0
  77. data/lib/bitclust/simplesearcher.rb +84 -0
  78. data/lib/bitclust/subcommand.rb +746 -0
  79. data/lib/bitclust/textutils.rb +51 -0
  80. data/lib/bitclust/version.rb +3 -0
  81. data/packer.rb +224 -0
  82. data/refe2.gemspec +29 -0
  83. data/server.exe +0 -0
  84. data/server.exy +159 -0
  85. data/server.rb +10 -0
  86. data/setup.rb +1596 -0
  87. data/standalone.rb +193 -0
  88. data/test/run_test.rb +15 -0
  89. data/test/test_bitclust.rb +81 -0
  90. data/test/test_entry.rb +39 -0
  91. data/test/test_functiondatabase.rb +55 -0
  92. data/test/test_libraryentry.rb +31 -0
  93. data/test/test_methoddatabase.rb +81 -0
  94. data/test/test_methodsignature.rb +14 -0
  95. data/test/test_nameutils.rb +324 -0
  96. data/test/test_preprocessor.rb +84 -0
  97. data/test/test_rdcompiler.rb +534 -0
  98. data/test/test_refsdatabase.rb +76 -0
  99. data/test/test_rrdparser.rb +26 -0
  100. data/test/test_runner.rb +102 -0
  101. data/test/test_simplesearcher.rb +48 -0
  102. data/theme/default/images/external.png +0 -0
  103. data/theme/default/rurema.png +0 -0
  104. data/theme/default/style.css +288 -0
  105. data/theme/default/test.css +254 -0
  106. data/theme/lillia/rurema.png +0 -0
  107. data/theme/lillia/style.css +331 -0
  108. data/theme/lillia/test.css +254 -0
  109. data/tools/bc-ancestors.rb +153 -0
  110. data/tools/bc-checkparams.rb +246 -0
  111. data/tools/bc-classes.rb +80 -0
  112. data/tools/bc-convert.rb +165 -0
  113. data/tools/bc-list.rb +63 -0
  114. data/tools/bc-methods.rb +171 -0
  115. data/tools/bc-preproc.rb +42 -0
  116. data/tools/bc-rdoc.rb +343 -0
  117. data/tools/bc-tochm.rb +301 -0
  118. data/tools/bc-tohtml.rb +125 -0
  119. data/tools/bc-tohtmlpackage.rb +241 -0
  120. data/tools/check-signature.rb +19 -0
  121. data/tools/forall-ruby.rb +20 -0
  122. data/tools/gencatalog.rb +69 -0
  123. data/tools/statrefm.rb +98 -0
  124. data/tools/stattodo.rb +150 -0
  125. data/tools/update-database.rb +146 -0
  126. data/view.cgi +6 -0
  127. metadata +222 -0
@@ -0,0 +1,518 @@
1
+ #
2
+ # bitclust/searcher.rb
3
+ #
4
+ # Copyright (C) 2006-2007 Minero Aoki
5
+ #
6
+ # This program is free software.
7
+ # You can distribute/modify this program under the Ruby License.
8
+ #
9
+
10
+ require 'bitclust/methoddatabase'
11
+ require 'bitclust/functiondatabase'
12
+ require 'bitclust/nameutils'
13
+ require 'bitclust/methodid'
14
+ require 'bitclust/exception'
15
+ require 'uri'
16
+ require 'rbconfig'
17
+ require 'optparse'
18
+ require 'nkf'
19
+
20
+ module BitClust
21
+
22
+ class Searcher
23
+
24
+ include NameUtils
25
+
26
+ def initialize
27
+ cmd = File.basename($0, '.*')
28
+ @dblocation = nil
29
+ @name = (/\Abitclust/ =~ cmd ? 'bitclust search' : 'refe')
30
+ @describe_all = false
31
+ @linep = false
32
+ @encoding = nil
33
+ @target_type = nil
34
+ @listen_url = nil
35
+ @foreground = false
36
+ @parser = OptionParser.new {|opt|
37
+ opt.banner = "Usage: #{@name} <pattern>"
38
+ unless cmd == 'bitclust'
39
+ opt.on('-d', '--database=URL', "Database location (default: #{dblocation_name()})") {|loc|
40
+ url = (/:/ =~ loc) ? loc : "file://#{File.expand_path(loc)}"
41
+ @dblocation = URI.parse(url)
42
+ }
43
+ opt.on('--server=URL', 'Spawns BitClust database server and listen URL. Requires --database option with local path.') {|url|
44
+ require 'bitclust/server' # require here for speed
45
+ @listen_url = url
46
+ }
47
+ opt.on('--foreground', 'Do not become daemon (for debug)') {
48
+ @foreground = true
49
+ }
50
+ end
51
+ opt.on('-a', '--all', 'Prints descriptions for all matched entries.') {
52
+ @describe_all = true
53
+ }
54
+ opt.on('-l', '--line', 'Prints one entry in one line.') {
55
+ @linep = true
56
+ }
57
+ opt.on('-e', '--encoding=ENCODING', 'Select encoding.') {|enc|
58
+ @encoding = enc
59
+ }
60
+ opt.on('--class', 'Search class or module.') {
61
+ @target_type = :class
62
+ }
63
+ opt.on('--version', 'Prints version and quit.') {
64
+ if cmd == 'bitclust'
65
+ puts "BitClust -- Next generation reference manual interface"
66
+ exit 1
67
+ else
68
+ puts "ReFe version 2"
69
+ exit 1
70
+ end
71
+ }
72
+ opt.on('--help', 'Prints this message and quit.') {
73
+ puts opt.help
74
+ exit 0
75
+ }
76
+ }
77
+ end
78
+
79
+ attr_reader :parser
80
+
81
+ def parse(argv)
82
+ @parser.parse! argv
83
+ if @listen_url # server mode
84
+ server_mode_check argv
85
+ else
86
+ refe_mode_check argv
87
+ end
88
+ end
89
+
90
+ def exec(db, argv)
91
+ if @listen_url
92
+ spawn_server db
93
+ else
94
+ search_pattern db, argv
95
+ end
96
+ end
97
+
98
+ private
99
+
100
+ def server_mode_check(argv)
101
+ if @dblocation
102
+ unless @dblocation.scheme == 'file'
103
+ $stderr.puts "Give local path to --database option on server mode"
104
+ exit 1
105
+ end
106
+ else
107
+ unless dbpath()
108
+ $stderr.puts "no local database given; use --database option with local database path"
109
+ exit 1
110
+ end
111
+ end
112
+ unless argv.empty?
113
+ $stderr.puts "too many arguments"
114
+ exit 1
115
+ end
116
+ end
117
+
118
+ def refe_mode_check(argv)
119
+ case @target_type
120
+ when :class
121
+ unless argv.size == 1
122
+ $stderr.puts "--class option requires only 1 argument"
123
+ exit 1
124
+ end
125
+ else
126
+ if argv.size > 3
127
+ $stderr.puts "too many arguments (#{argv.size} for 2)"
128
+ exit 1
129
+ end
130
+ end
131
+ # FIXME
132
+ #compiler = RDCompiler::Text.new
133
+ compiler = Plain.new
134
+ @view = TerminalView.new(compiler,
135
+ {:describe_all => @describe_all,
136
+ :line => @linep,
137
+ :encoding => @encoding})
138
+ end
139
+
140
+ def spawn_server(db)
141
+ Server.new(new_local_database(db)).listen @listen_url, @foreground
142
+ end
143
+
144
+ def new_local_database(db)
145
+ return db if db
146
+ path = @dblocation ? @dblocation.path : dbpath()
147
+ MethodDatabase.new(path)
148
+ end
149
+
150
+ def new_database
151
+ db = MethodDatabase.connect(@dblocation || dblocation())
152
+ @view.database = db if @view
153
+ db
154
+ end
155
+
156
+ def dblocation_name
157
+ find_dblocation() or 'NONE'
158
+ end
159
+
160
+ def dblocation
161
+ find_dblocation() or
162
+ raise InvalidDatabase, "database not exist or invalid database"
163
+ end
164
+
165
+ def find_dblocation
166
+ %w( REFE2_SERVER BITCLUST_SERVER ).each do |key|
167
+ return URI.parse(ENV[key]) if ENV[key]
168
+ end
169
+ if path = dbpath()
170
+ URI.parse("file://#{path}")
171
+ else
172
+ nil
173
+ end
174
+ end
175
+
176
+ def dbpath
177
+ env_dbpath() || default_dbpath()
178
+ end
179
+
180
+ def env_dbpath
181
+ [ 'REFE2_DATADIR', 'BITCLUST_DATADIR' ].each do |key|
182
+ if ENV.key?(key)
183
+ unless MethodDatabase.datadir?(ENV[key])
184
+ raise InvalidDatabase, "environment variable #{key} given but #{ENV[key]} is not a valid BitClust database"
185
+ end
186
+ return ENV[key]
187
+ end
188
+ end
189
+ nil
190
+ end
191
+
192
+ def default_dbpath
193
+ datadir = ::RbConfig::CONFIG['datadir']
194
+ [ "#{datadir}/refe2", "#{datadir}/bitclust" ].each do |path|
195
+ return path if MethodDatabase.datadir?(path)
196
+ end
197
+ nil
198
+ end
199
+
200
+ def search_pattern(db, argv)
201
+ db ||= new_database()
202
+ @view.database ||= db if @view
203
+ case @target_type || db
204
+ when :class
205
+ find_class db, argv[0]
206
+ when FunctionDatabase
207
+ case argv.size
208
+ when 0
209
+ show_all_functions db
210
+ when 1
211
+ find_function db, argv[0]
212
+ else
213
+ raise "must not happen: #{argv.size}"
214
+ end
215
+ else
216
+ case argv.size
217
+ when 0
218
+ show_all_classes db
219
+ when 1
220
+ find_class_or_method db, argv[0]
221
+ when 2
222
+ c, m = *argv
223
+ find_method db, c, nil, m
224
+ when 3
225
+ c, t, m = *argv
226
+ check_method_type t
227
+ find_method db, c, t, m
228
+ else
229
+ raise "must not happen: #{argv.size}"
230
+ end
231
+ end
232
+ end
233
+
234
+ def show_all_classes(db)
235
+ @view.show_class db.classes
236
+ end
237
+
238
+ def show_all_functions(db)
239
+ @view.show_function db.functions
240
+ end
241
+
242
+ def find_class(db, c)
243
+ @view.show_class db.search_classes(c)
244
+ end
245
+
246
+ def find_method(db, c, t, m)
247
+ @view.show_method db.search_methods(MethodNamePattern.new(c, t, m))
248
+ end
249
+
250
+ def find_function(db, f)
251
+ @view.show_function db.search_functions(f)
252
+ end
253
+
254
+ def check_method_type(t)
255
+ if t == '$'
256
+ raise InvalidKey, "'$' cannot be used as method type"
257
+ end
258
+ unless typemark?(t)
259
+ raise InvalidKey, "unknown method type: #{t.inspect}"
260
+ end
261
+ end
262
+
263
+ def find_class_or_method(db, pattern)
264
+ case pattern
265
+ when /\A\$/ # Special variable.
266
+ find_method db, 'Kernel', '$', pattern.sub(/\A\$/, '')
267
+ when /[\#,]\.|\.[\#,]|[\#\.\,]/ # method spec
268
+ find_method db, *parse_method_spec_pattern(pattern)
269
+ when /::/ # Class name or constant name.
270
+ find_constant db, pattern
271
+ when /\A[A-Z]/ # Method name or class name, but class name is better.
272
+ begin
273
+ find_class db, pattern
274
+ rescue ClassNotFound
275
+ find_method db, nil, nil, pattern
276
+ end
277
+ else # No hint. Method name or class name.
278
+ begin
279
+ find_method db, nil, nil, pattern
280
+ rescue MethodNotFound
281
+ find_class db, pattern
282
+ end
283
+ end
284
+ end
285
+
286
+ def find_constant(db, pattern)
287
+ # class lookup is faster
288
+ find_class db, pattern
289
+ rescue ClassNotFound
290
+ cnames = pattern.split(/::/)
291
+ name = cnames.pop
292
+ find_method db, cnames.join('::'), '::', name
293
+ end
294
+
295
+ def parse_method_spec_pattern(pat)
296
+ _m, _t, _c = pat.reverse.split(/([\#,]\.|\.[\#,]|[\#\.\,])/, 2)
297
+ c = _c.reverse
298
+ t = _t.tr(',', '#').sub(/\#\./, '.#')
299
+ m = _m.reverse
300
+ return c, t, m
301
+ end
302
+
303
+ end
304
+
305
+
306
+ class Plain
307
+ def compile(src)
308
+ src
309
+ end
310
+ end
311
+
312
+
313
+ class TerminalView
314
+
315
+ def initialize(compiler, opts)
316
+ @compiler = compiler
317
+ @describe_all = opts[:describe_all]
318
+ @line = opts[:line]
319
+ @encoding = opts[:encoding]
320
+ @database = nil
321
+ end
322
+
323
+ attr_accessor :database
324
+
325
+ def show_class(cs)
326
+ if cs.size == 1
327
+ if @line
328
+ print_names [cs.first.label]
329
+ else
330
+ describe_class cs.first
331
+ end
332
+ else
333
+ if @describe_all
334
+ cs.sort.each do |c|
335
+ describe_class c
336
+ end
337
+ else
338
+ print_names cs.map {|c| c.labels }.flatten
339
+ end
340
+ end
341
+ end
342
+
343
+ def show_method(result)
344
+ if result.determined?
345
+ if @line
346
+ print_names result.names
347
+ else
348
+ describe_method result.record
349
+ end
350
+ else
351
+ if @describe_all
352
+ result.each_record do |rec|
353
+ describe_method rec
354
+ end
355
+ else
356
+ print_names result.names
357
+ end
358
+ end
359
+ end
360
+
361
+ def show_function(fs)
362
+ if fs.size == 1
363
+ if @line
364
+ print_names [fs.first.label]
365
+ else
366
+ describe_function fs.first
367
+ end
368
+ else
369
+ if @describe_all
370
+ fs.sort.each do |f|
371
+ describe_function f
372
+ end
373
+ else
374
+ print_names fs.map {|f| f.label }
375
+ end
376
+ end
377
+ end
378
+
379
+ private
380
+
381
+ def print_names(names)
382
+ if @line
383
+ names.sort.each do |n|
384
+ puts n
385
+ end
386
+ else
387
+ print_packed_names names.sort
388
+ end
389
+ end
390
+
391
+ def print_packed_names(names)
392
+ max = terminal_column()
393
+ buf = ''
394
+ names.each do |name|
395
+ if buf.size + name.size + 1 > max
396
+ if buf.empty?
397
+ puts name
398
+ next
399
+ end
400
+ puts buf
401
+ buf = ''
402
+ end
403
+ buf << name << ' '
404
+ end
405
+ puts buf unless buf.empty?
406
+ end
407
+
408
+ def terminal_column
409
+ (ENV['COLUMNS'] || 70).to_i
410
+ end
411
+
412
+ def describe_class(c)
413
+ if c.alias?
414
+ describe_class(c.aliasof)
415
+ return
416
+ end
417
+
418
+ unless c.library.name == '_builtin'
419
+ puts "require '#{c.library.name}'"
420
+ puts
421
+ end
422
+ puts "#{c.type} #{c.name}#{c.superclass ? " < #{c.superclass.name}" : ''}"
423
+ unless c.included.empty?
424
+ puts
425
+ c.included.each do |mod|
426
+ puts "include #{mod.name}"
427
+ end
428
+ end
429
+ unless c.aliases.empty?
430
+ puts
431
+ c.aliases.each do |al|
432
+ puts "alias #{al.name}"
433
+ end
434
+ end
435
+ unless c.source.strip.empty?
436
+ puts
437
+ puts @compiler.compile(c.source.strip)
438
+ end
439
+ end
440
+
441
+ def describe_method(rec)
442
+ unless rec.entry.library.name == '_builtin'
443
+ puts "require '#{rec.entry.library.name}'"
444
+ end
445
+ # FIXME: replace method signature by method spec
446
+ if rec.method_of_alias_class?
447
+ rec.specs.each do |spec|
448
+ puts "#{rec.origin.klass}#{rec.origin.type}#{spec.method} (#{spec.klass} is an alias of #{rec.origin.klass})"
449
+ end
450
+ elsif rec.inherited_method?
451
+ rec.specs.each do |spec|
452
+ puts "#{spec.klass}\t< #{rec.origin.klass}#{rec.origin.type}#{spec.method}"
453
+ end
454
+ else
455
+ rec.names.each do |name|
456
+ puts name
457
+ end
458
+ end
459
+
460
+ puts @compiler.compile(rec.entry.source.strip)
461
+ puts
462
+ end
463
+
464
+ def describe_function(f)
465
+ puts "#{f.type_label} #{f.name}"
466
+ puts f.header
467
+ puts @compiler.compile(f.source.strip)
468
+ puts
469
+ end
470
+
471
+ def puts(*args)
472
+ super(*args.collect {|arg| convert(arg)})
473
+ end
474
+
475
+ def convert(string)
476
+ return string if @database.nil?
477
+ _output_encoding = output_encoding
478
+ return string if _output_encoding.nil?
479
+ input_nkf_option = encoding_to_nkf_option(@database.encoding)
480
+ output_nkf_option = encoding_to_nkf_option(_output_encoding)
481
+ if input_nkf_option and output_nkf_option
482
+ NKF.nkf("-#{input_nkf_option.upcase}#{output_nkf_option}", string)
483
+ else
484
+ string
485
+ end
486
+ end
487
+
488
+ def output_encoding
489
+ return @encoding if @encoding
490
+
491
+ locale = ENV["LC_ALL"] || ENV["LC_MESSAGE"] || ENV["LANG"]
492
+ case locale
493
+ when /\.([a-z\d\-]+)\z/i
494
+ $1
495
+ else
496
+ nil
497
+ end
498
+ end
499
+
500
+ def encoding_to_nkf_option(encoding)
501
+ return nil if encoding.nil?
502
+ case encoding
503
+ when /\A(?:euc[-_]?jp|ujis)\z/i
504
+ "e"
505
+ when /\Autf[-_]?8\z/i
506
+ "w"
507
+ when /\As(?:hift[-_]?)?jis\z/i
508
+ "s"
509
+ when /\Aiso-2022-jp\z/i
510
+ "j"
511
+ else
512
+ nil
513
+ end
514
+ end
515
+
516
+ end
517
+
518
+ end