mirror of
https://gitea.invidious.io/iv-org/shard-ameba.git
synced 2024-08-15 00:53:29 +00:00
Document configuration properties & specs
This commit is contained in:
parent
822a69b81c
commit
06855816d7
22 changed files with 325 additions and 8 deletions
|
@ -41,7 +41,7 @@ Or just compile it from sources `make install`.
|
|||
|
||||
## Usage
|
||||
|
||||
Run `ameba` binary to catch code issues within you project:
|
||||
Run `ameba` binary within your project directory to catch code issues:
|
||||
|
||||
```sh
|
||||
$ ameba
|
||||
|
@ -63,6 +63,12 @@ Finished in 10.53 milliseconds
|
|||
52 inspected, 3 failures.
|
||||
```
|
||||
|
||||
## Configuration
|
||||
|
||||
It is possible to configure or even disable specific rules using YAML configuration file.
|
||||
By default Ameba is looking for `.ameba.yml` in a project root directory.
|
||||
Copy and adjust [existed example](config/ameba.yml).
|
||||
|
||||
## Write a new Rule
|
||||
|
||||
Adding a new rule is as simple as inheriting from `Rule::Base` struct and implementing
|
||||
|
|
67
config/ameba.yml
Normal file
67
config/ameba.yml
Normal file
|
@ -0,0 +1,67 @@
|
|||
ComaprisonToBoolean:
|
||||
# Disallows comparison to booleans in conditions.
|
||||
Enabled: true
|
||||
|
||||
ConstantNames:
|
||||
# Enforces constant names to be in a screaming case.
|
||||
Enabled: true
|
||||
|
||||
DebuggerStatement:
|
||||
# Disallows calls to debugger.
|
||||
Enabled: true
|
||||
|
||||
EmptyExpression:
|
||||
# Disallows empty expressions.
|
||||
Enabled: true
|
||||
|
||||
LargeNumbers:
|
||||
# A rule that disallows usage of large numbers without underscore.
|
||||
Enabled: true
|
||||
|
||||
LineLength:
|
||||
# Disallows lines longer that MaxLength number of symbols.
|
||||
Enabled: true
|
||||
MaxLength: 80
|
||||
|
||||
LiteralInCondition:
|
||||
# Disallows useless conditional statements that contain a literal in place
|
||||
# of a variable or predicate function.
|
||||
Enabled: true
|
||||
|
||||
LiteralInInterpolation:
|
||||
# Disallows useless string interpolations that contain a literal value
|
||||
# instead of a variable or function.
|
||||
Enabled: true
|
||||
|
||||
MethodNames:
|
||||
# Enforces method names to be in the underscored case.
|
||||
Enabled: true
|
||||
|
||||
NegatedConditionsInUnless:
|
||||
# Disallows negated conditions in unless.
|
||||
Enabled: true
|
||||
|
||||
PredicateName:
|
||||
# Disallows tautological predicate names, meaning those that start with
|
||||
# the prefix `has_` or the prefix `is_`.
|
||||
Enabled: true
|
||||
|
||||
TrailingBlankLines:
|
||||
# Disallows trailing blank lines at the end of the source file.
|
||||
Enabled: true
|
||||
|
||||
TrailingWhitespace:
|
||||
# Disallows trailing whitespaces.
|
||||
Enabled: true
|
||||
|
||||
TypeNames:
|
||||
# Enforces type names in a camelcase manner.
|
||||
Enabled: true
|
||||
|
||||
UnlessElse:
|
||||
# Disallows the use of an `else` block with `unless`.
|
||||
Enabled: true
|
||||
|
||||
VariableNames:
|
||||
# Enforces variable names to be in the underscored case.
|
||||
Enabled: true
|
58
spec/ameba/config_spec.cr
Normal file
58
spec/ameba/config_spec.cr
Normal file
|
@ -0,0 +1,58 @@
|
|||
require "../spec_helper"
|
||||
|
||||
module Ameba
|
||||
describe Config do
|
||||
config_sample = "config/ameba.yml"
|
||||
|
||||
describe ".load" do
|
||||
it "loads custom config" do
|
||||
config = Config.load config_sample
|
||||
config.should_not be_nil
|
||||
config.files.should_not be_nil
|
||||
config.formatter.should_not be_nil
|
||||
end
|
||||
|
||||
it "loads default config" do
|
||||
config = Config.load
|
||||
config.should_not be_nil
|
||||
config.files.should_not be_nil
|
||||
config.formatter.should_not be_nil
|
||||
end
|
||||
end
|
||||
|
||||
describe "#files, #files=" do
|
||||
config = Config.load config_sample
|
||||
|
||||
it "holds source files" do
|
||||
config.files.should contain "spec/ameba/config_spec.cr"
|
||||
end
|
||||
|
||||
it "allows to set files" do
|
||||
config.files = ["file.cr"]
|
||||
config.files.should eq ["file.cr"]
|
||||
end
|
||||
end
|
||||
|
||||
describe "#formatter, formatter=" do
|
||||
config = Config.load config_sample
|
||||
formatter = DummyFormatter.new
|
||||
|
||||
it "contains default formatter" do
|
||||
config.formatter.should_not be_nil
|
||||
end
|
||||
|
||||
it "allows to set formatter" do
|
||||
config.formatter = formatter
|
||||
config.formatter.should eq formatter
|
||||
end
|
||||
end
|
||||
|
||||
describe "#subconfig" do
|
||||
it "returns a specific subconfig" do
|
||||
config = Config.load config_sample
|
||||
config.subconfig("NoSuchConfig").should be_nil
|
||||
config.subconfig(Rule::LineLength.new.name).should_not be_nil
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
58
spec/ameba/runner_spec.cr
Normal file
58
spec/ameba/runner_spec.cr
Normal file
|
@ -0,0 +1,58 @@
|
|||
require "../spec_helper"
|
||||
|
||||
module Ameba
|
||||
private def runner(files = [__FILE__], formatter = DummyFormatter.new)
|
||||
config = Config.load "config/ameba.yml"
|
||||
config.formatter = formatter
|
||||
config.files = files
|
||||
|
||||
Runner.new(config)
|
||||
end
|
||||
|
||||
describe Runner do
|
||||
formatter = DummyFormatter.new
|
||||
|
||||
describe "#run" do
|
||||
it "returns self" do
|
||||
runner.run.should_not be_nil
|
||||
end
|
||||
|
||||
it "calls started callback" do
|
||||
runner(formatter: formatter).run
|
||||
formatter.started_sources.should_not be_nil
|
||||
end
|
||||
|
||||
it "calls finished callback" do
|
||||
runner(formatter: formatter).run
|
||||
formatter.finished_sources.should_not be_nil
|
||||
end
|
||||
|
||||
it "calls source_started callback" do
|
||||
runner(formatter: formatter).run
|
||||
formatter.started_source.should_not be_nil
|
||||
end
|
||||
|
||||
it "calls source_finished callback" do
|
||||
runner(formatter: formatter).run
|
||||
formatter.finished_source.should_not be_nil
|
||||
end
|
||||
end
|
||||
|
||||
describe "#success?" do
|
||||
it "returns true if runner has not been run" do
|
||||
runner.success?.should be_true
|
||||
end
|
||||
|
||||
it "returns true if all sources are valid" do
|
||||
runner.run.success?.should be_true
|
||||
end
|
||||
|
||||
it "returns false if there are invalid sources" do
|
||||
s = Source.new %q(
|
||||
WrongConstant = 5
|
||||
)
|
||||
Runner.new([s], formatter).run.success?.should be_false
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
|
@ -7,6 +7,29 @@ module Ameba
|
|||
end
|
||||
end
|
||||
|
||||
class DummyFormatter < Formatter::BaseFormatter
|
||||
property started_sources : Array(Source)?
|
||||
property finished_sources : Array(Source)?
|
||||
property started_source : Source?
|
||||
property finished_source : Source?
|
||||
|
||||
def started(sources)
|
||||
@started_sources = sources
|
||||
end
|
||||
|
||||
def source_finished(source : Source)
|
||||
@started_source = source
|
||||
end
|
||||
|
||||
def source_started(source : Source)
|
||||
@finished_source = source
|
||||
end
|
||||
|
||||
def finished(sources)
|
||||
@finished_sources = sources
|
||||
end
|
||||
end
|
||||
|
||||
struct BeValidExpectation
|
||||
def match(source)
|
||||
source.valid?
|
||||
|
|
|
@ -8,10 +8,18 @@ module Ameba::Rule
|
|||
# bar != false
|
||||
# false === baz
|
||||
# ```
|
||||
#
|
||||
# This is because these expressions evaluate to `true` or `false`, so you
|
||||
# could get the same result by using either the variable directly,
|
||||
# or negating the variable.
|
||||
#
|
||||
# YAML configuration example:
|
||||
#
|
||||
# ```
|
||||
# ComparisonToBoolean:
|
||||
# Enabled: true
|
||||
# ```
|
||||
#
|
||||
struct ComparisonToBoolean < Base
|
||||
def test(source)
|
||||
AST::Visitor.new self, source
|
||||
|
|
|
@ -15,6 +15,13 @@ module Ameba::Rule
|
|||
# Wrong_NAME = 2
|
||||
# ```
|
||||
#
|
||||
# YAML configuration example:
|
||||
#
|
||||
# ```
|
||||
# ConstantNames:
|
||||
# Enabled: true
|
||||
# ```
|
||||
#
|
||||
struct ConstantNames < Base
|
||||
def test(source)
|
||||
AST::Visitor.new self, source
|
||||
|
|
|
@ -4,6 +4,13 @@ module Ameba::Rule
|
|||
# This is because we don't want debugger breakpoints accidentally being
|
||||
# committed into our codebase.
|
||||
#
|
||||
# YAML configuration example:
|
||||
#
|
||||
# ```
|
||||
# DebuggerStatement:
|
||||
# Enabled: true
|
||||
# ```
|
||||
#
|
||||
struct DebuggerStatement < Base
|
||||
def test(source)
|
||||
AST::Visitor.new self, source
|
||||
|
|
|
@ -21,6 +21,13 @@ module Ameba::Rule
|
|||
# end
|
||||
# ```
|
||||
#
|
||||
# YAML configuration example:
|
||||
#
|
||||
# ```
|
||||
# EmptyExpression:
|
||||
# Enabled: true
|
||||
# ```
|
||||
#
|
||||
struct EmptyExpression < Base
|
||||
include AST::Util
|
||||
|
||||
|
|
|
@ -19,6 +19,13 @@ module Ameba::Rule
|
|||
# 5.123_45
|
||||
# ```
|
||||
#
|
||||
# YAML configuration example:
|
||||
#
|
||||
# ```
|
||||
# LargeNumbers:
|
||||
# Enabled: true
|
||||
# ```
|
||||
#
|
||||
struct LargeNumbers < Base
|
||||
def test(source)
|
||||
Tokenizer.new(source).run do |token|
|
||||
|
|
|
@ -8,6 +8,7 @@ module Ameba::Rule
|
|||
# Enabled: true
|
||||
# MaxLength: 100
|
||||
# ```
|
||||
#
|
||||
struct LineLength < Base
|
||||
prop max_length = 80
|
||||
|
||||
|
|
|
@ -13,6 +13,13 @@ module Ameba::Rule
|
|||
# end
|
||||
# ```
|
||||
#
|
||||
# YAML configuration example:
|
||||
#
|
||||
# ```
|
||||
# LiteralInCondition:
|
||||
# Enabled: true
|
||||
# ```
|
||||
#
|
||||
struct LiteralInCondition < Base
|
||||
include AST::Util
|
||||
|
||||
|
|
|
@ -9,6 +9,13 @@ module Ameba::Rule
|
|||
# "There are #{4} cats"
|
||||
# ```
|
||||
#
|
||||
# YAML configuration example:
|
||||
#
|
||||
# ```
|
||||
# LiteralInInterpolation
|
||||
# Enabled: true
|
||||
# ```
|
||||
#
|
||||
struct LiteralInInterpolation < Base
|
||||
include AST::Util
|
||||
|
||||
|
|
|
@ -30,6 +30,14 @@ module Ameba::Rule
|
|||
# end
|
||||
# end
|
||||
# ```
|
||||
#
|
||||
# YAML configuration example:
|
||||
#
|
||||
# ```
|
||||
# MethodNames:
|
||||
# Enabled: true
|
||||
# ```
|
||||
#
|
||||
struct MethodNames < Base
|
||||
def test(source)
|
||||
AST::Visitor.new self, source
|
||||
|
|
|
@ -20,6 +20,13 @@ module Ameba::Rule
|
|||
# It is pretty difficult to wrap your head around a block of code
|
||||
# that is executed if a negated condition is NOT met.
|
||||
#
|
||||
# YAML configuration example:
|
||||
#
|
||||
# ```
|
||||
# NegatedConditionsInUnless:
|
||||
# Enabled: true
|
||||
# ```
|
||||
#
|
||||
struct NegatedConditionsInUnless < Base
|
||||
def test(source)
|
||||
AST::Visitor.new self, source
|
||||
|
|
|
@ -22,6 +22,13 @@ module Ameba::Rule
|
|||
# end
|
||||
# ```
|
||||
#
|
||||
# YAML configuration example:
|
||||
#
|
||||
# ```
|
||||
# PredicateName:
|
||||
# Enabled: true
|
||||
# ```
|
||||
#
|
||||
struct PredicateName < Base
|
||||
def test(source)
|
||||
AST::Visitor.new self, source
|
||||
|
|
|
@ -1,6 +1,13 @@
|
|||
module Ameba::Rule
|
||||
# A rule that disallows trailing blank lines at the end of the source file.
|
||||
#
|
||||
# YAML configuration example:
|
||||
#
|
||||
# ```
|
||||
# TrailingBlankLines:
|
||||
# Enabled: true
|
||||
# ```
|
||||
#
|
||||
struct TrailingBlankLines < Base
|
||||
def test(source)
|
||||
if source.lines.size > 1 && source.lines[-2, 2].join.strip.empty?
|
||||
|
|
|
@ -1,6 +1,13 @@
|
|||
module Ameba::Rule
|
||||
# A rule that disallows trailing whitespaces.
|
||||
#
|
||||
# YAML configuration example:
|
||||
#
|
||||
# ```
|
||||
# TrailingWhitespace:
|
||||
# Enabled: true
|
||||
# ```
|
||||
#
|
||||
struct TrailingWhitespace < Base
|
||||
def test(source)
|
||||
source.lines.each_with_index do |line, index|
|
||||
|
|
|
@ -45,6 +45,13 @@ module Ameba::Rule
|
|||
# end
|
||||
# ```
|
||||
#
|
||||
# YAML configuration example:
|
||||
#
|
||||
# ```
|
||||
# TypeNames:
|
||||
# Enabled: true
|
||||
# ```
|
||||
#
|
||||
struct TypeNames < Base
|
||||
def test(source)
|
||||
AST::Visitor.new self, source
|
||||
|
|
|
@ -36,6 +36,13 @@ module Ameba::Rule
|
|||
# end
|
||||
# ```
|
||||
#
|
||||
# YAML configuration example:
|
||||
#
|
||||
# ```
|
||||
# UnlessElse:
|
||||
# Enabled: true
|
||||
# ```
|
||||
#
|
||||
struct UnlessElse < Base
|
||||
def test(source)
|
||||
AST::Visitor.new self, source
|
||||
|
|
|
@ -24,6 +24,13 @@ module Ameba::Rule
|
|||
# wrong_Name = 2
|
||||
# ```
|
||||
#
|
||||
# YAML configuration example:
|
||||
#
|
||||
# ```
|
||||
# VariableNames:
|
||||
# Enabled: true
|
||||
# ```
|
||||
#
|
||||
struct VariableNames < Base
|
||||
def test(source)
|
||||
AST::Visitor.new self, source
|
||||
|
|
|
@ -10,6 +10,10 @@ module Ameba
|
|||
@formatter = config.formatter
|
||||
end
|
||||
|
||||
def initialize(@sources, @formatter)
|
||||
@rules = load_rules nil
|
||||
end
|
||||
|
||||
def run
|
||||
@formatter.started @sources
|
||||
@sources.each do |source|
|
||||
|
@ -28,13 +32,6 @@ module Ameba
|
|||
@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] }
|
||||
|
|
Loading…
Reference in a new issue