Class: BitClust::MethodDatabase
Overview
Database for Ruby entries (library, class, method).
Constant Summary
Constants included
from NameUtils
NameUtils::CHAR_TO_MARK, NameUtils::CHAR_TO_NAME, NameUtils::CLASS_NAME_RE, NameUtils::CLASS_PATH_RE, NameUtils::CONST_PATH_RE, NameUtils::CONST_RE, NameUtils::GVAR_RE, NameUtils::LIBNAME_RE, NameUtils::MARK_TO_CHAR, NameUtils::MARK_TO_NAME, NameUtils::METHOD_NAME_RE, NameUtils::METHOD_SPEC_RE, NameUtils::MID, NameUtils::NAME_TO_CHAR, NameUtils::NAME_TO_MARK, NameUtils::TYPEMARK_RE
Instance Attribute Summary collapse
Instance Method Summary
collapse
Methods inherited from Database
#atomic_write_open, #dummy?, #encoding, #entries, #exist?, #foreach_line, #load_properties, #makepath, #properties, #propget, #propkeys, #propset, #read, #save_properties, #transaction
Methods included from NameUtils
build_method_id, classid2name, classname2id, classname?, decodeid, decodename_fs, decodename_url, display_typemark, encodeid, encodename_fs, encodename_rdocurl, encodename_url, functionname?, gvarname?, html_filename, libid2name, libname2id, libname?, method_spec?, methodid2classid, methodid2libid, methodid2mname, methodid2specparts, methodid2specstring, methodid2typechar, methodid2typemark, methodid2typename, methodname?, split_method_id, split_method_spec, typechar2mark, typechar2name, typechar?, typemark2char, typemark2name, typemark?, typename2char, typename2mark, typename?
Constructor Details
Returns a new instance of MethodDatabase.
36
37
38
39
40
41
42
43
44
45
46
|
# File 'lib/bitclust/methoddatabase.rb', line 36
def initialize(prefix)
super prefix
@librarymap = nil
@classmap = {}
@class_extent_loaded = false
@in_transaction = false
@dirty_libraries = {}
@dirty_classes = {}
@dirty_methods = {}
@refs = nil
end
|
Instance Attribute Details
217
218
219
|
# File 'lib/bitclust/methoddatabase.rb', line 217
def refs
@refs ||= RefsDatabase.load(realpath('refs'))
end
|
Instance Method Details
376
377
378
|
# File 'lib/bitclust/methoddatabase.rb', line 376
def classes
classmap().values
end
|
#clear_dirty ⇒ Object
127
128
129
130
131
|
# File 'lib/bitclust/methoddatabase.rb', line 127
def clear_dirty
@dirty_libraries.clear
@dirty_classes.clear
@dirty_methods.clear
end
|
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
|
# File 'lib/bitclust/methoddatabase.rb', line 230
def copy_doc
return copy_doc_md if @md_root
return unless @root
root_path = Pathname.new(@root).expand_path
Dir.glob("#{@root}/../../doc/**/*.rd").each do |f|
if %r!\A#{Regexp.escape(@root)}/\.\./\.\./doc/([-\./\w]+)\.rd\z! =~ f
id = libname2id($1 || raise)
se = DocEntry.new(self, id)
s = Preprocessor.read(f, properties)
title, source = RRDParser.split_doc(s)
relative_path = Pathname.new(f).expand_path(@root).relative_path_from(root_path)
se.title = title
se.source = source
se.source_location = Location.new(relative_path, 1)
se.save
end
end
end
|
#dirty? ⇒ Boolean
91
92
93
94
95
|
# File 'lib/bitclust/methoddatabase.rb', line 91
def dirty?
not @dirty_libraries.empty? or
not @dirty_classes.empty? or
not @dirty_methods.empty?
end
|
#dirty_class(c) ⇒ Object
111
112
113
|
# File 'lib/bitclust/methoddatabase.rb', line 111
def dirty_class(c)
@dirty_classes[c] = true
end
|
#dirty_library(lib) ⇒ Object
103
104
105
|
# File 'lib/bitclust/methoddatabase.rb', line 103
def dirty_library(lib)
@dirty_libraries[lib] = true
end
|
#dirty_method(m) ⇒ Object
119
120
121
|
# File 'lib/bitclust/methoddatabase.rb', line 119
def dirty_method(m)
@dirty_methods[m] = true
end
|
312
313
314
|
# File 'lib/bitclust/methoddatabase.rb', line 312
def docs
docmap().values
end
|
#each_dirty_class(&block) ⇒ Object
115
116
117
|
# File 'lib/bitclust/methoddatabase.rb', line 115
def each_dirty_class(&block)
@dirty_classes.each_key(&block)
end
|
#each_dirty_entry(&block) ⇒ Object
97
98
99
100
101
|
# File 'lib/bitclust/methoddatabase.rb', line 97
def each_dirty_entry(&block)
(@dirty_libraries.keys +
@dirty_classes.keys +
@dirty_methods.keys).each(&block)
end
|
#each_dirty_library(&block) ⇒ Object
107
108
109
|
# File 'lib/bitclust/methoddatabase.rb', line 107
def each_dirty_library(&block)
@dirty_libraries.each_key(&block)
end
|
#each_dirty_method(&block) ⇒ Object
123
124
125
|
# File 'lib/bitclust/methoddatabase.rb', line 123
def each_dirty_method(&block)
@dirty_methods.each_key(&block)
end
|
#fetch_class(name) ⇒ Object
This method does not work in transaction.
403
404
405
406
407
408
|
# File 'lib/bitclust/methoddatabase.rb', line 403
def fetch_class(name)
id = intern_classname(name) or
raise ClassNotFound, "class not found: #{name.inspect}"
load_class(id) or
raise "must not happen: #{name.inspect}, #{id.inspect}"
end
|
#fetch_class_id(id) ⇒ Object
410
411
412
413
|
# File 'lib/bitclust/methoddatabase.rb', line 410
def fetch_class_id(id)
load_class(id) or
raise ClassNotFound, "class not found: #{id.inspect}"
end
|
#fetch_doc(name) ⇒ Object
326
327
328
329
|
# File 'lib/bitclust/methoddatabase.rb', line 326
def fetch_doc(name)
docmap()[libname2id(name)] or
raise DocNotFound, "doc not found: #{name.inspect}"
end
|
#fetch_library(name) ⇒ Object
349
350
351
352
|
# File 'lib/bitclust/methoddatabase.rb', line 349
def fetch_library(name)
librarymap()[libname2id(name)] or
raise LibraryNotFound, "library not found: #{name.inspect}"
end
|
#fetch_library_id(id) ⇒ Object
354
355
356
357
|
# File 'lib/bitclust/methoddatabase.rb', line 354
def fetch_library_id(id)
librarymap()[id] or
raise LibraryNotFound, "library not found: #{id.inspect}"
end
|
#fetch_method(spec) ⇒ Object
495
496
497
|
# File 'lib/bitclust/methoddatabase.rb', line 495
def fetch_method(spec)
fetch_class(spec.klass).fetch_method(spec)
end
|
#fetch_methods(spec) ⇒ Object
491
492
493
|
# File 'lib/bitclust/methoddatabase.rb', line 491
def fetch_methods(spec)
fetch_class(spec.klass).fetch_methods(spec)
end
|
#get_class(name) ⇒ Object
get a class entry if it exists, or create a new class entry object
if it doesn't exist.
392
393
394
395
396
397
398
399
400
|
# File 'lib/bitclust/methoddatabase.rb', line 392
def get_class(name)
if id = intern_classname(name)
load_class(id) or
raise "must not happen: #{name.inspect}, #{id.inspect}"
else
id = classname2id(name)
@classmap[id] ||= ClassEntry.new(self, id)
end
end
|
#get_doc(name) ⇒ Object
321
322
323
324
|
# File 'lib/bitclust/methoddatabase.rb', line 321
def get_doc(name)
id = libname2id(name)
docmap()[id] ||= DocEntry.new(self, id)
end
|
#get_library(name) ⇒ Object
344
345
346
347
|
# File 'lib/bitclust/methoddatabase.rb', line 344
def get_library(name)
id = libname2id(name)
librarymap()[id] ||= LibraryEntry.new(self, id)
end
|
#get_method(spec) ⇒ Object
487
488
489
|
# File 'lib/bitclust/methoddatabase.rb', line 487
def get_method(spec)
get_class(spec.klass).get_method(spec)
end
|
50
51
52
53
54
55
56
57
58
59
60
|
# File 'lib/bitclust/methoddatabase.rb', line 50
def init
prefix = @prefix || raise
FileUtils.rm_rf prefix
FileUtils.mkdir_p prefix
Dir.mkdir "#{prefix}/library"
Dir.mkdir "#{prefix}/class"
Dir.mkdir "#{prefix}/method"
Dir.mkdir "#{prefix}/doc"
FileUtils.touch "#{prefix}/properties"
FileUtils.touch "#{prefix}/refs"
end
|
#libraries ⇒ Object
335
336
337
|
# File 'lib/bitclust/methoddatabase.rb', line 335
def libraries
librarymap().values
end
|
#make_refs ⇒ Object
221
222
223
224
225
226
227
228
|
# File 'lib/bitclust/methoddatabase.rb', line 221
def make_refs
[classes, libraries, methods, docs].each do |es|
es.each do |e|
refs().(e)
end
end
refs
end
|
483
484
485
|
# File 'lib/bitclust/methoddatabase.rb', line 483
def methods
classes().map {|c| c.entries }.flatten
end
|
#open_class(name) {|c| ... } ⇒ Object
423
424
425
426
427
428
429
430
431
432
433
434
435
|
# File 'lib/bitclust/methoddatabase.rb', line 423
def open_class(name)
check_transaction
id = classname2id(name)
if exist?("class/#{id}")
c = load_class(id) || raise
c.clear
else
c = (@classmap[id] ||= ClassEntry.new(self, id))
end
yield c
dirty_class c
c
end
|
#open_library(name, reopen = false) ⇒ Object
359
360
361
362
363
364
365
366
367
368
369
370
|
# File 'lib/bitclust/methoddatabase.rb', line 359
def open_library(name, reopen = false)
check_transaction
map = librarymap()
id = libname2id(name)
if lib = map[id]
lib.clear unless reopen
else
lib = (map[id] ||= LibraryEntry.new(self, id))
end
dirty_library lib
lib
end
|
#open_method(id) {|m| ... } ⇒ Object
Return existing/newly created MethodEntry from the given MethodID
FIXME: see kind
468
469
470
471
472
473
474
475
476
477
478
479
480
481
|
# File 'lib/bitclust/methoddatabase.rb', line 468
def open_method(id)
check_transaction
if m = id.klass.get_method(id)
m.clear
else
m = MethodEntry.new(self, id.idstring)
id.klass.add_method m
end
m.library = id.library
m.klass = id.klass
yield m
dirty_method m
m
end
|
#search_classes(pattern) ⇒ Object
415
416
417
418
419
420
421
|
# File 'lib/bitclust/methoddatabase.rb', line 415
def search_classes(pattern)
cs = _search_classes(pattern)
if cs.empty?
raise ClassNotFound, "no such class: #{pattern}"
end
cs
end
|
#search_methods(pattern) ⇒ Object
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
|
# File 'lib/bitclust/methoddatabase.rb', line 499
def search_methods(pattern)
result = _search_methods(pattern)
if result.fail?
if result.classes.empty?
loc = pattern.klass ? pattern.klass + '.' : ''
raise MethodNotFound, "no such method: #{loc}#{pattern.method}"
end
if result.classes.size <= 5
loc = result.classes.map {|c| c.label }.join(', ')
else
loc = "#{result.classes.size} classes"
end
raise MethodNotFound, "no such method in #{loc}: #{pattern.method}"
end
result
end
|
#update_by_file(path, libname) ⇒ Object
162
163
164
165
|
# File 'lib/bitclust/methoddatabase.rb', line 162
def update_by_file(path, libname)
check_transaction
RRDParser.new(self).parse_file(path, libname, properties())
end
|
#update_by_markdowntree(md_root) ⇒ Object
Markdown ツリー(manual/api)を直接パースして DB を更新する(M3)。
front matter の library: が所属を表すため、ライブラリごとに
lib ファイル → メンバーファイル(reopen/redefine のみのファイルは後置。
dynamic include の対象 module が先に定義されている必要があるため)の
順でパースする。版ゲート(since/until)外のライブラリ/メンバーはスキップ。
エントリの source には md 断片が入り、source_location は md の実パスを指す
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
|
# File 'lib/bitclust/methoddatabase.rb', line 173
def update_by_markdowntree(md_root)
require 'bitclust/markdown_tree'
require 'bitclust/mdparser'
@md_root = md_root
propset 'source_format', 'markdown'
tree = MarkdownTree.scan(md_root)
version = properties()["version"]
tree.libraries.sort.each do |libname, lib|
next unless md_version_covers?(version, lib[:since], lib[:until])
lib_entry = MDParser.new(self).parse_file(File.join(md_root, lib[:path]), libname, properties())
lib_location = lib_entry.source_location
members = tree.entities.select { |_, e|
e[:memberships].any? { |m|
m[:library] == libname && md_version_covers?(version, m[:since], m[:until])
}
}
sorted = members.keys.sort_by { |path|
reopen_only = members[path][:kinds].all? { |kind, _| %w[reopen redefine].include?(kind) }
[reopen_only ? 1 : 0, path]
}
sorted.each do |path|
entity = members[path]
next unless md_version_covers?(version, entity[:since], entity[:until])
MDParser.new(self).parse_file(File.join(md_root, path), libname, properties())
end
lib_entry.source_location = lib_location
end
end
|
#update_by_stdlibtree(root) ⇒ Object
148
149
150
151
152
153
|
# File 'lib/bitclust/methoddatabase.rb', line 148
def update_by_stdlibtree(root)
@root = root
parse_LIBRARIES("#{root}/LIBRARIES", properties()).each do |libname|
update_by_file "#{root}/#{libname}.rd", libname
end
end
|
#update_requires ⇒ Object
133
134
135
136
137
|
# File 'lib/bitclust/methoddatabase.rb', line 133
def update_requires
libraries.each{|lib|
lib.requires = lib.all_requires
}
end
|
#update_sublibraries ⇒ Object
139
140
141
142
143
144
145
146
|
# File 'lib/bitclust/methoddatabase.rb', line 139
def update_sublibraries
libraries.each{|lib|
re = /\A#{lib.name}\//
libraries.each{|l|
lib.sublibrary(l) if re =~ l.name
}
}
end
|