mirror of
https://gitea.invidious.io/iv-org/shard-ameba.git
synced 2024-08-15 00:53:29 +00:00
Merge pull request #282 from crystal-ameba/Sija/fix-issue-270
Populate `Rule::Base+.parsed_doc` on compile time
This commit is contained in:
commit
4700ae7649
2 changed files with 51 additions and 50 deletions
|
@ -138,57 +138,29 @@ module Ameba::Rule
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
private macro read_type_doc(filepath = __FILE__)
|
||||||
|
{{ run("../../contrib/read_type_doc",
|
||||||
|
@type.name.split("::").last,
|
||||||
|
filepath
|
||||||
|
).chomp.stringify }}.presence
|
||||||
|
end
|
||||||
|
|
||||||
macro inherited
|
macro inherited
|
||||||
protected def self.path_to_source_file
|
# Returns documentation for this rule, if there is any.
|
||||||
__FILE__
|
#
|
||||||
end
|
# ```
|
||||||
end
|
# module Ameba
|
||||||
|
# # This is a test rule.
|
||||||
# Returns documentation for this rule if any.
|
# # Does nothing.
|
||||||
#
|
# class MyRule < Ameba::Rule::Base
|
||||||
# ```
|
# def test(source)
|
||||||
# module Ameba
|
# end
|
||||||
# # This is a test rule.
|
# end
|
||||||
# # Does nothing.
|
# end
|
||||||
# class MyRule < Ameba::Rule::Base
|
#
|
||||||
# def test(source)
|
# MyRule.parsed_doc # => "This is a test rule.\nDoes nothing."
|
||||||
# end
|
# ```
|
||||||
# end
|
class_getter parsed_doc : String? = read_type_doc
|
||||||
# end
|
|
||||||
#
|
|
||||||
# MyRule.parsed_doc # => "This is a test rule.\nDoes nothing."
|
|
||||||
# ```
|
|
||||||
def self.parsed_doc
|
|
||||||
source = File.read(path_to_source_file)
|
|
||||||
nodes = Crystal::Parser.new(source)
|
|
||||||
.tap(&.wants_doc = true)
|
|
||||||
.parse
|
|
||||||
type_name = rule_name.split('/').last?
|
|
||||||
|
|
||||||
DocFinder.new(nodes, type_name).doc
|
|
||||||
end
|
|
||||||
|
|
||||||
# :nodoc:
|
|
||||||
private class DocFinder < Crystal::Visitor
|
|
||||||
getter doc : String?
|
|
||||||
getter type_name : String?
|
|
||||||
|
|
||||||
def initialize(nodes, @type_name)
|
|
||||||
self.accept(nodes)
|
|
||||||
end
|
|
||||||
|
|
||||||
def visit(node : Crystal::ASTNode)
|
|
||||||
return false if @doc
|
|
||||||
|
|
||||||
if node.responds_to?(:name) &&
|
|
||||||
(name = node.name) &&
|
|
||||||
name.is_a?(Crystal::Path) &&
|
|
||||||
name.names.last? == @type_name
|
|
||||||
@doc = node.doc
|
|
||||||
end
|
|
||||||
|
|
||||||
true
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
29
src/contrib/read_type_doc.cr
Normal file
29
src/contrib/read_type_doc.cr
Normal file
|
@ -0,0 +1,29 @@
|
||||||
|
require "compiler/crystal/syntax/*"
|
||||||
|
|
||||||
|
private class DocFinder < Crystal::Visitor
|
||||||
|
getter type_name : String
|
||||||
|
getter doc : String?
|
||||||
|
|
||||||
|
def initialize(nodes, @type_name)
|
||||||
|
self.accept(nodes)
|
||||||
|
end
|
||||||
|
|
||||||
|
def visit(node : Crystal::ASTNode)
|
||||||
|
return false if @doc
|
||||||
|
|
||||||
|
if node.responds_to?(:name) && (name = node.name).is_a?(Crystal::Path)
|
||||||
|
@doc = node.doc if name.names.last? == @type_name
|
||||||
|
end
|
||||||
|
|
||||||
|
true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
type_name, path_to_source_file = ARGV
|
||||||
|
|
||||||
|
source = File.read(path_to_source_file)
|
||||||
|
nodes = Crystal::Parser.new(source)
|
||||||
|
.tap(&.wants_doc = true)
|
||||||
|
.parse
|
||||||
|
|
||||||
|
puts DocFinder.new(nodes, type_name).doc
|
Loading…
Reference in a new issue