Ameba::Rule -> Ameba::Rule::Base

This commit is contained in:
Vitalii Elenhaupt 2017-11-07 23:50:25 +02:00
parent b6c0d3e8ad
commit 80e2ab4f55
No known key found for this signature in database
GPG key ID: 7558EF3A4056C706
39 changed files with 79 additions and 73 deletions

View file

@ -65,11 +65,11 @@ Finished in 10.53 milliseconds
## Write a new Rule
Adding a new rule is as simple as inheriting from `Rule` struct and implementing
Adding a new rule is as simple as inheriting from `Rule::Base` struct and implementing
your logic to detect a problem:
```crystal
struct DebuggerStatement < Rule
struct DebuggerStatement < Rule::Base
# This is a required method to be implemented by the rule.
# Source will be passed here. If rule finds an issue in this source,
# it reports an error:

View file

@ -1,7 +1,7 @@
require "../../spec/spec_helper"
module Ameba
describe Rule do
describe Rule::Base do
describe "#catch" do
it "accepts and returns source" do
s = Source.new "", ""
@ -14,7 +14,9 @@ module Ameba
DummyRule.new.name.should eq "Ameba::DummyRule"
end
end
end
describe Rule do
describe ".rules" do
it "returns a list of all defined rules" do
Rule.rules.includes?(DummyRule).should be_true

View file

@ -1,6 +1,6 @@
require "../../spec_helper"
module Ameba::Rules
module Ameba::Rule
subject = ComparisonToBoolean.new
describe ComparisonToBoolean do

View file

@ -1,17 +1,17 @@
require "../../spec_helper"
module Ameba
subject = Rules::ConstantNames.new
subject = Rule::ConstantNames.new
private def it_reports_constant(code, expected)
it "reports constant name #{expected}" do
s = Source.new code
Rules::ConstantNames.new.catch(s).should_not be_valid
Rule::ConstantNames.new.catch(s).should_not be_valid
s.errors.first.message.should contain expected
end
end
describe Rules::ConstantNames do
describe Rule::ConstantNames do
it "passes if type names are screaming-cased" do
s = Source.new %(
LUCKY_NUMBERS = [3, 7, 11]

View file

@ -1,6 +1,6 @@
require "../../spec_helper"
module Ameba::Rules
module Ameba::Rule
subject = DebuggerStatement.new
describe DebuggerStatement do

View file

@ -1,17 +1,17 @@
require "../../spec_helper"
module Ameba
subject = Rules::EmptyExpression.new
subject = Rule::EmptyExpression.new
def it_detects_empty_expression(code)
it "detects empty expression" do
s = Source.new code
rule = Rules::EmptyExpression.new
rule = Rule::EmptyExpression.new
rule.catch(s).should_not be_valid
end
end
describe Rules::EmptyExpression do
describe Rule::EmptyExpression do
it "passes if there is no empty expression" do
s = Source.new %(
def method()

View file

@ -1,17 +1,17 @@
require "../../spec_helper"
module Ameba
subject = Rules::LargeNumbers.new
subject = Rule::LargeNumbers.new
private def it_transforms(number, expected)
it "transforms large number #{number}" do
s = Source.new number
Rules::LargeNumbers.new.catch(s).should_not be_valid
Rule::LargeNumbers.new.catch(s).should_not be_valid
s.errors.first.message.should contain expected
end
end
describe Rules::LargeNumbers do
describe Rule::LargeNumbers do
it "passes if large number does not require underscore" do
s = Source.new %q(
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15

View file

@ -1,6 +1,6 @@
require "../../spec_helper"
module Ameba::Rules
module Ameba::Rule
subject = LineLength.new
long_line = "*" * 81

View file

@ -1,6 +1,6 @@
require "../../spec_helper"
module Ameba::Rules
module Ameba::Rule
subject = LiteralInCondition.new
describe LiteralInCondition do

View file

@ -1,6 +1,6 @@
require "../../spec_helper"
module Ameba::Rules
module Ameba::Rule
subject = LiteralInInterpolation.new
describe LiteralInInterpolation do

View file

@ -1,17 +1,17 @@
require "../../spec_helper"
module Ameba
subject = Rules::MethodNames.new
subject = Rule::MethodNames.new
private def it_reports_method_name(code, expected)
it "reports method name #{expected}" do
s = Source.new code
Rules::MethodNames.new.catch(s).should_not be_valid
Rule::MethodNames.new.catch(s).should_not be_valid
s.errors.first.message.should contain expected
end
end
describe Rules::MethodNames do
describe Rule::MethodNames do
it "passes if method names are underscore-cased" do
s = Source.new %(
class Person

View file

@ -1,6 +1,6 @@
require "../../spec_helper"
module Ameba::Rules
module Ameba::Rule
subject = NegatedConditionsInUnless.new
describe NegatedConditionsInUnless do

View file

@ -1,6 +1,6 @@
require "../../spec_helper"
module Ameba::Rules
module Ameba::Rule
subject = PredicateName.new
describe PredicateName do

View file

@ -1,6 +1,6 @@
require "../../spec_helper"
module Ameba::Rules
module Ameba::Rule
subject = TrailingBlankLines.new
describe TrailingBlankLines do

View file

@ -1,6 +1,6 @@
require "../../spec_helper"
module Ameba::Rules
module Ameba::Rule
subject = TrailingWhitespace.new
describe TrailingWhitespace do

View file

@ -1,17 +1,17 @@
require "../../spec_helper"
module Ameba
subject = Rules::TypeNames.new
subject = Rule::TypeNames.new
private def it_reports_name(code, expected)
it "reports type name #{expected}" do
s = Source.new code
Rules::TypeNames.new.catch(s).should_not be_valid
Rule::TypeNames.new.catch(s).should_not be_valid
s.errors.first.message.should contain expected
end
end
describe Rules::TypeNames do
describe Rule::TypeNames do
it "passes if type names are camelcased" do
s = Source.new %(
class ParseError < Exception

View file

@ -1,6 +1,6 @@
require "../../spec_helper"
module Ameba::Rules
module Ameba::Rule
subject = UnlessElse.new
describe UnlessElse do

View file

@ -1,17 +1,17 @@
require "../../spec_helper"
module Ameba
subject = Rules::VariableNames.new
subject = Rule::VariableNames.new
private def it_reports_var_name(code, expected)
it "reports method name #{expected}" do
s = Source.new code
Rules::VariableNames.new.catch(s).should_not be_valid
Rule::VariableNames.new.catch(s).should_not be_valid
s.errors.first.message.should contain expected
end
end
describe Rules::VariableNames do
describe Rule::VariableNames do
it "passes if var names are underscore-cased" do
s = Source.new %(
class Greeting

View file

@ -2,7 +2,7 @@ require "spec"
require "../src/ameba"
module Ameba
struct DummyRule < Ameba::Rule
struct DummyRule < Rule::Base
def test(source)
end
end

View file

@ -1,6 +1,6 @@
require "./ameba/*"
require "./ameba/ast/*"
require "./ameba/rules/*"
require "./ameba/rule/*"
require "./ameba/formatter/*"
module Ameba

View file

@ -21,7 +21,7 @@ module Ameba::AST
]
class Visitor < Crystal::Visitor
@rule : Rule
@rule : Rule::Base
@source : Source
def initialize(@rule, @source)

View file

@ -1,5 +1,5 @@
module Ameba
abstract struct Rule
module Ameba::Rule
abstract struct Base
abstract def test(source : Source)
def test(source : Source, node : Crystal::ASTNode)
@ -11,11 +11,15 @@ module Ameba
end
def name
self.class.name.gsub("Ameba::Rules::", "")
self.class.name.gsub("Ameba::Rule::", "")
end
def self.rules
protected def self.subclasses
{{ @type.subclasses }}
end
end
def self.rules
Base.subclasses
end
end

View file

@ -1,4 +1,4 @@
module Ameba::Rules
module Ameba::Rule
# A rule that disallows comparison to booleans.
#
# For example, these are considered invalid:
@ -12,7 +12,7 @@ module Ameba::Rules
# could get the same result by using either the variable directly,
# or negating the variable.
#
struct ComparisonToBoolean < Rule
struct ComparisonToBoolean < Base
def test(source)
AST::Visitor.new self, source
end

View file

@ -1,4 +1,4 @@
module Ameba::Rules
module Ameba::Rule
# A rule that enforces constant names to be in screaming case.
#
# For example, these constant names are considered valid:
@ -15,7 +15,7 @@ module Ameba::Rules
# Wrong_NAME = 2
# ```
#
struct ConstantNames < Rule
struct ConstantNames < Base
def test(source)
AST::Visitor.new self, source
end

