Dynamically load rule documentation

This commit is contained in:
Vitalii Elenhaupt 2018-12-08 22:52:32 +02:00
parent f8dab3bc34
commit 20938da89a
No known key found for this signature in database
GPG key ID: 7558EF3A4056C706
3 changed files with 57 additions and 0 deletions

View file

@ -67,5 +67,11 @@ module Ameba::Rule
rule.excluded?(Source.new "", "source.cr").should be_false
end
end
describe ".parsed_doc" do
it "returns the parsed rule doc" do
DummyRule.parsed_doc.should eq "Dummy Rule which does nothing."
end
end
end
end

View file

@ -2,6 +2,7 @@ require "spec"
require "../src/ameba"
module Ameba
# Dummy Rule which does nothing.
struct DummyRule < Rule::Base
properties do
description : String = "Dummy rule that does nothing."

View file

@ -120,6 +120,56 @@ module Ameba::Rule
protected def self.subclasses
{{ @type.subclasses }}
end
macro inherited
protected def self.path_to_source_file
__FILE__
end
end
# Returns documentation for this rule if any.
#
# ```
# module Ameba
# # This is a test rule.
# # Does nothing.
# struct MyRule < Ameba::Rule::Base
# def test(source)
# end
# end
# 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
# Returns a list of all available rules.