|
1 | 1 | #!/usr/bin/env ruby
|
2 | 2 |
|
3 |
| -require "rdoc" |
| 3 | +require "bundler/setup" |
| 4 | +require "optparse" |
| 5 | +require "rbs" |
| 6 | +require "rbs/annotate" |
4 | 7 |
|
5 |
| -def store_for_class(name, stores:) |
6 |
| - stores.find do |store| |
7 |
| - store.find_class_named(name) || store.find_module_named(name) |
8 |
| - end |
9 |
| -end |
10 |
| - |
11 |
| -def format_comment(comment) |
12 |
| - out = RDoc::Markup::Document.new |
13 |
| - out << comment |
14 |
| - formatter = RDoc::Markup::ToMarkdown.new |
15 |
| - out.accept(formatter) |
16 |
| -end |
17 |
| - |
18 |
| -def comment_for_constant(name, stores:) |
19 |
| - *class_components, const_name = name.split(/::/) |
20 |
| - class_name = class_components.join("::") |
21 |
| - |
22 |
| - klass = store_for_class(class_name, stores: stores)&.yield_self {|store| |
23 |
| - store.find_class_named(class_name) || store.find_module_named(class_name) |
24 |
| - } |
| 8 | +source = RBS::Annotate::RDocSource.new() |
| 9 | +annotator = RBS::Annotate::RDocAnnotator.new(source: source) |
25 | 10 |
|
26 |
| - constant = klass.constants.find do |const| |
27 |
| - const.name == const_name |
28 |
| - end |
| 11 | +OptionParser.new do |opts| |
| 12 | + opts.on("--[no-]system", "Load RDoc from system (defaults to true)") {|b| source.with_system_dir = b } |
| 13 | + opts.on("--[no-]gems", "Load RDoc from gems (defaults to false)") {|b| source.with_gems_dir = b } |
| 14 | + opts.on("--[no-]site", "Load RDoc from site directory (defaults to false)") {|b| source.with_site_dir = b } |
| 15 | + opts.on("--[no-]home", "Load RDoc from home directory (defaults to false)") {|b| source.with_home_dir = b } |
| 16 | + opts.on("-d", "--dir DIRNAME", "Load RDoc from DIRNAME") {|d| source.extra_dirs << Pathname(d) } |
| 17 | + opts.on("--[no-]arglists", "Generate arglists section (defaults to true)") {|b| annotator.include_arg_lists = b } |
| 18 | + opts.on("--[no-]filename", "Include source file name in the documentation (defaults to true)") {|b| annotator.include_filename = b } |
| 19 | +end.parse!(ARGV) |
29 | 20 |
|
30 |
| - if constant&.documented? |
31 |
| - format_comment(constant.comment) |
32 |
| - end |
| 21 | +tester = Object.new.tap do |object| |
| 22 | + object.singleton_class.define_method(:test_path) {|*| true } |
33 | 23 | end
|
34 | 24 |
|
35 |
| -def comment_for_class(class_name, stores:) |
36 |
| - klass = store_for_class(class_name, stores: stores)&.yield_self {|store| |
37 |
| - store.find_class_named(class_name) || store.find_module_named(class_name) |
38 |
| - } |
39 |
| - |
40 |
| - if klass&.documented? |
41 |
| - format_comment(klass.comment) |
42 |
| - end |
43 |
| -end |
44 |
| - |
45 |
| -def comment_for_method(klass, method, stores:) |
46 |
| - method = store_for_class(klass, stores: stores)&.load_method(klass, method) |
47 |
| - |
48 |
| - if method&.documented? |
49 |
| - out = RDoc::Markup::Document.new |
| 25 | +name = ARGV.shift or return |
50 | 26 |
|
51 |
| - out << method.comment |
| 27 | +source.load() |
52 | 28 |
|
53 |
| - if method.arglists |
54 |
| - out << RDoc::Markup::Heading.new(1, "arglists 💪👽🚨 << Delete this section") |
55 |
| - arglists = method.arglists.chomp.split("\n").map {|line| line + "\n" } |
56 |
| - out << RDoc::Markup::Verbatim.new(*arglists) |
57 |
| - end |
58 |
| - |
59 |
| - out.accept(RDoc::Markup::ToMarkdown.new) |
60 |
| - end |
61 |
| -rescue RDoc::Store::MissingFileError |
62 |
| - nil |
63 |
| -end |
64 |
| - |
65 |
| -if ARGV.empty? |
66 |
| - puts 'query-rdoc [subject]' |
67 |
| - puts " subject ::= ClassName (class, module, or constant)" |
68 |
| - puts " | ClassName.method (singleton method)" |
69 |
| - puts " | ClassName#method (instance method)" |
70 |
| - exit |
71 |
| -end |
72 |
| - |
73 |
| -stores = [] |
74 |
| -RDoc::RI::Paths.each true, true, false, false do |path, type| |
75 |
| - STDERR.puts "Loading store from #{path}..." |
76 |
| - store = RDoc::RI::Store.new(path, type) |
77 |
| - store.load_all |
78 |
| - stores << store |
79 |
| -end |
| 29 | +case |
| 30 | +when match = name.match(/(?<constant_name>[^#]+)#(?<method_name>.+)/) |
| 31 | + type_name = TypeName(match[:constant_name] || raise) |
| 32 | + instance_method = (match[:method_name] or raise).to_sym |
80 | 33 |
|
81 |
| -subject = ARGV[0] |
| 34 | + doc = annotator.doc_for_method(type_name, instance_method: instance_method, tester: tester) |
| 35 | +when match = name.match(/(?<constant_name>[^#]+)\.(?<method_name>.+)/) |
| 36 | + type_name = TypeName(match[:constant_name] || raise) |
| 37 | + singleton_method = (match[:method_name] or raise).to_sym |
82 | 38 |
|
83 |
| -case |
84 |
| -when match = subject.match(/(?<constant_name>[^#]+)#(?<method_name>.+)/) |
85 |
| - STDERR.puts "Finding instance method #{match[:constant_name]} # #{match[:method_name]} ..." |
86 |
| - comment = comment_for_method(match[:constant_name], "##{match[:method_name]}", stores: stores) |
87 |
| -when match = subject.match(/(?<constant_name>[^.]+)\.(?<method_name>.+)/) |
88 |
| - STDERR.puts "Finding singleton method #{match[:constant_name]} . #{match[:method_name]} ..." |
89 |
| - comment = comment_for_method(match[:constant_name], "::#{match[:method_name]}", stores: stores) |
| 39 | + doc = annotator.doc_for_method(type_name, singleton_method: singleton_method, tester: tester) |
90 | 40 | else
|
91 |
| - STDERR.puts "Finding class/module/constant #{subject} ..." |
92 |
| - comment = comment_for_class(subject, stores: stores) || comment_for_constant(subject, stores: stores) |
| 41 | + type_name = TypeName(name) |
| 42 | + |
| 43 | + doc = annotator.doc_for_class(type_name, tester: tester) || annotator.doc_for_constant(type_name, tester: tester) |
93 | 44 | end
|
94 | 45 |
|
95 |
| -if comment |
96 |
| - STDERR.puts "Printing document..." |
97 |
| - comment.each_line do |line| |
98 |
| - puts "# #{line}" |
99 |
| - end |
| 46 | +if doc |
| 47 | + puts doc |
100 | 48 | else
|
101 |
| - STDERR.puts "Nothing to print; failed to query the document..." |
102 |
| - exit 1 |
| 49 | + puts "🤯 Cannot find the definition of `#{name}`" |
103 | 50 | end
|
0 commit comments