TODO formatter

This commit is contained in:
Vitalii Elenhaupt 2017-11-30 11:27:52 +02:00 committed by V. Elenhaupt
parent bc552d0730
commit a1854c0aa3
5 changed files with 122 additions and 28 deletions

View file

@ -0,0 +1,44 @@
require "../../spec_helper"
module Ameba
private def create_todo(formatter)
s = Source.new "a = 1"
s.error DummyRule.new, s.location(1, 2), "message"
formatter.finished [s]
end
describe Formatter::TODOFormatter do
file = IO::Memory.new
subject = Formatter::TODOFormatter.new IO::Memory.new, file
context "problems not reported" do
it "does not create todo" do
subject.finished [Source.new ""]
file.to_s.empty?.should be_true
end
end
context "problems reported" do
it "creates a todo with header" do
create_todo subject
file.to_s.should contain "# This configuration file was generated by"
file.to_s.should contain "Ameba version #{VERSION}"
end
it "creates a todo with rule name" do
create_todo subject
file.to_s.should contain "DummyRule"
end
it "creates a todo with problems count" do
create_todo subject
file.to_s.should contain "Problems found: 1"
end
it "creates a valid YAML document" do
create_todo subject
YAML.parse(file.to_s).should_not be_nil
end
end
end
end

View file

@ -46,13 +46,11 @@ module Ameba::Cli
def run_ameba(opts)
config = Ameba::Config.load opts.config
config.files = opts.files
config.formatter = Ameba::Formatter::BaseFormatter.new if opts.silent
configure_formatter(config, opts)
configure_rules(config, opts)
runner = Ameba.run(config)
generate_config_file(config, runner, opts) if opts.generate
exit 1 unless runner.success?
exit 1 unless Ameba.run(config).success?
rescue e
puts "Error: #{e.message}"
exit 255
@ -71,14 +69,14 @@ module Ameba::Cli
end
end
private def generate_config_file(config, runner, opts)
failed_rules =
runner.sources
.map { |s| s.errors.map &.rule.name }
.flatten
.uniq!
failed_rules.each { |rule| config.update_rule rule, enabled: false }
File.write(opts.config, config.to_yaml)
private def configure_formatter(config, opts)
if opts.silent
config.formatter = Ameba::Formatter::BaseFormatter.new
elsif opts.generate
config.formatter = Ameba::Formatter::TODOFormatter.new
else
config.formatter = Ameba::Formatter::DotFormatter.new
end
end
private def print_version

View file

@ -20,7 +20,7 @@ class Ameba::Config
# Creates a new instance of `Ameba::Config` based on YAML parameters.
#
# `Config.load` uses this constructor to instantiate new config by YAML file.
protected def initialize(@config : Hash(YAML::Type, YAML::Type))
protected def initialize(@config : YAML::Any)
@rules = Rule.rules.map &.new(config)
end
@ -31,9 +31,9 @@ class Ameba::Config
# ```
#
def self.load(path = PATH)
content = File.exists?(path) ? File.read path : "{}"
Config.new YAML.parse(content).as_h
rescue e
content = File.exists?(path) ? File.read path : ""
Config.new YAML.parse(content)
rescue
raise "Config file is invalid"
end
@ -80,15 +80,6 @@ class Ameba::Config
@rules[index] = rule
end
def to_yaml(yaml : YAML::Builder)
yaml.mapping do
rules.each do |rule|
rule.name.to_yaml(yaml)
rule.to_yaml(yaml)
end
end
end
private def default_files
Dir["**/*.cr"].reject(&.starts_with? "lib/")
end
@ -158,8 +149,10 @@ class Ameba::Config
properties {}
def self.new(config = nil)
yaml = config.try &.[class_name]?.try &.to_yaml || "{}"
from_yaml yaml
if (raw = config.try &.raw).is_a? Hash
yaml = raw[class_name]?.try &.to_yaml
end
from_yaml yaml || "{}"
end
end
end

View file

@ -21,7 +21,7 @@ module Ameba::Formatter
# Reports a message when inspection is finished.
def finished(sources)
output << "\n\n"
failed_sources = sources.reject { |s| s.valid? }
failed_sources = sources.reject &.valid?
failed_sources.each do |source|
source.errors.each do |error|

View file

@ -0,0 +1,59 @@
module Ameba::Formatter
# A formatter that creates a todo config.
# Basically, it takes all errors reported and disables corresponding rules
# or excludes failed sources from these rules.
class TODOFormatter < DotFormatter
@io : IO::FileDescriptor | IO::Memory
def initialize(@output = STDOUT, @io = File.new(Config::PATH, mode: "w"))
end
def finished(sources)
super
errors = sources.map(&.errors).flatten
generate_todo_config errors if errors.any?
if (io = @io).is_a?(File)
@output << "Created #{io.path}\n"
end
end
private def generate_todo_config(errors)
@io << header
rule_errors_map(errors).each do |rule, rule_errors|
@io << "\n# Problems found: #{rule_errors.size}"
@io << rule_todo(rule, rule_errors).gsub("---", "")
end
ensure
@io.flush
end
private def rule_errors_map(errors)
Hash(Rule::Base, Array(Source::Error)).new.tap do |h|
errors.each do |error|
h[error.rule] ||= Array(Source::Error).new
h[error.rule] << error
end
end
end
private def header
<<-HEADER
# This configuration file was generated by `ameba --gen-config`
# on #{Time.now} using Ameba version #{VERSION}.
# The point is for the user to remove these configuration records
# one by one as the reported problems are removed from the code base.
HEADER
end
private def rule_todo(rule, errors)
rule.enabled = false
YAML.build do |yaml|
yaml.mapping do
rule.name.to_yaml(yaml)
rule.to_yaml(yaml)
end
end
end
end
end