mirror of
https://gitea.invidious.io/iv-org/shard-ameba.git
synced 2024-08-15 00:53:29 +00:00
Base YAML config loader & Ameba runner
This commit is contained in:
parent
80e2ab4f55
commit
822a69b81c
7 changed files with 158 additions and 32 deletions
|
@ -1,7 +1,7 @@
|
|||
require "../src/ameba"
|
||||
require "benchmark"
|
||||
|
||||
private def get_sources(n)
|
||||
private def get_files(n)
|
||||
Dir["src/**/*.cr"].first(n)
|
||||
end
|
||||
|
||||
|
@ -16,10 +16,11 @@ Benchmark.ips do |x|
|
|||
30,
|
||||
40,
|
||||
].each do |n|
|
||||
sources = get_sources(n)
|
||||
formatter = Ameba::Formatter::BaseFormatter.new
|
||||
config = Ameba::Config.load
|
||||
config.formatter = Ameba::Formatter::BaseFormatter.new
|
||||
config.files = get_files(n)
|
||||
s = n == 1 ? "" : "s"
|
||||
x.report("#{n} source#{s}") { Ameba.run sources, formatter }
|
||||
x.report("#{n} source#{s}") { Ameba.run config }
|
||||
end
|
||||
end
|
||||
|
||||
|
|
23
src/ameba.cr
23
src/ameba.cr
|
@ -6,26 +6,7 @@ require "./ameba/formatter/*"
|
|||
module Ameba
|
||||
extend self
|
||||
|
||||
def run(formatter = Formatter::BaseFormatter.new)
|
||||
run Dir["**/*.cr"].reject(&.starts_with? "lib/"), formatter
|
||||
end
|
||||
|
||||
def run(files, formatter : Formatter::BaseFormatter)
|
||||
sources = files.map { |path| Source.new(File.read(path), path) }
|
||||
|
||||
formatter.started sources
|
||||
sources.each do |source|
|
||||
formatter.source_started source
|
||||
catch(source)
|
||||
formatter.source_finished source
|
||||
end
|
||||
formatter.finished sources
|
||||
sources
|
||||
end
|
||||
|
||||
def catch(source : Source)
|
||||
Rule.rules.each do |rule|
|
||||
rule.new.test(source)
|
||||
end
|
||||
def run(config = Config.load)
|
||||
Runner.new(config).run
|
||||
end
|
||||
end
|
||||
|
|
69
src/ameba/config.cr
Normal file
69
src/ameba/config.cr
Normal file
|
@ -0,0 +1,69 @@
|
|||
require "yaml"
|
||||
|
||||
class Ameba::Config
|
||||
setter formatter : Formatter::BaseFormatter?
|
||||
setter files : Array(String)?
|
||||
|
||||
def initialize(@config : YAML::Any)
|
||||
end
|
||||
|
||||
def self.load(path = ".ameba.yml")
|
||||
content = (path && File.exists? path) ? File.read path : "{}"
|
||||
Config.new YAML.parse(content)
|
||||
end
|
||||
|
||||
def files
|
||||
@files ||= default_files
|
||||
end
|
||||
|
||||
def formatter
|
||||
@formatter ||= default_formatter
|
||||
end
|
||||
|
||||
def subconfig(name)
|
||||
@config[name]?
|
||||
end
|
||||
|
||||
private def default_files
|
||||
Dir["**/*.cr"].reject(&.starts_with? "lib/")
|
||||
end
|
||||
|
||||
private def default_formatter
|
||||
Formatter::DotFormatter.new
|
||||
end
|
||||
|
||||
module Rule
|
||||
getter config : YAML::Any?
|
||||
|
||||
macro prop(assign)
|
||||
# Rule configuration property.
|
||||
def {{assign.target}}
|
||||
{% prop_name = assign.target.id.camelcase.gsub(/\?/, "") %}
|
||||
|
||||
{% if assign.value.is_a? NumberLiteral %}
|
||||
int_prop "{{prop_name}}", {{assign.value}}
|
||||
{% elsif assign.value.is_a? BoolLiteral %}
|
||||
bool_prop "{{prop_name}}", {{assign.value}}
|
||||
{% elsif assign.value.is_a? StringLiteral %}
|
||||
str_prop "{{prop_name}}", {{assign.value}}
|
||||
{% end %}
|
||||
end
|
||||
end
|
||||
|
||||
def initialize(config = nil)
|
||||
@config = config.try &.subconfig(name)
|
||||
end
|
||||
|
||||
protected def int_prop(name, default : Number)
|
||||
str_prop(name, default).to_i
|
||||
end
|
||||
|
||||
protected def bool_prop(name, default : Bool)
|
||||
str_prop(name, default.to_s) == "true"
|
||||
end
|
||||
|
||||
protected def str_prop(name, default)
|
||||
config.try &.[name]?.try &.as_s || default
|
||||
end
|
||||
end
|
||||
end
|
|
@ -1,7 +1,11 @@
|
|||
module Ameba::Rule
|
||||
abstract struct Base
|
||||
include Config::Rule
|
||||
|
||||
abstract def test(source : Source)
|
||||
|
||||
prop enabled? = true
|
||||
|
||||
def test(source : Source, node : Crystal::ASTNode)
|
||||
# can't be abstract
|
||||
end
|
||||
|
|
|
@ -1,10 +1,19 @@
|
|||
module Ameba::Rule
|
||||
# A rule that disallows lines longer than 80 symbols.
|
||||
# A rule that disallows lines longer than `max_length` number of symbols.
|
||||
#
|
||||
# YAML configuration example:
|
||||
#
|
||||
# ```
|
||||
# LineLength:
|
||||
# Enabled: true
|
||||
# MaxLength: 100
|
||||
# ```
|
||||
struct LineLength < Base
|
||||
prop max_length = 80
|
||||
|
||||
def test(source)
|
||||
source.lines.each_with_index do |line, index|
|
||||
next unless line.size > 80
|
||||
next unless line.size > max_length
|
||||
|
||||
source.error self, source.location(index + 1, line.size),
|
||||
"Line too long"
|
||||
|
|
49
src/ameba/runner.cr
Normal file
49
src/ameba/runner.cr
Normal file
|
@ -0,0 +1,49 @@
|
|||
module Ameba
|
||||
class Runner
|
||||
@rules : Array(Rule::Base)
|
||||
@sources : Array(Source)
|
||||
@formatter : Formatter::BaseFormatter
|
||||
|
||||
def initialize(config : Config)
|
||||
@rules = load_rules(config)
|
||||
@sources = load_sources(config)
|
||||
@formatter = config.formatter
|
||||
end
|
||||
|
||||
def run
|
||||
@formatter.started @sources
|
||||
@sources.each do |source|
|
||||
@formatter.source_started source
|
||||
|
||||
@rules.each &.test(source)
|
||||
|
||||
@formatter.source_finished source
|
||||
end
|
||||
self
|
||||
ensure
|
||||
@formatter.finished @sources
|
||||
end
|
||||
|
||||
def success?
|
||||
@sources.all? &.valid?
|
||||
end
|
||||
|
||||
def test_source(source)
|
||||
@formatter.source_started source
|
||||
@rules.each &.test(source)
|
||||
ensure
|
||||
@formatter.source_finished source
|
||||
end
|
||||
|
||||
private def load_sources(config)
|
||||
config.files
|
||||
.map { |wildcard| Dir[wildcard] }
|
||||
.flatten
|
||||
.map { |path| Source.new File.read(path), path }
|
||||
end
|
||||
|
||||
private def load_rules(config)
|
||||
Rule.rules.map { |r| r.new config }.select &.enabled?
|
||||
end
|
||||
end
|
||||
end
|
23
src/cli.cr
23
src/cli.cr
|
@ -1,10 +1,10 @@
|
|||
require "option_parser"
|
||||
require "./ameba"
|
||||
|
||||
formatter = Ameba::Formatter::DotFormatter
|
||||
files, formatter, config_path = nil, nil, nil
|
||||
|
||||
OptionParser.parse(ARGV) do |parser|
|
||||
parser.banner = "Usage: ameba [options]"
|
||||
parser.banner = "Usage: ameba [options] [file1 file2 ...]"
|
||||
|
||||
parser.on("-v", "--version", "Print version") do
|
||||
puts Ameba::VERSION
|
||||
|
@ -17,10 +17,23 @@ OptionParser.parse(ARGV) do |parser|
|
|||
end
|
||||
|
||||
parser.on("-s", "--silent", "Disable output") do
|
||||
formatter = Ameba::Formatter::BaseFormatter
|
||||
formatter = Ameba::Formatter::BaseFormatter.new
|
||||
end
|
||||
|
||||
# parser.on("-f FORMATTER", "--format FORMATTER", "Specify formatter") do |f|
|
||||
# end
|
||||
|
||||
parser.on("-c PATH", "--config PATH", "Specify configuration file") do |f|
|
||||
config_path = f
|
||||
end
|
||||
|
||||
parser.unknown_args do |f|
|
||||
files = f if f.any?
|
||||
end
|
||||
end
|
||||
|
||||
files = Dir["**/*.cr"]
|
||||
config = Ameba::Config.load config_path
|
||||
config.formatter = formatter
|
||||
config.files = files
|
||||
|
||||
exit(1) unless Ameba.run(files, formatter.new).all? &.valid?
|
||||
exit(1) unless Ameba.run(config).success?
|
||||
|
|
Loading…
Reference in a new issue