View file

@ -1,10 +1,10 @@
module Ameba::Rules
module Ameba::Rule
# A rule that disallows calls to debugger.
#
# This is because we don't want debugger breakpoints accidentally being
# committed into our codebase.
#
struct DebuggerStatement < Rule
struct DebuggerStatement < Base
def test(source)
AST::Visitor.new self, source
end

View file

@ -1,4 +1,4 @@
module Ameba::Rules
module Ameba::Rule
# A rule that disallows empty expressions.
#
# This is considered invalid:
@ -21,7 +21,7 @@ module Ameba::Rules
# end
# ```
#
struct EmptyExpression < Rule
struct EmptyExpression < Base
include AST::Util
def test(source)

View file

@ -1,4 +1,4 @@
module Ameba::Rules
module Ameba::Rule
# A rule that disallows usage of large numbers without underscore.
# These do not affect the value of the number, but can help read
# large numbers more easily.
@ -19,7 +19,7 @@ module Ameba::Rules
# 5.123_45
# ```
#
struct LargeNumbers < Rule
struct LargeNumbers < Base
def test(source)
Tokenizer.new(source).run do |token|
next unless token.type == :NUMBER && decimal?(token.raw)

View file

@ -1,7 +1,7 @@
module Ameba::Rules
module Ameba::Rule
# A rule that disallows lines longer than 80 symbols.
#
struct LineLength < Rule
struct LineLength < Base
def test(source)
source.lines.each_with_index do |line, index|
next unless line.size > 80

