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
221
222
223
|
# File 'lib/bitclust/methoddatabase.rb', line 221
def refs
@refs ||= RefsDatabase.load(realpath('refs'))
end
|
Instance Method Details
380
381
382
|
# File 'lib/bitclust/methoddatabase.rb', line 380
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
|
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
|
# File 'lib/bitclust/methoddatabase.rb', line 234
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
|
316
317
318
|
# File 'lib/bitclust/methoddatabase.rb', line 316
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.
407
408
409
410
411
412
|
# File 'lib/bitclust/methoddatabase.rb', line 407
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
414
415
416
417
|
# File 'lib/bitclust/methoddatabase.rb', line 414
def fetch_class_id(id)
load_class(id) or
raise ClassNotFound, "class not found: #{id.inspect}"
end
|
#fetch_doc(name) ⇒ Object
330
331
332
333
|
# File 'lib/bitclust/methoddatabase.rb', line 330
def fetch_doc(name)
docmap()[libname2id(name)] or
raise DocNotFound, "doc not found: #{name.inspect}"
end
|
#fetch_library(name) ⇒ Object
353
354
355
356
|
# File 'lib/bitclust/methoddatabase.rb', line 353
def fetch_library(name)
librarymap()[libname2id(name)] or
raise LibraryNotFound, "library not found: #{name.inspect}"
end
|
#fetch_library_id(id) ⇒ Object
358
359
360
361
|
# File 'lib/bitclust/methoddatabase.rb', line 358
def fetch_library_id(id)
librarymap()[id] or
raise LibraryNotFound, "library not found: #{id.inspect}"
end
|
#fetch_method(spec) ⇒ Object
499
500
501
|
# File 'lib/bitclust/methoddatabase.rb', line 499
def fetch_method(spec)
fetch_class(spec.klass).fetch_method(spec)
end
|
#fetch_methods(spec) ⇒ Object
495
496
497
|
# File 'lib/bitclust/methoddatabase.rb', line 495
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.
396
397
398
399
400
401
402
403
404
|
# File 'lib/bitclust/methoddatabase.rb', line 396
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
325
326
327
328
|
# File 'lib/bitclust/methoddatabase.rb', line 325
def get_doc(name)
id = libname2id(name)
docmap()[id] ||= DocEntry.new(self, id)
end
|
#get_library(name) ⇒ Object
348
349
350
351
|
# File 'lib/bitclust/methoddatabase.rb', line 348
def get_library(name)
id = libname2id(name)
librarymap()[id] ||= LibraryEntry.new(self, id)
end
|
#get_method(spec) ⇒ Object
491
492
493
|
# File 'lib/bitclust/methoddatabase.rb', line 491
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
339
340
341
|
# File 'lib/bitclust/methoddatabase.rb', line 339
def libraries
librarymap().values
end
|
#make_refs ⇒ Object
225
226
227
228
229
230
231
232
|
# File 'lib/bitclust/methoddatabase.rb', line 225
def make_refs
[classes, libraries, methods, docs].each do |es|
es.each do |e|
refs().(e)
end
end
refs
end
|
487
488
489
|
# File 'lib/bitclust/methoddatabase.rb', line 487
def methods
classes().map {|c| c.entries }.flatten
end
|
#open_class(name) {|c| ... } ⇒ Object
427
428
429
430
431
432
433
434
435
436
437
438
439
|
# File 'lib/bitclust/methoddatabase.rb', line 427
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
363
364
365
366
367
368
369
370
371
372
373
374
|
# File 'lib/bitclust/methoddatabase.rb', line 363
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
472
473
474
475
476
477
478
479
480
481
482
483
484
485
|
# File 'lib/bitclust/methoddatabase.rb', line 472
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
419
420
421
422
423
424
425
|
# File 'lib/bitclust/methoddatabase.rb', line 419
def search_classes(pattern)
cs = _search_classes(pattern)
if cs.empty?
raise ClassNotFound, "no such class: #{pattern}"
end
cs
end
|
#search_methods(pattern) ⇒ Object
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
|
# File 'lib/bitclust/methoddatabase.rb', line 503
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
206
207
208
209
|
# 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
rescue ParseError => e
raise ParseError, "#{e.message} (ヒント: マニュアルがより新しい bitclust を必要とする記法を含んでいる可能性があります。bitclust の gem を更新すると解決するかもしれません)", e.backtrace
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
|