View file

@ -1,4 +1,4 @@
module Ameba::Rules
module Ameba::Rule
# A rule that disallows useless conditional statements that contain a literal
# in place of a variable or predicate function.
#
@ -13,7 +13,7 @@ module Ameba::Rules
# end
# ```
#
struct LiteralInCondition < Rule
struct LiteralInCondition < Base
include AST::Util
def test(source)

View file

@ -1,4 +1,4 @@
module Ameba::Rules
module Ameba::Rule
# A rule that disallows useless string interpolations
# that contain a literal value instead of a variable or function.
#
@ -9,7 +9,7 @@ module Ameba::Rules
# "There are #{4} cats"
# ```
#
struct LiteralInInterpolation < Rule
struct LiteralInInterpolation < Base
include AST::Util
def test(source)

View file

@ -1,4 +1,4 @@
module Ameba::Rules
module Ameba::Rule
# A rule that enforces method names to be in underscored case.
#
# For example, these are considered valid:
@ -30,7 +30,7 @@ module Ameba::Rules
# end
# end
# ```
struct MethodNames < Rule
struct MethodNames < Base
def test(source)
AST::Visitor.new self, source
end

View file

@ -1,4 +1,4 @@
module Ameba::Rules
module Ameba::Rule
# A rule that disallows negated conditions in unless.
#
# For example, this is considered invalid:
@ -20,7 +20,7 @@ module Ameba::Rules
# It is pretty difficult to wrap your head around a block of code
# that is executed if a negated condition is NOT met.
#
struct NegatedConditionsInUnless < Rule
struct NegatedConditionsInUnless < Base
def test(source)
AST::Visitor.new self, source
end

View file

@ -1,4 +1,4 @@
module Ameba::Rules
module Ameba::Rule
# A rule that disallows tautological predicate names, meaning those that
# start with the prefix `has_` or the prefix `is_`.
#
@ -22,7 +22,7 @@ module Ameba::Rules
# end
# ```
#
struct PredicateName < Rule
struct PredicateName < Base
def test(source)
AST::Visitor.new self, source
end

View file

@ -1,7 +1,7 @@
module Ameba::Rules
module Ameba::Rule
# A rule that disallows trailing blank lines at the end of the source file.
#
struct TrailingBlankLines < Rule
struct TrailingBlankLines < Base
def test(source)
if source.lines.size > 1 && source.lines[-2, 2].join.strip.empty?
source.error self, source.location(source.lines.size, 1),

View file

@ -1,7 +1,7 @@
module Ameba::Rules
module Ameba::Rule
# A rule that disallows trailing whitespaces.
#
struct TrailingWhitespace < Rule
struct TrailingWhitespace < Base
def test(source)
source.lines.each_with_index do |line, index|
next unless line =~ /\s$/

View file

@ -1,4 +1,4 @@
module Ameba::Rules
module Ameba::Rule
# A rule that enforces type names in camelcase manner.
#
# For example, these are considered valid:
@ -45,7 +45,7 @@ module Ameba::Rules
# end
# ```
#
struct TypeNames < Rule
struct TypeNames < Base
def test(source)
AST::Visitor.new self, source
end

View file

@ -1,4 +1,4 @@
module Ameba::Rules
module Ameba::Rule
# A rule that disallows the use of an `else` block with the `unless`.
#
# For example, the rule considers these valid:
@ -36,7 +36,7 @@ module Ameba::Rules
# end
# ```
#
struct UnlessElse < Rule
struct UnlessElse < Base
def test(source)
AST::Visitor.new self, source
end

View file

@ -1,4 +1,4 @@
module Ameba::Rules
module Ameba::Rule
# A rule that enforces variable names to be in underscored case.
#
# For example, these variable names are considered valid:
@ -24,7 +24,7 @@ module Ameba::Rules
# wrong_Name = 2
# ```
#
struct VariableNames < Rule
struct VariableNames < Base
def test(source)
AST::Visitor.new self, source
end

View file

@ -5,9 +5,9 @@ module Ameba
# Represents an error caught by Ameba.
#
# Each error has the rule that created this error,
# position of the error and a message.
# location of the issue and a message.
record Error,
rule : Rule,
rule : Rule::Base,
location : Crystal::Location?,
message : String
@ -20,7 +20,7 @@ module Ameba
def initialize(@code : String, @path = nil)
end
def error(rule : Rule, location, message : String)
def error(rule : Rule::Base, location, message : String)
errors << Error.new rule, location, message
end