diff --git a/spec/ameba/ast/flow_expression_spec.cr b/spec/ameba/ast/flow_expression_spec.cr index d18b3686c..676a9ff92 100644 --- a/spec/ameba/ast/flow_expression_spec.cr +++ b/spec/ameba/ast/flow_expression_spec.cr @@ -52,7 +52,7 @@ module Ameba::AST CRYSTAL node = nodes.expressions_nodes.first flow_expression = FlowExpression.new node, false - flow_expression.unreachable_nodes.empty?.should eq true + flow_expression.unreachable_nodes.empty?.should be_true end it "returns nil if there is no unreachable node" do @@ -64,7 +64,7 @@ module Ameba::AST CRYSTAL node = nodes.expressions_nodes.first flow_expression = FlowExpression.new node, false - flow_expression.unreachable_nodes.empty?.should eq true + flow_expression.unreachable_nodes.empty?.should be_true end end end diff --git a/spec/ameba/ast/util_spec.cr b/spec/ameba/ast/util_spec.cr index 56169feda..447b1fb36 100644 --- a/spec/ameba/ast/util_spec.cr +++ b/spec/ameba/ast/util_spec.cr @@ -5,9 +5,9 @@ module Ameba::AST include Util end - subject = Test.new - describe Util do + subject = Test.new + describe "#literal?" do [ Crystal::ArrayLiteral.new, @@ -120,12 +120,12 @@ module Ameba::AST describe "#flow_command?" do it "returns true if this is return" do node = as_node("return 22") - subject.flow_command?(node, false).should eq true + subject.flow_command?(node, false).should be_true end it "returns true if this is a break in a loop" do node = as_node("break") - subject.flow_command?(node, true).should eq true + subject.flow_command?(node, true).should be_true end it "returns false if this is a break out of loop" do @@ -135,7 +135,7 @@ module Ameba::AST it "returns true if this is a next in a loop" do node = as_node("next") - subject.flow_command?(node, true).should eq true + subject.flow_command?(node, true).should be_true end it "returns false if this is a next out of loop" do @@ -145,17 +145,17 @@ module Ameba::AST it "returns true if this is raise" do node = as_node("raise e") - subject.flow_command?(node, false).should eq true + subject.flow_command?(node, false).should be_true end it "returns true if this is exit" do node = as_node("exit") - subject.flow_command?(node, false).should eq true + subject.flow_command?(node, false).should be_true end it "returns true if this is abort" do node = as_node("abort") - subject.flow_command?(node, false).should eq true + subject.flow_command?(node, false).should be_true end it "returns false otherwise" do @@ -167,7 +167,7 @@ module Ameba::AST describe "#flow_expression?" do it "returns true if this is a flow command" do node = as_node("return") - subject.flow_expression?(node, true).should eq true + subject.flow_expression?(node, true).should be_true end it "returns true if this is if-else consumed by flow expressions" do @@ -178,7 +178,7 @@ module Ameba::AST return :bar end CRYSTAL - subject.flow_expression?(node, false).should eq true + subject.flow_expression?(node, false).should be_true end it "returns true if this is unless-else consumed by flow expressions" do @@ -189,7 +189,7 @@ module Ameba::AST return :bar end CRYSTAL - subject.flow_expression?(node).should eq true + subject.flow_expression?(node).should be_true end it "returns true if this is case consumed by flow expressions" do @@ -203,7 +203,7 @@ module Ameba::AST return 3 end CRYSTAL - subject.flow_expression?(node).should eq true + subject.flow_expression?(node).should be_true end it "returns true if this is exception handler consumed by flow expressions" do @@ -214,7 +214,7 @@ module Ameba::AST return e end CRYSTAL - subject.flow_expression?(node).should eq true + subject.flow_expression?(node).should be_true end it "returns true if this while consumed by flow expressions" do @@ -223,7 +223,7 @@ module Ameba::AST return end CRYSTAL - subject.flow_expression?(node).should eq true + subject.flow_expression?(node).should be_true end it "returns false if this while with break" do @@ -241,7 +241,7 @@ module Ameba::AST return end CRYSTAL - subject.flow_expression?(node).should eq true + subject.flow_expression?(node).should be_true end it "returns false if this until with break" do @@ -259,7 +259,7 @@ module Ameba::AST exp2 return CRYSTAL - subject.flow_expression?(node).should eq true + subject.flow_expression?(node).should be_true end it "returns false otherwise" do @@ -274,7 +274,7 @@ module Ameba::AST describe "#raise?" do it "returns true if this is a raise method call" do node = as_node "raise e" - subject.raise?(node).should eq true + subject.raise?(node).should be_true end it "returns false if it has a receiver" do @@ -291,12 +291,12 @@ module Ameba::AST describe "#exit?" do it "returns true if this is a exit method call" do node = as_node "exit" - subject.exit?(node).should eq true + subject.exit?(node).should be_true end it "returns true if this is a exit method call with one argument" do node = as_node "exit 1" - subject.exit?(node).should eq true + subject.exit?(node).should be_true end it "returns false if it has a receiver" do @@ -313,17 +313,17 @@ module Ameba::AST describe "#abort?" do it "returns true if this is an abort method call" do node = as_node "abort" - subject.abort?(node).should eq true + subject.abort?(node).should be_true end it "returns true if this is an abort method call with one argument" do node = as_node "abort \"message\"" - subject.abort?(node).should eq true + subject.abort?(node).should be_true end it "returns true if this is an abort method call with two arguments" do node = as_node "abort \"message\", 1" - subject.abort?(node).should eq true + subject.abort?(node).should be_true end it "returns false if it has a receiver" do @@ -340,7 +340,7 @@ module Ameba::AST describe "#loop?" do it "returns true if this is a loop method call" do node = as_node "loop" - subject.loop?(node).should eq true + subject.loop?(node).should be_true end it "returns false if it has a receiver" do diff --git a/spec/ameba/ast/variabling/reference_spec.cr b/spec/ameba/ast/variabling/reference_spec.cr index 155270918..e057d3d93 100644 --- a/spec/ameba/ast/variabling/reference_spec.cr +++ b/spec/ameba/ast/variabling/reference_spec.cr @@ -4,7 +4,8 @@ module Ameba::AST describe Reference do it "is derived from a Variable" do node = Crystal::Var.new "foo" - Reference.new(node, Scope.new as_node "foo = 1").is_a?(Variable).should be_true + ref = Reference.new(node, Scope.new as_node "foo = 1") + ref.should be_a Variable end end end diff --git a/spec/ameba/cli/cmd_spec.cr b/spec/ameba/cli/cmd_spec.cr index 0f174243e..fb5a83f76 100644 --- a/spec/ameba/cli/cmd_spec.cr +++ b/spec/ameba/cli/cmd_spec.cr @@ -66,7 +66,7 @@ module Ameba::Cli it "accepts --rules flag" do c = Cli.parse_args %w[--rules] - c.rules?.should eq true + c.rules?.should be_true end it "defaults all? flag to false" do @@ -76,7 +76,7 @@ module Ameba::Cli it "accepts --all flag" do c = Cli.parse_args %w[--all] - c.all?.should eq true + c.all?.should be_true end it "accepts --gen-config flag" do diff --git a/spec/ameba/formatter/disabled_formatter_spec.cr b/spec/ameba/formatter/disabled_formatter_spec.cr index 5c338ae00..e2abbaaa6 100644 --- a/spec/ameba/formatter/disabled_formatter_spec.cr +++ b/spec/ameba/formatter/disabled_formatter_spec.cr @@ -5,6 +5,10 @@ module Ameba::Formatter output = IO::Memory.new subject = DisabledFormatter.new output + before_each do + output.clear + end + describe "#finished" do it "writes a final message" do subject.finished [Source.new ""] @@ -24,7 +28,6 @@ module Ameba::Formatter log.should contain "#{path}:1 #{ErrorRule.rule_name}" log.should contain "#{path}:2 #{NamedRule.rule_name}" ensure - output.clear Colorize.enabled = true end diff --git a/spec/ameba/formatter/explain_formatter_spec.cr b/spec/ameba/formatter/explain_formatter_spec.cr index c7aacf9c2..eac1dbc8b 100644 --- a/spec/ameba/formatter/explain_formatter_spec.cr +++ b/spec/ameba/formatter/explain_formatter_spec.cr @@ -1,21 +1,24 @@ require "../../spec_helper" -module Ameba - def explanation(source) - output = IO::Memory.new - ErrorRule.new.catch(source) - location = {file: "source.cr", line: 1, column: 1} - Formatter::ExplainFormatter.new(output, location).finished([source]) - output.to_s - end +private LOCATION = {file: "source.cr", line: 1, column: 1} + +private def explanation(source) + Ameba::ErrorRule.new.catch(source) - describe Formatter::ExplainFormatter do + output = IO::Memory.new + Ameba::Formatter::ExplainFormatter.new(output, LOCATION).finished([source]) + output.to_s +end + +module Ameba::Formatter + describe ExplainFormatter do describe "#location" do it "returns crystal location" do - location = Formatter::ExplainFormatter - .new(STDOUT, {file: "compiler.cr", line: 3, column: 8}).location + location = ExplainFormatter + .new(STDOUT, {file: "compiler.cr", line: 3, column: 8}) + .location - location.is_a?(Crystal::Location).should be_true + location.should be_a Crystal::Location location.filename.should eq "compiler.cr" location.line_number.should eq 3 location.column_number.should eq 8 @@ -24,8 +27,10 @@ module Ameba describe "#output" do it "returns io" do - output = Formatter::ExplainFormatter - .new(STDOUT, {file: "compiler.cr", line: 3, column: 8}).output + output = ExplainFormatter + .new(STDOUT, {file: "compiler.cr", line: 3, column: 8}) + .output + output.should eq STDOUT end end diff --git a/spec/ameba/formatter/flycheck_formatter_spec.cr b/spec/ameba/formatter/flycheck_formatter_spec.cr index d9fda5fdc..2d45b8356 100644 --- a/spec/ameba/formatter/flycheck_formatter_spec.cr +++ b/spec/ameba/formatter/flycheck_formatter_spec.cr @@ -1,15 +1,16 @@ require "../../spec_helper" -private def flycheck - output = IO::Memory.new - Ameba::Formatter::FlycheckFormatter.new output -end - module Ameba::Formatter describe FlycheckFormatter do + output = IO::Memory.new + subject = FlycheckFormatter.new output + + before_each do + output.clear + end + context "problems not found" do it "reports nothing" do - subject = flycheck subject.source_finished Source.new "" subject.output.to_s.empty?.should be_true end @@ -19,7 +20,7 @@ module Ameba::Formatter it "reports an issue" do s = Source.new "a = 1", "source.cr" s.add_issue DummyRule.new, {1, 2}, "message" - subject = flycheck + subject.source_finished s subject.output.to_s.should eq( "source.cr:1:2: C: [#{DummyRule.rule_name}] message\n" @@ -29,7 +30,7 @@ module Ameba::Formatter it "properly reports multi-line message" do s = Source.new "a = 1", "source.cr" s.add_issue DummyRule.new, {1, 2}, "multi\nline" - subject = flycheck + subject.source_finished s subject.output.to_s.should eq( "source.cr:1:2: C: [#{DummyRule.rule_name}] multi line\n" @@ -39,7 +40,7 @@ module Ameba::Formatter it "reports nothing if location was not set" do s = Source.new "a = 1", "source.cr" s.add_issue DummyRule.new, Crystal::Nop.new, "message" - subject = flycheck + subject.source_finished s subject.output.to_s.should eq "" end diff --git a/spec/ameba/formatter/github_actions_formatter_spec.cr b/spec/ameba/formatter/github_actions_formatter_spec.cr index ebe0b32f2..1d4a7db90 100644 --- a/spec/ameba/formatter/github_actions_formatter_spec.cr +++ b/spec/ameba/formatter/github_actions_formatter_spec.cr @@ -24,7 +24,10 @@ module Ameba::Formatter source.add_issue DummyRule.new, location, location, "message\n2nd line" subject.source_finished(source) - output.to_s.should eq("::notice file=/path/to/file.cr,line=1,col=2,endLine=1,endColumn=2,title=Ameba/DummyRule::message%0A2nd line\n") + output.to_s.should eq( + "::notice file=/path/to/file.cr,line=1,col=2,endLine=1,endColumn=2," \ + "title=Ameba/DummyRule::message%0A2nd line\n" + ) end end @@ -78,8 +81,14 @@ module Ameba::Formatter summary.should contain "### Issues found:" summary.should contain "#### `src/source.cr` (**2** issues)" if repo && sha - summary.should contain "| [1-2](https://github.com/#{repo}/blob/#{sha}/src/source.cr#L1-L2) | Convention | Ameba/DummyRule | DummyRuleError |" - summary.should contain "| [1](https://github.com/#{repo}/blob/#{sha}/src/source.cr#L1) | Convention | Ameba/DummyRule | DummyRuleError 2 |" + summary.should contain( + "| [1-2](https://github.com/#{repo}/blob/#{sha}/src/source.cr#L1-L2) " \ + "| Convention | Ameba/DummyRule | DummyRuleError |" + ) + summary.should contain( + "| [1](https://github.com/#{repo}/blob/#{sha}/src/source.cr#L1) " \ + "| Convention | Ameba/DummyRule | DummyRuleError 2 |" + ) else summary.should contain "| 1-2 | Convention | Ameba/DummyRule | DummyRuleError |" summary.should contain "| 1 | Convention | Ameba/DummyRule | DummyRuleError 2 |" diff --git a/spec/ameba/formatter/json_formatter_spec.cr b/spec/ameba/formatter/json_formatter_spec.cr index 6011e4596..fca016bcf 100644 --- a/spec/ameba/formatter/json_formatter_spec.cr +++ b/spec/ameba/formatter/json_formatter_spec.cr @@ -1,18 +1,18 @@ require "../../spec_helper" -module Ameba - def get_result(sources = [Source.new ""]) - file = IO::Memory.new - formatter = Formatter::JSONFormatter.new file +private def get_result(sources = [Ameba::Source.new ""]) + output = IO::Memory.new + formatter = Ameba::Formatter::JSONFormatter.new output - formatter.started sources - sources.each { |source| formatter.source_finished source } - formatter.finished sources + formatter.started sources + sources.each { |source| formatter.source_finished source } + formatter.finished sources - JSON.parse file.to_s - end + JSON.parse(output.to_s) +end - describe Formatter::JSONFormatter do +module Ameba::Formatter + describe JSONFormatter do context "metadata" do it "shows ameba version" do get_result["metadata"]["ameba_version"].should eq Ameba::VERSION diff --git a/spec/ameba/formatter/todo_formatter_spec.cr b/spec/ameba/formatter/todo_formatter_spec.cr index 448cd10ad..00afbc898 100644 --- a/spec/ameba/formatter/todo_formatter_spec.cr +++ b/spec/ameba/formatter/todo_formatter_spec.cr @@ -1,7 +1,7 @@ require "../../spec_helper" require "file_utils" -CONFIG_PATH = Path[Dir.tempdir] / Ameba::Config::FILENAME +private CONFIG_PATH = Path[Dir.tempdir] / Ameba::Config::FILENAME module Ameba private def with_formatter(&) diff --git a/spec/ameba/formatter/util_spec.cr b/spec/ameba/formatter/util_spec.cr index 126500e1d..8597c06f5 100644 --- a/spec/ameba/formatter/util_spec.cr +++ b/spec/ameba/formatter/util_spec.cr @@ -5,9 +5,9 @@ module Ameba::Formatter include Util end - subject = Subject.new - describe Util do + subject = Subject.new + describe "#deansify" do it "returns given string without ANSI codes" do str = String.build do |io| diff --git a/spec/ameba/issue_spec.cr b/spec/ameba/issue_spec.cr index 08188eaf8..e2d2e1b39 100644 --- a/spec/ameba/issue_spec.cr +++ b/spec/ameba/issue_spec.cr @@ -24,7 +24,7 @@ module Ameba status: nil issue.location.to_s.should eq location.to_s - issue.end_location.should eq nil + issue.end_location.should be_nil end it "accepts end_location" do @@ -36,7 +36,7 @@ module Ameba message: "Blah", status: nil - issue.location.should eq nil + issue.location.should be_nil issue.end_location.to_s.should eq location.to_s end diff --git a/spec/ameba/rule/documentation/documentation_admonition_spec.cr b/spec/ameba/rule/documentation/documentation_admonition_spec.cr index b4c9e4052..cae65aea8 100644 --- a/spec/ameba/rule/documentation/documentation_admonition_spec.cr +++ b/spec/ameba/rule/documentation/documentation_admonition_spec.cr @@ -1,9 +1,9 @@ require "../../../spec_helper" module Ameba::Rule::Documentation - subject = DocumentationAdmonition.new - describe DocumentationAdmonition do + subject = DocumentationAdmonition.new + it "passes for comments with admonition mid-word/sentence" do subject.admonitions.each do |admonition| expect_no_issues subject, <<-CRYSTAL diff --git a/spec/ameba/rule/documentation/documentation_spec.cr b/spec/ameba/rule/documentation/documentation_spec.cr index 0d1b485be..3be29cea4 100644 --- a/spec/ameba/rule/documentation/documentation_spec.cr +++ b/spec/ameba/rule/documentation/documentation_spec.cr @@ -1,14 +1,14 @@ require "../../../spec_helper" module Ameba::Rule::Documentation - subject = Documentation.new - .tap(&.ignore_classes = false) - .tap(&.ignore_modules = false) - .tap(&.ignore_enums = false) - .tap(&.ignore_defs = false) - .tap(&.ignore_macros = false) - describe Documentation do + subject = Documentation.new + subject.ignore_classes = false + subject.ignore_modules = false + subject.ignore_enums = false + subject.ignore_defs = false + subject.ignore_macros = false + it "passes for undocumented private types" do expect_no_issues subject, <<-CRYSTAL private class Foo diff --git a/spec/ameba/rule/layout/line_length_spec.cr b/spec/ameba/rule/layout/line_length_spec.cr index 514f16a49..b8868288e 100644 --- a/spec/ameba/rule/layout/line_length_spec.cr +++ b/spec/ameba/rule/layout/line_length_spec.cr @@ -1,10 +1,10 @@ require "../../../spec_helper" module Ameba::Rule::Layout - subject = LineLength.new - long_line = "*" * (subject.max_length + 1) - describe LineLength do + subject = LineLength.new + long_line = "*" * (subject.max_length + 1) + it "passes if all lines are shorter than MaxLength symbols" do expect_no_issues subject, <<-CRYSTAL short line diff --git a/spec/ameba/rule/layout/trailing_blank_lines_spec.cr b/spec/ameba/rule/layout/trailing_blank_lines_spec.cr index 028ab496b..f87e24e59 100644 --- a/spec/ameba/rule/layout/trailing_blank_lines_spec.cr +++ b/spec/ameba/rule/layout/trailing_blank_lines_spec.cr @@ -1,9 +1,9 @@ require "../../../spec_helper" module Ameba::Rule::Layout - subject = TrailingBlankLines.new - describe TrailingBlankLines do + subject = TrailingBlankLines.new + it "passes if there is a blank line at the end of a source" do expect_no_issues subject, "a = 1\n" end diff --git a/spec/ameba/rule/layout/trailing_whitespace_spec.cr b/spec/ameba/rule/layout/trailing_whitespace_spec.cr index df376870f..0d63c112c 100644 --- a/spec/ameba/rule/layout/trailing_whitespace_spec.cr +++ b/spec/ameba/rule/layout/trailing_whitespace_spec.cr @@ -1,9 +1,9 @@ require "../../../spec_helper" module Ameba::Rule::Layout - subject = TrailingWhitespace.new - describe TrailingWhitespace do + subject = TrailingWhitespace.new + it "passes if all lines do not have trailing whitespace" do expect_no_issues subject, "no-whitespace" end diff --git a/spec/ameba/rule/lint/comparison_to_boolean_spec.cr b/spec/ameba/rule/lint/comparison_to_boolean_spec.cr index e99eba971..3253c0cc5 100644 --- a/spec/ameba/rule/lint/comparison_to_boolean_spec.cr +++ b/spec/ameba/rule/lint/comparison_to_boolean_spec.cr @@ -1,9 +1,9 @@ require "../../../spec_helper" module Ameba::Rule::Lint - subject = ComparisonToBoolean.new - describe ComparisonToBoolean do + subject = ComparisonToBoolean.new + it "passes if there is no comparison to boolean" do expect_no_issues subject, <<-CRYSTAL a = true diff --git a/spec/ameba/rule/lint/debug_calls_spec.cr b/spec/ameba/rule/lint/debug_calls_spec.cr index ffdc90ea0..f5ee5e804 100644 --- a/spec/ameba/rule/lint/debug_calls_spec.cr +++ b/spec/ameba/rule/lint/debug_calls_spec.cr @@ -1,9 +1,9 @@ require "../../../spec_helper" module Ameba::Rule::Lint - subject = DebugCalls.new - describe DebugCalls do + subject = DebugCalls.new + it "fails if there is a debug call" do subject.method_names.each do |name| source = expect_issue subject, <<-CRYSTAL, name: name diff --git a/spec/ameba/rule/lint/debugger_statement_spec.cr b/spec/ameba/rule/lint/debugger_statement_spec.cr index ad6942dff..1e52365b0 100644 --- a/spec/ameba/rule/lint/debugger_statement_spec.cr +++ b/spec/ameba/rule/lint/debugger_statement_spec.cr @@ -1,9 +1,9 @@ require "../../../spec_helper" module Ameba::Rule::Lint - subject = DebuggerStatement.new - describe DebuggerStatement do + subject = DebuggerStatement.new + it "passes if there is no debugger statement" do expect_no_issues subject, <<-CRYSTAL "this is not a debugger statement" diff --git a/spec/ameba/rule/lint/duplicated_require_spec.cr b/spec/ameba/rule/lint/duplicated_require_spec.cr index 031fd1952..fe4a72e3d 100644 --- a/spec/ameba/rule/lint/duplicated_require_spec.cr +++ b/spec/ameba/rule/lint/duplicated_require_spec.cr @@ -1,9 +1,9 @@ require "../../../spec_helper" module Ameba::Rule::Lint - subject = DuplicatedRequire.new - describe DuplicatedRequire do + subject = DuplicatedRequire.new + it "passes if there are no duplicated requires" do expect_no_issues subject, <<-CRYSTAL require "math" diff --git a/spec/ameba/rule/lint/empty_expression_spec.cr b/spec/ameba/rule/lint/empty_expression_spec.cr index 671f7ef61..e7a98fdcf 100644 --- a/spec/ameba/rule/lint/empty_expression_spec.cr +++ b/spec/ameba/rule/lint/empty_expression_spec.cr @@ -1,17 +1,17 @@ require "../../../spec_helper" -module Ameba - subject = Rule::Lint::EmptyExpression.new - - private def it_detects_empty_expression(code, *, file = __FILE__, line = __LINE__) - it "detects empty expression #{code.inspect}", file, line do - source = Source.new code - rule = Rule::Lint::EmptyExpression.new - rule.catch(source).should_not be_valid, file: file, line: line - end +private def it_detects_empty_expression(code, *, file = __FILE__, line = __LINE__) + it "detects empty expression #{code.inspect}", file, line do + source = Ameba::Source.new code + rule = Ameba::Rule::Lint::EmptyExpression.new + rule.catch(source).should_not be_valid, file: file, line: line end +end + +module Ameba::Rule::Lint + describe EmptyExpression do + subject = EmptyExpression.new - describe Rule::Lint::EmptyExpression do it "passes if there is no empty expression" do expect_no_issues subject, <<-CRYSTAL def method() diff --git a/spec/ameba/rule/lint/literal_assignments_in_expressions_spec.cr b/spec/ameba/rule/lint/literal_assignments_in_expressions_spec.cr index 2902a5f17..bc57461d1 100644 --- a/spec/ameba/rule/lint/literal_assignments_in_expressions_spec.cr +++ b/spec/ameba/rule/lint/literal_assignments_in_expressions_spec.cr @@ -7,9 +7,9 @@ LITERAL_SAMPLES = { } module Ameba::Rule::Lint - subject = LiteralAssignmentsInExpressions.new - describe LiteralAssignmentsInExpressions do + subject = LiteralAssignmentsInExpressions.new + it "passes if the assignment value is not a literal" do expect_no_issues subject, <<-CRYSTAL if a = b diff --git a/spec/ameba/rule/lint/literal_in_condition_spec.cr b/spec/ameba/rule/lint/literal_in_condition_spec.cr index 8150ad2bd..1997fdccf 100644 --- a/spec/ameba/rule/lint/literal_in_condition_spec.cr +++ b/spec/ameba/rule/lint/literal_in_condition_spec.cr @@ -1,9 +1,9 @@ require "../../../spec_helper" module Ameba::Rule::Lint - subject = LiteralInCondition.new - describe LiteralInCondition do + subject = LiteralInCondition.new + it "passes if there is not literals in conditional" do s = Source.new %( if a == 2 diff --git a/spec/ameba/rule/lint/literal_in_interpolation_spec.cr b/spec/ameba/rule/lint/literal_in_interpolation_spec.cr index 78487eecf..ef8260e7c 100644 --- a/spec/ameba/rule/lint/literal_in_interpolation_spec.cr +++ b/spec/ameba/rule/lint/literal_in_interpolation_spec.cr @@ -1,9 +1,9 @@ require "../../../spec_helper" module Ameba::Rule::Lint - subject = LiteralInInterpolation.new - describe LiteralInInterpolation do + subject = LiteralInInterpolation.new + it "passes with good interpolation examples" do expect_no_issues subject, <<-CRYSTAL name = "Ary" diff --git a/spec/ameba/rule/lint/literals_comparison_spec.cr b/spec/ameba/rule/lint/literals_comparison_spec.cr index ef75b6824..afccafc42 100644 --- a/spec/ameba/rule/lint/literals_comparison_spec.cr +++ b/spec/ameba/rule/lint/literals_comparison_spec.cr @@ -1,9 +1,9 @@ require "../../../spec_helper" module Ameba::Rule::Lint - subject = LiteralsComparison.new - describe LiteralsComparison do + subject = LiteralsComparison.new + it "passes for valid cases" do expect_no_issues subject, <<-CRYSTAL {start.year, start.month} == {stop.year, stop.month} diff --git a/spec/ameba/rule/lint/missing_block_argument_spec.cr b/spec/ameba/rule/lint/missing_block_argument_spec.cr index 90e9f93db..c82ecd375 100644 --- a/spec/ameba/rule/lint/missing_block_argument_spec.cr +++ b/spec/ameba/rule/lint/missing_block_argument_spec.cr @@ -1,9 +1,9 @@ require "../../../spec_helper" module Ameba::Rule::Lint - subject = MissingBlockArgument.new - describe MissingBlockArgument do + subject = MissingBlockArgument.new + it "passes if the block argument is defined" do expect_no_issues subject, <<-CRYSTAL def foo(&) diff --git a/spec/ameba/rule/lint/not_nil_after_no_bang_spec.cr b/spec/ameba/rule/lint/not_nil_after_no_bang_spec.cr index 7fe3a1fad..c9f61ac63 100644 --- a/spec/ameba/rule/lint/not_nil_after_no_bang_spec.cr +++ b/spec/ameba/rule/lint/not_nil_after_no_bang_spec.cr @@ -1,9 +1,9 @@ require "../../../spec_helper" module Ameba::Rule::Lint - subject = NotNilAfterNoBang.new - describe NotNilAfterNoBang do + subject = NotNilAfterNoBang.new + it "passes for valid cases" do expect_no_issues subject, <<-CRYSTAL (1..3).index(1).not_nil!(:foo) diff --git a/spec/ameba/rule/lint/not_nil_spec.cr b/spec/ameba/rule/lint/not_nil_spec.cr index 0f5881b26..92b011905 100644 --- a/spec/ameba/rule/lint/not_nil_spec.cr +++ b/spec/ameba/rule/lint/not_nil_spec.cr @@ -1,9 +1,9 @@ require "../../../spec_helper" module Ameba::Rule::Lint - subject = NotNil.new - describe NotNil do + subject = NotNil.new + it "passes for valid cases" do expect_no_issues subject, <<-CRYSTAL (1..3).first?.not_nil!(:foo) diff --git a/spec/ameba/rule/lint/spec_filename_spec.cr b/spec/ameba/rule/lint/spec_filename_spec.cr index fa3757484..ff12d36db 100644 --- a/spec/ameba/rule/lint/spec_filename_spec.cr +++ b/spec/ameba/rule/lint/spec_filename_spec.cr @@ -1,9 +1,9 @@ require "../../../spec_helper" module Ameba::Rule::Lint - subject = SpecFilename.new - describe SpecFilename do + subject = SpecFilename.new + it "passes if relative file path does not start with `spec/`" do expect_no_issues subject, code: "", path: "src/spec/foo.cr" expect_no_issues subject, code: "", path: "src/spec/foo/bar.cr" diff --git a/spec/ameba/rule/lint/trailing_rescue_exception_spec.cr b/spec/ameba/rule/lint/trailing_rescue_exception_spec.cr index a26373c74..3408f6e3c 100644 --- a/spec/ameba/rule/lint/trailing_rescue_exception_spec.cr +++ b/spec/ameba/rule/lint/trailing_rescue_exception_spec.cr @@ -1,25 +1,27 @@ require "../../../spec_helper" module Ameba::Rule::Lint - subject = TrailingRescueException.new + describe TrailingRescueException do + subject = TrailingRescueException.new - it "passes for trailing rescue with literal values" do - expect_no_issues subject, <<-CRYSTAL + it "passes for trailing rescue with literal values" do + expect_no_issues subject, <<-CRYSTAL puts "hello" rescue "world" puts :meow rescue 1234 CRYSTAL - end + end - it "passes for trailing rescue with class initialization" do - expect_no_issues subject, <<-CRYSTAL + it "passes for trailing rescue with class initialization" do + expect_no_issues subject, <<-CRYSTAL puts "hello" rescue MyClass.new CRYSTAL - end + end - it "fails if trailing rescue has exception name" do - expect_issue subject, <<-CRYSTAL + it "fails if trailing rescue has exception name" do + expect_issue subject, <<-CRYSTAL puts "hello" rescue MyException - # ^^^^^^^^^^^ error: Trailing rescues with a path aren't allowed, use a block rescue instead to filter by exception type + # ^^^^^^^^^^^ error: Use a block variant of `rescue` to filter by the exception type CRYSTAL + end end end diff --git a/spec/ameba/rule/lint/typos_spec.cr b/spec/ameba/rule/lint/typos_spec.cr index 50b2ca714..de9c71bb7 100644 --- a/spec/ameba/rule/lint/typos_spec.cr +++ b/spec/ameba/rule/lint/typos_spec.cr @@ -7,10 +7,10 @@ private def check_typos_bin! end module Ameba::Rule::Lint - subject = Typos.new - .tap(&.fail_on_error = true) - describe Typos do + subject = Typos.new + subject.fail_on_error = true + it "reports typos" do check_typos_bin! diff --git a/spec/ameba/rule/lint/unreachable_code_spec.cr b/spec/ameba/rule/lint/unreachable_code_spec.cr index 15aa93ac9..2cf447bc5 100644 --- a/spec/ameba/rule/lint/unreachable_code_spec.cr +++ b/spec/ameba/rule/lint/unreachable_code_spec.cr @@ -1,9 +1,9 @@ require "../../../spec_helper" module Ameba::Rule::Lint - subject = UnreachableCode.new - describe UnreachableCode do + subject = UnreachableCode.new + context "return" do it "reports if there is unreachable code after return" do s = Source.new %( diff --git a/spec/ameba/rule/lint/unused_argument_spec.cr b/spec/ameba/rule/lint/unused_argument_spec.cr index 0cff6a130..540284aa1 100644 --- a/spec/ameba/rule/lint/unused_argument_spec.cr +++ b/spec/ameba/rule/lint/unused_argument_spec.cr @@ -1,10 +1,10 @@ require "../../../spec_helper" module Ameba::Rule::Lint - subject = UnusedArgument.new - subject.ignore_defs = false - describe UnusedArgument do + subject = UnusedArgument.new + subject.ignore_defs = false + it "doesn't report if arguments are used" do expect_no_issues subject, <<-CRYSTAL def method(a, b, c) diff --git a/spec/ameba/rule/lint/unused_block_argument_spec.cr b/spec/ameba/rule/lint/unused_block_argument_spec.cr index 2a577dab5..3fb820474 100644 --- a/spec/ameba/rule/lint/unused_block_argument_spec.cr +++ b/spec/ameba/rule/lint/unused_block_argument_spec.cr @@ -1,9 +1,9 @@ require "../../../spec_helper" module Ameba::Rule::Lint - subject = UnusedBlockArgument.new - describe UnusedBlockArgument do + subject = UnusedBlockArgument.new + it "doesn't report if it is an instance var argument" do expect_no_issues subject, <<-CRYSTAL class A diff --git a/spec/ameba/rule/lint/unused_comparison_spec.cr b/spec/ameba/rule/lint/unused_comparison_spec.cr index 620cb9ecd..341681f3f 100644 --- a/spec/ameba/rule/lint/unused_comparison_spec.cr +++ b/spec/ameba/rule/lint/unused_comparison_spec.cr @@ -1,9 +1,9 @@ require "../../../spec_helper" module Ameba::Rule::Lint - subject = UnusedComparison.new - describe UnusedComparison do + subject = UnusedComparison.new + it "passes if comparisons are significant" do expect_no_issues subject, <<-CRYSTAL a = 1 == "1" diff --git a/spec/ameba/rule/lint/unused_literal_spec.cr b/spec/ameba/rule/lint/unused_literal_spec.cr index 8907f6537..5fc58aa39 100644 --- a/spec/ameba/rule/lint/unused_literal_spec.cr +++ b/spec/ameba/rule/lint/unused_literal_spec.cr @@ -1,14 +1,14 @@ require "../../../spec_helper" module Ameba::Rule::Lint - subject = UnusedLiteral.new - describe UnusedLiteral do + subject = UnusedLiteral.new + it "passes if literals are used to assign" do - expect_no_issues subject, <<-CRYSTAL + expect_no_issues subject, <<-'CRYSTAL' a = 1 b = "string" - g = "interp \#{string}" + g = "interp #{string}" h = <<-HEREDOC this is a heredoc HEREDOC @@ -74,125 +74,125 @@ module Ameba::Rule::Lint it "fails if literals are top-level" do expect_issue subject, <<-CRYSTAL - 1234 - # ^^^^ error: Literal value is not used - 1234_f32 - # ^^^^^^^^ error: Literal value is not used - "hello world" - # ^^^^^^^^^^^^^ error: Literal value is not used - "interp \#{string}" - # ^^^^^^^^^^^^^^^^^^ error: Literal value is not used - [1, 2, 3, 4, 5] - # ^^^^^^^^^^^^^^^ error: Literal value is not used - {"hello" => "world"} - # ^^^^^^^^^^^^^^^^^^^^ error: Literal value is not used - '\t' - # ^^^ error: Literal value is not used - 1..2 - # ^^^^ error: Literal value is not used - {goodnight: moon} - # ^^^^^^^^^^^^^^^^^ error: Literal value is not used - {1, 2, 3} - # ^^^^^^^^^ error: Literal value is not used - <<-HEREDOC - # ^^^^^^^^^^ error: Literal value is not used - this is a heredoc - HEREDOC - CRYSTAL + 1234 + # ^^^^ error: Literal value is not used + 1234_f32 + # ^^^^^^^^ error: Literal value is not used + "hello world" + # ^^^^^^^^^^^^^ error: Literal value is not used + "interp \#{string}" + # ^^^^^^^^^^^^^^^^^^ error: Literal value is not used + [1, 2, 3, 4, 5] + # ^^^^^^^^^^^^^^^ error: Literal value is not used + {"hello" => "world"} + # ^^^^^^^^^^^^^^^^^^^^ error: Literal value is not used + '\t' + # ^^^ error: Literal value is not used + 1..2 + # ^^^^ error: Literal value is not used + {goodnight: moon} + # ^^^^^^^^^^^^^^^^^ error: Literal value is not used + {1, 2, 3} + # ^^^^^^^^^ error: Literal value is not used + <<-HEREDOC + # ^^^^^^^^^^ error: Literal value is not used + this is a heredoc + HEREDOC + CRYSTAL end it "fails if literals are in def body with Nil return" do expect_issue subject, <<-CRYSTAL - def hello : Nil - 1234 - # ^^^^ error: Literal value is not used - 1234_f32 - # ^^^^^^^^ error: Literal value is not used - "hello world" - # ^^^^^^^^^^^^^ error: Literal value is not used - "interp \#{string}" - # ^^^^^^^^^^^^^^^^^^ error: Literal value is not used - [1, 2, 3, 4, 5] - # ^^^^^^^^^^^^^^^ error: Literal value is not used - {"hello" => "world"} - # ^^^^^^^^^^^^^^^^^^^^ error: Literal value is not used - '\t' - # ^^^ error: Literal value is not used - 1..2 - # ^^^^ error: Literal value is not used - {goodnight: moon} - # ^^^^^^^^^^^^^^^^^ error: Literal value is not used - {1, 2, 3} - # ^^^^^^^^^ error: Literal value is not used - <<-HEREDOC - # ^^^^^^^^^^ error: Literal value is not used - this is a heredoc - HEREDOC - end - CRYSTAL + def hello : Nil + 1234 + # ^^^^ error: Literal value is not used + 1234_f32 + # ^^^^^^^^ error: Literal value is not used + "hello world" + # ^^^^^^^^^^^^^ error: Literal value is not used + "interp \#{string}" + # ^^^^^^^^^^^^^^^^^^ error: Literal value is not used + [1, 2, 3, 4, 5] + # ^^^^^^^^^^^^^^^ error: Literal value is not used + {"hello" => "world"} + # ^^^^^^^^^^^^^^^^^^^^ error: Literal value is not used + '\t' + # ^^^ error: Literal value is not used + 1..2 + # ^^^^ error: Literal value is not used + {goodnight: moon} + # ^^^^^^^^^^^^^^^^^ error: Literal value is not used + {1, 2, 3} + # ^^^^^^^^^ error: Literal value is not used + <<-HEREDOC + # ^^^^^^^^^^ error: Literal value is not used + this is a heredoc + HEREDOC + end + CRYSTAL end it "fails if literals are in proc body with Nil return, alongside the proc itself" do expect_issue subject, <<-CRYSTAL - -> : Nil do - # ^^^^^^^^^ error: Literal value is not used - 1234 - # ^^^^ error: Literal value is not used - 1234_f32 - # ^^^^^^^^ error: Literal value is not used - "hello world" - # ^^^^^^^^^^^^^ error: Literal value is not used - "interp \#{string}" - # ^^^^^^^^^^^^^^^^^^ error: Literal value is not used - [1, 2, 3, 4, 5] - # ^^^^^^^^^^^^^^^ error: Literal value is not used - {"hello" => "world"} - # ^^^^^^^^^^^^^^^^^^^^ error: Literal value is not used - '\t' - # ^^^ error: Literal value is not used - 1..2 - # ^^^^ error: Literal value is not used - {goodnight: moon} - # ^^^^^^^^^^^^^^^^^ error: Literal value is not used - {1, 2, 3} - # ^^^^^^^^^ error: Literal value is not used - <<-HEREDOC - # ^^^^^^^^^^ error: Literal value is not used - this is a heredoc - HEREDOC - end - CRYSTAL + -> : Nil do + # ^^^^^^^^^ error: Literal value is not used + 1234 + # ^^^^ error: Literal value is not used + 1234_f32 + # ^^^^^^^^ error: Literal value is not used + "hello world" + # ^^^^^^^^^^^^^ error: Literal value is not used + "interp \#{string}" + # ^^^^^^^^^^^^^^^^^^ error: Literal value is not used + [1, 2, 3, 4, 5] + # ^^^^^^^^^^^^^^^ error: Literal value is not used + {"hello" => "world"} + # ^^^^^^^^^^^^^^^^^^^^ error: Literal value is not used + '\t' + # ^^^ error: Literal value is not used + 1..2 + # ^^^^ error: Literal value is not used + {goodnight: moon} + # ^^^^^^^^^^^^^^^^^ error: Literal value is not used + {1, 2, 3} + # ^^^^^^^^^ error: Literal value is not used + <<-HEREDOC + # ^^^^^^^^^^ error: Literal value is not used + this is a heredoc + HEREDOC + end + CRYSTAL end it "fails if literals in unused if" do expect_issue subject, <<-CRYSTAL - if true - 1234 - # ^^^^ error: Literal value is not used - 1234_f32 - # ^^^^^^^^ error: Literal value is not used - "hello world" - # ^^^^^^^^^^^^^ error: Literal value is not used - "interp \#{string}" - # ^^^^^^^^^^^^^^^^^^ error: Literal value is not used - [1, 2, 3, 4, 5] - # ^^^^^^^^^^^^^^^ error: Literal value is not used - {"hello" => "world"} - # ^^^^^^^^^^^^^^^^^^^^ error: Literal value is not used - '\t' - # ^^^ error: Literal value is not used - 1..2 - # ^^^^ error: Literal value is not used - {goodnight: moon} - # ^^^^^^^^^^^^^^^^^ error: Literal value is not used - {1, 2, 3} - # ^^^^^^^^^ error: Literal value is not used - <<-HEREDOC - # ^^^^^^^^^^ error: Literal value is not used - this is a heredoc - HEREDOC - end - CRYSTAL + if true + 1234 + # ^^^^ error: Literal value is not used + 1234_f32 + # ^^^^^^^^ error: Literal value is not used + "hello world" + # ^^^^^^^^^^^^^ error: Literal value is not used + "interp \#{string}" + # ^^^^^^^^^^^^^^^^^^ error: Literal value is not used + [1, 2, 3, 4, 5] + # ^^^^^^^^^^^^^^^ error: Literal value is not used + {"hello" => "world"} + # ^^^^^^^^^^^^^^^^^^^^ error: Literal value is not used + '\t' + # ^^^ error: Literal value is not used + 1..2 + # ^^^^ error: Literal value is not used + {goodnight: moon} + # ^^^^^^^^^^^^^^^^^ error: Literal value is not used + {1, 2, 3} + # ^^^^^^^^^ error: Literal value is not used + <<-HEREDOC + # ^^^^^^^^^^ error: Literal value is not used + this is a heredoc + HEREDOC + end + CRYSTAL end it "fails if literals are unused in case" do @@ -293,23 +293,23 @@ module Ameba::Rule::Lint # Locations for Regex literals were added in Crystal v1.15.0 {% if compare_versions(Crystal::VERSION, "1.15.0") >= 0 %} it "fails if a regex literal is unused" do - expect_issue subject, <<-CRYSTAL - a = /hello world/ - /goodnight moon/ - # ^^^^^^^^^^^^^^^^ error: Literal value is not used - b = /goodnight moon, \#{a}/ - /goodnight moon, \#{a}/ - # ^^^^^^^^^^^^^^^^^^^^^^ error: Literal value is not used + expect_issue subject, <<-'CRYSTAL' + a = /hello world/ + /goodnight moon/ + # ^^^^^^^^^^^^^^ error: Literal value is not used + b = /goodnight moon, #{a}/ + /goodnight moon, #{a}/ + # ^^^^^^^^^^^^^^^^^^^^ error: Literal value is not used CRYSTAL end {% else %} it "passes if a regex literal is unused" do - expect_no_issues subject, <<-CRYSTAL - a = /hello world/ - /goodnight moon/ - b = /goodnight moon, \#{a}/ - /goodnight moon, \#{a}/ - CRYSTAL + expect_no_issues subject, <<-'CRYSTAL' + a = /hello world/ + /goodnight moon/ + b = /goodnight moon, #{a}/ + /goodnight moon, #{a}/ + CRYSTAL end {% end %} end diff --git a/spec/ameba/rule/lint/useless_assign_spec.cr b/spec/ameba/rule/lint/useless_assign_spec.cr index bdc587f92..0183c8056 100644 --- a/spec/ameba/rule/lint/useless_assign_spec.cr +++ b/spec/ameba/rule/lint/useless_assign_spec.cr @@ -3,7 +3,7 @@ require "../../../spec_helper" module Ameba::Rule::Lint describe UselessAssign do subject = UselessAssign.new - .tap(&.exclude_type_declarations = false) + subject.exclude_type_declarations = false it "does not report used assignments" do expect_no_issues subject, <<-CRYSTAL diff --git a/spec/ameba/rule/lint/useless_condition_in_when_spec.cr b/spec/ameba/rule/lint/useless_condition_in_when_spec.cr index c31e3e31b..0a1c3eef9 100644 --- a/spec/ameba/rule/lint/useless_condition_in_when_spec.cr +++ b/spec/ameba/rule/lint/useless_condition_in_when_spec.cr @@ -1,9 +1,9 @@ require "../../../spec_helper" module Ameba::Rule::Lint - subject = UselessConditionInWhen.new - describe UselessConditionInWhen do + subject = UselessConditionInWhen.new + it "passes if there is not useless condition" do expect_no_issues subject, <<-CRYSTAL case @@ -20,7 +20,7 @@ module Ameba::Rule::Lint case when utc? io << " UTC" if utc? - # ^^^^ error: Useless condition in when detected + # ^^^^ error: Useless condition in `when` detected end CRYSTAL end diff --git a/spec/ameba/rule/metrics/cyclomatic_complexity_spec.cr b/spec/ameba/rule/metrics/cyclomatic_complexity_spec.cr index dcb9555f2..51ce01d2b 100644 --- a/spec/ameba/rule/metrics/cyclomatic_complexity_spec.cr +++ b/spec/ameba/rule/metrics/cyclomatic_complexity_spec.cr @@ -1,23 +1,23 @@ require "../../../spec_helper" module Ameba::Rule::Metrics - subject = CyclomaticComplexity.new - complex_method = <<-CRYSTAL - def hello(a, b, c) - if a && b && c - begin - while true - return if false && b + describe CyclomaticComplexity do + subject = CyclomaticComplexity.new + complex_method = <<-CRYSTAL + def hello(a, b, c) + if a && b && c + begin + while true + return if false && b + end + "" + rescue + "" end - "" - rescue - "" end end - end - CRYSTAL + CRYSTAL - describe CyclomaticComplexity do it "passes for empty methods" do expect_no_issues subject, <<-CRYSTAL def hello diff --git a/spec/ameba/rule/naming/accessor_method_name_spec.cr b/spec/ameba/rule/naming/accessor_method_name_spec.cr index a1241d996..235418469 100644 --- a/spec/ameba/rule/naming/accessor_method_name_spec.cr +++ b/spec/ameba/rule/naming/accessor_method_name_spec.cr @@ -1,9 +1,9 @@ require "../../../spec_helper" module Ameba::Rule::Naming - subject = AccessorMethodName.new - describe AccessorMethodName do + subject = AccessorMethodName.new + it "passes if accessor method name is correct" do expect_no_issues subject, <<-CRYSTAL class Foo diff --git a/spec/ameba/rule/naming/ascii_identifiers_spec.cr b/spec/ameba/rule/naming/ascii_identifiers_spec.cr index 87bed3311..508b60f71 100644 --- a/spec/ameba/rule/naming/ascii_identifiers_spec.cr +++ b/spec/ameba/rule/naming/ascii_identifiers_spec.cr @@ -1,9 +1,9 @@ require "../../../spec_helper" module Ameba::Rule::Naming - subject = AsciiIdentifiers.new - describe AsciiIdentifiers do + subject = AsciiIdentifiers.new + it "reports classes with names containing non-ascii characters" do expect_issue subject, <<-CRYSTAL class BigAwesome🐺 diff --git a/spec/ameba/rule/naming/binary_operator_parameter_name_spec.cr b/spec/ameba/rule/naming/binary_operator_parameter_name_spec.cr index bd27a96cb..c6cfee479 100644 --- a/spec/ameba/rule/naming/binary_operator_parameter_name_spec.cr +++ b/spec/ameba/rule/naming/binary_operator_parameter_name_spec.cr @@ -1,9 +1,9 @@ require "../../../spec_helper" module Ameba::Rule::Naming - subject = BinaryOperatorParameterName.new - describe BinaryOperatorParameterName do + subject = BinaryOperatorParameterName.new + it "ignores `other` parameter name in binary method definitions" do expect_no_issues subject, <<-CRYSTAL def +(other); end diff --git a/spec/ameba/rule/naming/block_parameter_name_spec.cr b/spec/ameba/rule/naming/block_parameter_name_spec.cr index ac8fdedc2..4afdda8b4 100644 --- a/spec/ameba/rule/naming/block_parameter_name_spec.cr +++ b/spec/ameba/rule/naming/block_parameter_name_spec.cr @@ -1,11 +1,11 @@ require "../../../spec_helper" module Ameba::Rule::Naming - subject = BlockParameterName.new - .tap(&.min_name_length = 3) - .tap(&.allowed_names = %w[e i j k v]) - describe BlockParameterName do + subject = BlockParameterName.new + subject.min_name_length = 3 + subject.allowed_names = %w[e i j k v] + it "passes if block parameter name matches #allowed_names" do subject.allowed_names.each do |name| expect_no_issues subject, <<-CRYSTAL diff --git a/spec/ameba/rule/naming/constant_names_spec.cr b/spec/ameba/rule/naming/constant_names_spec.cr index c57027cc6..0a2378e3e 100644 --- a/spec/ameba/rule/naming/constant_names_spec.cr +++ b/spec/ameba/rule/naming/constant_names_spec.cr @@ -1,19 +1,19 @@ require "../../../spec_helper" -module Ameba - subject = Rule::Naming::ConstantNames.new - - private def it_reports_constant(name, value, expected, *, file = __FILE__, line = __LINE__) - it "reports constant name #{expected}", file, line do - rule = Rule::Naming::ConstantNames.new - expect_issue rule, <<-CRYSTAL, name: name, file: file, line: line - %{name} = #{value} - # ^{name} error: Constant name should be screaming-cased: `#{expected}`, not `#{name}` - CRYSTAL - end +private def it_reports_constant(name, value, expected, *, file = __FILE__, line = __LINE__) + it "reports constant name #{expected}", file, line do + rule = Ameba::Rule::Naming::ConstantNames.new + expect_issue rule, <<-CRYSTAL, name: name, file: file, line: line + %{name} = #{value} + # ^{name} error: Constant name should be screaming-cased: `#{expected}`, not `#{name}` + CRYSTAL end +end + +module Ameba::Rule::Naming + describe ConstantNames do + subject = ConstantNames.new - describe Rule::Naming::ConstantNames do it "passes if type names are screaming-cased" do expect_no_issues subject, <<-CRYSTAL LUCKY_NUMBERS = [3, 7, 11] diff --git a/spec/ameba/rule/naming/filename_spec.cr b/spec/ameba/rule/naming/filename_spec.cr index e12c32fc5..b6dd10fbb 100644 --- a/spec/ameba/rule/naming/filename_spec.cr +++ b/spec/ameba/rule/naming/filename_spec.cr @@ -1,9 +1,9 @@ require "../../../spec_helper" module Ameba::Rule::Naming - subject = Filename.new - describe Filename do + subject = Filename.new + it "passes if filename is correct" do expect_no_issues subject, code: "", path: "src/foo.cr" expect_no_issues subject, code: "", path: "src/foo_bar.cr" diff --git a/spec/ameba/rule/naming/method_names_spec.cr b/spec/ameba/rule/naming/method_names_spec.cr index a6bb82d8d..864118b00 100644 --- a/spec/ameba/rule/naming/method_names_spec.cr +++ b/spec/ameba/rule/naming/method_names_spec.cr @@ -1,19 +1,19 @@ require "../../../spec_helper" -module Ameba - subject = Rule::Naming::MethodNames.new - - private def it_reports_method_name(name, expected, *, file = __FILE__, line = __LINE__) - it "reports method name #{expected}", file, line do - rule = Rule::Naming::MethodNames.new - expect_issue rule, <<-CRYSTAL, name: name, file: file, line: line - def %{name}; end - # ^{name} error: Method name should be underscore-cased: `#{expected}`, not `%{name}` - CRYSTAL - end +private def it_reports_method_name(name, expected, *, file = __FILE__, line = __LINE__) + it "reports method name #{expected}", file, line do + rule = Ameba::Rule::Naming::MethodNames.new + expect_issue rule, <<-CRYSTAL, name: name, file: file, line: line + def %{name}; end + # ^{name} error: Method name should be underscore-cased: `#{expected}`, not `%{name}` + CRYSTAL end +end + +module Ameba::Rule::Naming + describe MethodNames do + subject = MethodNames.new - describe Rule::Naming::MethodNames do it "passes if method names are underscore-cased" do expect_no_issues subject, <<-CRYSTAL class Person diff --git a/spec/ameba/rule/naming/predicate_name_spec.cr b/spec/ameba/rule/naming/predicate_name_spec.cr index acf9adcae..1b389740a 100644 --- a/spec/ameba/rule/naming/predicate_name_spec.cr +++ b/spec/ameba/rule/naming/predicate_name_spec.cr @@ -1,9 +1,9 @@ require "../../../spec_helper" module Ameba::Rule::Naming - subject = PredicateName.new - describe PredicateName do + subject = PredicateName.new + it "passes if predicate name is correct" do expect_no_issues subject, <<-CRYSTAL def valid?(x) diff --git a/spec/ameba/rule/naming/query_bool_methods_spec.cr b/spec/ameba/rule/naming/query_bool_methods_spec.cr index ee731efd3..69a9e8538 100644 --- a/spec/ameba/rule/naming/query_bool_methods_spec.cr +++ b/spec/ameba/rule/naming/query_bool_methods_spec.cr @@ -1,9 +1,9 @@ require "../../../spec_helper" module Ameba::Rule::Naming - subject = QueryBoolMethods.new - describe QueryBoolMethods do + subject = QueryBoolMethods.new + it "passes for valid cases" do expect_no_issues subject, <<-CRYSTAL class Foo diff --git a/spec/ameba/rule/naming/rescued_exceptions_variable_name_spec.cr b/spec/ameba/rule/naming/rescued_exceptions_variable_name_spec.cr index 53a58e344..d1424a4b6 100644 --- a/spec/ameba/rule/naming/rescued_exceptions_variable_name_spec.cr +++ b/spec/ameba/rule/naming/rescued_exceptions_variable_name_spec.cr @@ -1,9 +1,9 @@ require "../../../spec_helper" module Ameba::Rule::Naming - subject = RescuedExceptionsVariableName.new - describe RescuedExceptionsVariableName do + subject = RescuedExceptionsVariableName.new + it "passes if exception handler variable name matches #allowed_names" do subject.allowed_names.each do |name| expect_no_issues subject, <<-CRYSTAL diff --git a/spec/ameba/rule/naming/type_names_spec.cr b/spec/ameba/rule/naming/type_names_spec.cr index 9dc94f846..a05bdeb4f 100644 --- a/spec/ameba/rule/naming/type_names_spec.cr +++ b/spec/ameba/rule/naming/type_names_spec.cr @@ -1,19 +1,19 @@ require "../../../spec_helper" -module Ameba - subject = Rule::Naming::TypeNames.new - - private def it_reports_name(type, name, expected, *, file = __FILE__, line = __LINE__) - it "reports type name #{expected}", file, line do - rule = Rule::Naming::TypeNames.new - expect_issue rule, <<-CRYSTAL, type: type, name: name, file: file, line: line - %{type} %{name}; end - _{type} # ^{name} error: Type name should be camelcased: `#{expected}`, not `%{name}` - CRYSTAL - end +private def it_reports_name(type, name, expected, *, file = __FILE__, line = __LINE__) + it "reports type name #{expected}", file, line do + rule = Ameba::Rule::Naming::TypeNames.new + expect_issue rule, <<-CRYSTAL, type: type, name: name, file: file, line: line + %{type} %{name}; end + _{type} # ^{name} error: Type name should be camelcased: `#{expected}`, not `%{name}` + CRYSTAL end +end + +module Ameba::Rule::Naming + describe TypeNames do + subject = TypeNames.new - describe Rule::Naming::TypeNames do it "passes if type names are camelcased" do expect_no_issues subject, <<-CRYSTAL class ParseError < Exception diff --git a/spec/ameba/rule/naming/variable_names_spec.cr b/spec/ameba/rule/naming/variable_names_spec.cr index b2c5cb0b4..5e18e8d82 100644 --- a/spec/ameba/rule/naming/variable_names_spec.cr +++ b/spec/ameba/rule/naming/variable_names_spec.cr @@ -1,19 +1,19 @@ require "../../../spec_helper" -module Ameba - subject = Rule::Naming::VariableNames.new - - private def it_reports_var_name(name, value, expected, *, file = __FILE__, line = __LINE__) - it "reports variable name #{expected}", file, line do - rule = Rule::Naming::VariableNames.new - expect_issue rule, <<-CRYSTAL, name: name, file: file, line: line - %{name} = #{value} - # ^{name} error: Variable name should be underscore-cased: `#{expected}`, not `%{name}` - CRYSTAL - end +private def it_reports_var_name(name, value, expected, *, file = __FILE__, line = __LINE__) + it "reports variable name #{expected}", file, line do + rule = Ameba::Rule::Naming::VariableNames.new + expect_issue rule, <<-CRYSTAL, name: name, file: file, line: line + %{name} = #{value} + # ^{name} error: Variable name should be underscore-cased: `#{expected}`, not `%{name}` + CRYSTAL end +end + +module Ameba::Rule::Naming + describe VariableNames do + subject = VariableNames.new - describe Rule::Naming::VariableNames do it "passes if var names are underscore-cased" do expect_no_issues subject, <<-CRYSTAL class Greeting diff --git a/spec/ameba/rule/performance/any_after_filter_spec.cr b/spec/ameba/rule/performance/any_after_filter_spec.cr index e7c122eaf..a54483c5b 100644 --- a/spec/ameba/rule/performance/any_after_filter_spec.cr +++ b/spec/ameba/rule/performance/any_after_filter_spec.cr @@ -1,9 +1,9 @@ require "../../../spec_helper" module Ameba::Rule::Performance - subject = AnyAfterFilter.new - describe AnyAfterFilter do + subject = AnyAfterFilter.new + it "passes if there is no potential performance improvements" do expect_no_issues subject, <<-CRYSTAL [1, 2, 3].select { |e| e > 1 }.any?(&.zero?) diff --git a/spec/ameba/rule/performance/any_instead_of_empty_spec.cr b/spec/ameba/rule/performance/any_instead_of_empty_spec.cr index 7d4827b94..b2fc32fa4 100644 --- a/spec/ameba/rule/performance/any_instead_of_empty_spec.cr +++ b/spec/ameba/rule/performance/any_instead_of_empty_spec.cr @@ -1,9 +1,9 @@ require "../../../spec_helper" module Ameba::Rule::Performance - subject = AnyInsteadOfEmpty.new - describe AnyInsteadOfEmpty do + subject = AnyInsteadOfEmpty.new + it "passes if there is no potential performance improvements" do expect_no_issues subject, <<-CRYSTAL [1, 2, 3].any?(&.zero?) diff --git a/spec/ameba/rule/performance/chained_call_with_no_bang_spec.cr b/spec/ameba/rule/performance/chained_call_with_no_bang_spec.cr index a72590ad4..b4c2bde98 100644 --- a/spec/ameba/rule/performance/chained_call_with_no_bang_spec.cr +++ b/spec/ameba/rule/performance/chained_call_with_no_bang_spec.cr @@ -1,9 +1,9 @@ require "../../../spec_helper" module Ameba::Rule::Performance - subject = ChainedCallWithNoBang.new - describe ChainedCallWithNoBang do + subject = ChainedCallWithNoBang.new + it "passes if there is no potential performance improvements" do expect_no_issues subject, <<-CRYSTAL (1..3).select { |e| e > 1 }.sort! diff --git a/spec/ameba/rule/performance/compact_after_map_spec.cr b/spec/ameba/rule/performance/compact_after_map_spec.cr index b09e4d97f..6665a0213 100644 --- a/spec/ameba/rule/performance/compact_after_map_spec.cr +++ b/spec/ameba/rule/performance/compact_after_map_spec.cr @@ -1,9 +1,9 @@ require "../../../spec_helper" module Ameba::Rule::Performance - subject = CompactAfterMap.new - describe CompactAfterMap do + subject = CompactAfterMap.new + it "passes if there is no potential performance improvements" do expect_no_issues subject, <<-CRYSTAL (1..3).compact_map(&.itself) diff --git a/spec/ameba/rule/performance/excessive_allocations_spec.cr b/spec/ameba/rule/performance/excessive_allocations_spec.cr index 010c50641..81d138ff7 100644 --- a/spec/ameba/rule/performance/excessive_allocations_spec.cr +++ b/spec/ameba/rule/performance/excessive_allocations_spec.cr @@ -1,9 +1,9 @@ require "../../../spec_helper" module Ameba::Rule::Performance - subject = ExcessiveAllocations.new - describe ExcessiveAllocations do + subject = ExcessiveAllocations.new + it "passes if there is no potential performance improvements" do expect_no_issues subject, <<-CRYSTAL "Alice".chars.each(arg) { |c| puts c } diff --git a/spec/ameba/rule/performance/first_last_after_filter_spec.cr b/spec/ameba/rule/performance/first_last_after_filter_spec.cr index 49aa46e78..a7f40cc5f 100644 --- a/spec/ameba/rule/performance/first_last_after_filter_spec.cr +++ b/spec/ameba/rule/performance/first_last_after_filter_spec.cr @@ -1,9 +1,9 @@ require "../../../spec_helper" module Ameba::Rule::Performance - subject = FirstLastAfterFilter.new - describe FirstLastAfterFilter do + subject = FirstLastAfterFilter.new + it "passes if there is no potential performance improvements" do expect_no_issues subject, <<-CRYSTAL [1, 2, 3].select { |e| e > 1 } diff --git a/spec/ameba/rule/performance/flatten_after_map_spec.cr b/spec/ameba/rule/performance/flatten_after_map_spec.cr index 3d498fdd3..e51624553 100644 --- a/spec/ameba/rule/performance/flatten_after_map_spec.cr +++ b/spec/ameba/rule/performance/flatten_after_map_spec.cr @@ -1,9 +1,9 @@ require "../../../spec_helper" module Ameba::Rule::Performance - subject = FlattenAfterMap.new - describe FlattenAfterMap do + subject = FlattenAfterMap.new + it "passes if there is no potential performance improvements" do expect_no_issues subject, <<-CRYSTAL %w[Alice Bob].flat_map(&.chars) diff --git a/spec/ameba/rule/performance/map_instead_of_block_spec.cr b/spec/ameba/rule/performance/map_instead_of_block_spec.cr index 878e22bcf..b024161e5 100644 --- a/spec/ameba/rule/performance/map_instead_of_block_spec.cr +++ b/spec/ameba/rule/performance/map_instead_of_block_spec.cr @@ -1,9 +1,9 @@ require "../../../spec_helper" module Ameba::Rule::Performance - subject = MapInsteadOfBlock.new - describe MapInsteadOfBlock do + subject = MapInsteadOfBlock.new + it "passes if there is no potential performance improvements" do expect_no_issues subject, <<-CRYSTAL (1..3).sum(&.*(2)) diff --git a/spec/ameba/rule/performance/minmax_after_map_spec.cr b/spec/ameba/rule/performance/minmax_after_map_spec.cr index e44629920..183753402 100644 --- a/spec/ameba/rule/performance/minmax_after_map_spec.cr +++ b/spec/ameba/rule/performance/minmax_after_map_spec.cr @@ -1,9 +1,9 @@ require "../../../spec_helper" module Ameba::Rule::Performance - subject = MinMaxAfterMap.new - describe MinMaxAfterMap do + subject = MinMaxAfterMap.new + it "passes if there are no potential performance improvements" do expect_no_issues subject, <<-CRYSTAL %w[Alice Bob].map { |name| name.size }.min(2) diff --git a/spec/ameba/rule/performance/size_after_filter_spec.cr b/spec/ameba/rule/performance/size_after_filter_spec.cr index 62d8d1ee5..e5632800b 100644 --- a/spec/ameba/rule/performance/size_after_filter_spec.cr +++ b/spec/ameba/rule/performance/size_after_filter_spec.cr @@ -1,9 +1,9 @@ require "../../../spec_helper" module Ameba::Rule::Performance - subject = SizeAfterFilter.new - describe SizeAfterFilter do + subject = SizeAfterFilter.new + it "passes if there is no potential performance improvements" do expect_no_issues subject, <<-CRYSTAL [1, 2, 3].select { |e| e > 2 } diff --git a/spec/ameba/rule/style/guard_clause_spec.cr b/spec/ameba/rule/style/guard_clause_spec.cr index fc09fdef5..d0bbb3ce4 100644 --- a/spec/ameba/rule/style/guard_clause_spec.cr +++ b/spec/ameba/rule/style/guard_clause_spec.cr @@ -1,184 +1,184 @@ require "../../../spec_helper" -module Ameba - subject = Rule::Style::GuardClause.new - - private def it_reports_body(body, *, file = __FILE__, line = __LINE__) - rule = Rule::Style::GuardClause.new - - it "reports an issue if method body is if / unless without else", file, line do - source = expect_issue rule, <<-CRYSTAL, file: file, line: line - def func - if something - # ^^ error: Use a guard clause (`return unless something`) instead of wrapping the code inside a conditional expression. - #{body} - end +private def it_reports_body(body, *, file = __FILE__, line = __LINE__) + rule = Ameba::Rule::Style::GuardClause.new + + it "reports an issue if method body is if / unless without else", file, line do + source = expect_issue rule, <<-CRYSTAL, file: file, line: line + def func + if something + # ^^ error: Use a guard clause (`return unless something`) instead of wrapping the code inside a conditional expression. + #{body} end + end - def func - unless something - # ^^^^^^ error: Use a guard clause (`return if something`) instead of wrapping the code inside a conditional expression. - #{body} - end + def func + unless something + # ^^^^^^ error: Use a guard clause (`return if something`) instead of wrapping the code inside a conditional expression. + #{body} end - CRYSTAL + end + CRYSTAL - expect_correction source, <<-CRYSTAL, file: file, line: line - def func - return unless something - #{body} - #{trailing_whitespace} - end + expect_correction source, <<-CRYSTAL, file: file, line: line + def func + return unless something + #{body} + #{trailing_whitespace} + end - def func - return if something - #{body} - #{trailing_whitespace} - end - CRYSTAL - end + def func + return if something + #{body} + #{trailing_whitespace} + end + CRYSTAL + end - it "reports an issue if method body ends with if / unless without else", file, line do - source = expect_issue rule, <<-CRYSTAL, file: file, line: line - def func - test - if something - # ^^ error: Use a guard clause (`return unless something`) instead of wrapping the code inside a conditional expression. - #{body} - end + it "reports an issue if method body ends with if / unless without else", file, line do + source = expect_issue rule, <<-CRYSTAL, file: file, line: line + def func + test + if something + # ^^ error: Use a guard clause (`return unless something`) instead of wrapping the code inside a conditional expression. + #{body} end + end - def func - test - unless something - # ^^^^^^ error: Use a guard clause (`return if something`) instead of wrapping the code inside a conditional expression. - #{body} - end - end - CRYSTAL - - expect_correction source, <<-CRYSTAL, file: file, line: line - def func - test - return unless something - #{body} - #{trailing_whitespace} + def func + test + unless something + # ^^^^^^ error: Use a guard clause (`return if something`) instead of wrapping the code inside a conditional expression. + #{body} end + end + CRYSTAL + + expect_correction source, <<-CRYSTAL, file: file, line: line + def func + test + return unless something + #{body} + #{trailing_whitespace} + end - def func - test - return if something - #{body} - #{trailing_whitespace} - end - CRYSTAL - end + def func + test + return if something + #{body} + #{trailing_whitespace} + end + CRYSTAL end +end - private def it_reports_control_expression(kw, *, file = __FILE__, line = __LINE__) - rule = Rule::Style::GuardClause.new +private def it_reports_control_expression(kw, *, file = __FILE__, line = __LINE__) + rule = Ameba::Rule::Style::GuardClause.new - it "reports an issue with #{kw} in the if branch", file, line do - source = expect_issue rule, <<-CRYSTAL, file: file, line: line - def func - if something - # ^^ error: Use a guard clause (`#{kw} if something`) instead of wrapping the code inside a conditional expression. - #{kw} - else - puts "hello" - end + it "reports an issue with #{kw} in the if branch", file, line do + source = expect_issue rule, <<-CRYSTAL, file: file, line: line + def func + if something + # ^^ error: Use a guard clause (`#{kw} if something`) instead of wrapping the code inside a conditional expression. + #{kw} + else + puts "hello" end - CRYSTAL + end + CRYSTAL - expect_no_corrections source, file: file, line: line - end + expect_no_corrections source, file: file, line: line + end - it "reports an issue with #{kw} in the else branch", file, line do - source = expect_issue rule, <<-CRYSTAL, file: file, line: line - def func - if something - # ^^ error: Use a guard clause (`#{kw} unless something`) instead of wrapping the code inside a conditional expression. - puts "hello" - else - #{kw} - end + it "reports an issue with #{kw} in the else branch", file, line do + source = expect_issue rule, <<-CRYSTAL, file: file, line: line + def func + if something + # ^^ error: Use a guard clause (`#{kw} unless something`) instead of wrapping the code inside a conditional expression. + puts "hello" + else + #{kw} end - CRYSTAL + end + CRYSTAL - expect_no_corrections source, file: file, line: line - end + expect_no_corrections source, file: file, line: line + end - it "doesn't report an issue if condition has multiple lines", file, line do - expect_no_issues rule, <<-CRYSTAL, file: file, line: line - def func - if something && - something_else - #{kw} - else - puts "hello" - end + it "doesn't report an issue if condition has multiple lines", file, line do + expect_no_issues rule, <<-CRYSTAL, file: file, line: line + def func + if something && + something_else + #{kw} + else + puts "hello" end - CRYSTAL - end + end + CRYSTAL + end - it "does not report an issue if #{kw} is inside elsif", file, line do - expect_no_issues rule, <<-CRYSTAL, file: file, line: line - def func - if something - a - elsif something_else - #{kw} - end + it "does not report an issue if #{kw} is inside elsif", file, line do + expect_no_issues rule, <<-CRYSTAL, file: file, line: line + def func + if something + a + elsif something_else + #{kw} end - CRYSTAL - end + end + CRYSTAL + end - it "does not report an issue if #{kw} is inside if..elsif..else..end", file, line do - expect_no_issues rule, <<-CRYSTAL, file: file, line: line - def func - if something - a - elsif something_else - b - else - #{kw} - end + it "does not report an issue if #{kw} is inside if..elsif..else..end", file, line do + expect_no_issues rule, <<-CRYSTAL, file: file, line: line + def func + if something + a + elsif something_else + b + else + #{kw} end - CRYSTAL - end + end + CRYSTAL + end - it "doesn't report an issue if control flow expr has multiple lines", file, line do - expect_no_issues rule, <<-CRYSTAL, file: file, line: line - def func - if something - #{kw} \\ - "blah blah blah" \\ - "blah blah blah" - else - puts "hello" - end + it "doesn't report an issue if control flow expr has multiple lines", file, line do + expect_no_issues rule, <<-CRYSTAL, file: file, line: line + def func + if something + #{kw} \\ + "blah blah blah" \\ + "blah blah blah" + else + puts "hello" end - CRYSTAL - end + end + CRYSTAL + end - it "reports an issue if non-control-flow branch has multiple lines", file, line do - source = expect_issue rule, <<-CRYSTAL, file: file, line: line - def func - if something - # ^^ error: Use a guard clause (`#{kw} if something`) instead of wrapping the code inside a conditional expression. - #{kw} - else - puts "hello" \\ - "blah blah blah" - end + it "reports an issue if non-control-flow branch has multiple lines", file, line do + source = expect_issue rule, <<-CRYSTAL, file: file, line: line + def func + if something + # ^^ error: Use a guard clause (`#{kw} if something`) instead of wrapping the code inside a conditional expression. + #{kw} + else + puts "hello" \\ + "blah blah blah" end - CRYSTAL + end + CRYSTAL - expect_no_corrections source, file: file, line: line - end + expect_no_corrections source, file: file, line: line end +end + +module Ameba::Rule::Style + describe GuardClause do + subject = GuardClause.new - describe Rule::Style::GuardClause do it_reports_body "work" it_reports_body "# TODO" diff --git a/spec/ameba/rule/style/is_a_filter_spec.cr b/spec/ameba/rule/style/is_a_filter_spec.cr index a1b34da4c..7edf51f39 100644 --- a/spec/ameba/rule/style/is_a_filter_spec.cr +++ b/spec/ameba/rule/style/is_a_filter_spec.cr @@ -1,9 +1,9 @@ require "../../../spec_helper" module Ameba::Rule::Style - subject = IsAFilter.new - describe IsAFilter do + subject = IsAFilter.new + it "passes if there is no potential performance improvements" do expect_no_issues subject, <<-CRYSTAL [1, 2, nil].select(Int32) diff --git a/spec/ameba/rule/style/large_numbers_spec.cr b/spec/ameba/rule/style/large_numbers_spec.cr index cca9fcf96..53e780640 100644 --- a/spec/ameba/rule/style/large_numbers_spec.cr +++ b/spec/ameba/rule/style/large_numbers_spec.cr @@ -1,25 +1,25 @@ require "../../../spec_helper" -module Ameba - subject = Rule::Style::LargeNumbers.new - - private def it_transforms(number, expected, *, file = __FILE__, line = __LINE__) - it "transforms large number #{number}", file, line do - rule = Rule::Style::LargeNumbers.new - rule.int_min_digits = 5 - - source = expect_issue rule, <<-CRYSTAL, number: number, file: file, line: line - number = %{number} - # ^{number} error: Large numbers should be written with underscores: `#{expected}` - CRYSTAL - - expect_correction source, <<-CRYSTAL - number = #{expected} - CRYSTAL - end +private def it_transforms(number, expected, *, file = __FILE__, line = __LINE__) + it "transforms large number #{number}", file, line do + rule = Ameba::Rule::Style::LargeNumbers.new + rule.int_min_digits = 5 + + source = expect_issue rule, <<-CRYSTAL, number: number, file: file, line: line + number = %{number} + # ^{number} error: Large numbers should be written with underscores: `#{expected}` + CRYSTAL + + expect_correction source, <<-CRYSTAL + number = #{expected} + CRYSTAL end +end + +module Ameba::Rule::Style + describe LargeNumbers do + subject = LargeNumbers.new - describe Rule::Style::LargeNumbers do it "passes if large number does not require underscore" do expect_no_issues subject, <<-CRYSTAL 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 diff --git a/spec/ameba/rule/style/negated_conditions_in_unless_spec.cr b/spec/ameba/rule/style/negated_conditions_in_unless_spec.cr index 60edb7cfe..47468e630 100644 --- a/spec/ameba/rule/style/negated_conditions_in_unless_spec.cr +++ b/spec/ameba/rule/style/negated_conditions_in_unless_spec.cr @@ -1,9 +1,9 @@ require "../../../spec_helper" module Ameba::Rule::Style - subject = NegatedConditionsInUnless.new - describe NegatedConditionsInUnless do + subject = NegatedConditionsInUnless.new + it "passes with a unless without negated condition" do expect_no_issues subject, <<-CRYSTAL unless a diff --git a/spec/ameba/rule/style/parentheses_around_condition_spec.cr b/spec/ameba/rule/style/parentheses_around_condition_spec.cr index d4adb811f..9ea8b2304 100644 --- a/spec/ameba/rule/style/parentheses_around_condition_spec.cr +++ b/spec/ameba/rule/style/parentheses_around_condition_spec.cr @@ -1,9 +1,9 @@ require "../../../spec_helper" module Ameba::Rule::Style - subject = ParenthesesAroundCondition.new - describe ParenthesesAroundCondition do + subject = ParenthesesAroundCondition.new + {% for keyword in %w[if unless while until] %} context "{{ keyword.id }}" do it "reports if redundant parentheses are found" do @@ -101,13 +101,19 @@ module Ameba::Rule::Style rule = ParenthesesAroundCondition.new rule.allow_safe_assignment = true - expect_issue rule, <<-CRYSTAL + source = expect_issue rule, <<-CRYSTAL if foo = @foo # ^^^^^^^^^^ error: Missing parentheses foo end CRYSTAL + expect_correction source, <<-CRYSTAL + if (foo = @foo) + foo + end + CRYSTAL + expect_no_issues rule, <<-CRYSTAL if (foo = @foo) foo diff --git a/spec/ameba/rule/style/redundant_next_spec.cr b/spec/ameba/rule/style/redundant_next_spec.cr index ed1e4123c..05cd6e093 100644 --- a/spec/ameba/rule/style/redundant_next_spec.cr +++ b/spec/ameba/rule/style/redundant_next_spec.cr @@ -1,9 +1,9 @@ require "../../../spec_helper" module Ameba::Rule::Style - subject = RedundantNext.new - describe RedundantNext do + subject = RedundantNext.new + it "does not report if there is no redundant next" do expect_no_issues subject, <<-CRYSTAL array.map { |x| x + 1 } diff --git a/spec/ameba/rule/style/redundant_return_spec.cr b/spec/ameba/rule/style/redundant_return_spec.cr index 634717d20..c9447fb3f 100644 --- a/spec/ameba/rule/style/redundant_return_spec.cr +++ b/spec/ameba/rule/style/redundant_return_spec.cr @@ -1,9 +1,9 @@ require "../../../spec_helper" module Ameba::Rule::Style - subject = RedundantReturn.new - describe RedundantReturn do + subject = RedundantReturn.new + it "does not report if there is no return" do expect_no_issues subject, <<-CRYSTAL def inc(a) diff --git a/spec/ameba/rule/style/unless_else_spec.cr b/spec/ameba/rule/style/unless_else_spec.cr index 262214ee5..a1c548317 100644 --- a/spec/ameba/rule/style/unless_else_spec.cr +++ b/spec/ameba/rule/style/unless_else_spec.cr @@ -1,9 +1,9 @@ require "../../../spec_helper" module Ameba::Rule::Style - subject = UnlessElse.new - describe UnlessElse do + subject = UnlessElse.new + it "passes if unless hasn't else" do expect_no_issues subject, <<-CRYSTAL unless something diff --git a/spec/ameba/rule/style/verbose_block_spec.cr b/spec/ameba/rule/style/verbose_block_spec.cr index 0373c2a4a..b0a72495d 100644 --- a/spec/ameba/rule/style/verbose_block_spec.cr +++ b/spec/ameba/rule/style/verbose_block_spec.cr @@ -1,9 +1,9 @@ require "../../../spec_helper" module Ameba::Rule::Style - subject = VerboseBlock.new - describe VerboseBlock do + subject = VerboseBlock.new + it "passes if there is no potential performance improvements" do expect_no_issues subject, <<-CRYSTAL (1..3).any?(&.odd?) diff --git a/spec/ameba/rule/style/while_true_spec.cr b/spec/ameba/rule/style/while_true_spec.cr index 7c11505d8..0fa45eadf 100644 --- a/spec/ameba/rule/style/while_true_spec.cr +++ b/spec/ameba/rule/style/while_true_spec.cr @@ -1,9 +1,9 @@ require "../../../spec_helper" module Ameba::Rule::Style - subject = WhileTrue.new - describe WhileTrue do + subject = WhileTrue.new + it "passes if there is no `while true`" do expect_no_issues subject, <<-CRYSTAL a = 1 diff --git a/spec/ameba/rule/typing/method_parameter_type_restriction_spec.cr b/spec/ameba/rule/typing/method_parameter_type_restriction_spec.cr index b37121fc9..070ea4c24 100644 --- a/spec/ameba/rule/typing/method_parameter_type_restriction_spec.cr +++ b/spec/ameba/rule/typing/method_parameter_type_restriction_spec.cr @@ -164,10 +164,10 @@ module Ameba::Rule::Typing rule = MethodParameterTypeRestriction.new rule.default_value = true - expect_issue rule, <<-CRYSTAL + expect_issue rule, <<-'CRYSTAL' def hello(a = "world") # ^ error: Method parameter should have a type restriction - "hello \#{a}" + "hello #{a}" end CRYSTAL end @@ -187,10 +187,10 @@ module Ameba::Rule::Typing end it "fails if a block parameter with a name doesn't have a type restriction" do - expect_issue rule, <<-CRYSTAL + expect_issue rule, <<-'CRYSTAL' def hello(&a) # ^ error: Method parameter should have a type restriction - "hello, \#{a.call}" + "hello, #{a.call}" end CRYSTAL end diff --git a/spec/ameba/rule/typing/method_return_type_restriction_spec.cr b/spec/ameba/rule/typing/method_return_type_restriction_spec.cr index 2880c9a06..08cd8622f 100644 --- a/spec/ameba/rule/typing/method_return_type_restriction_spec.cr +++ b/spec/ameba/rule/typing/method_return_type_restriction_spec.cr @@ -1,121 +1,123 @@ require "../../../spec_helper" module Ameba::Rule::Typing - subject = MethodReturnTypeRestriction.new - - it "passes if a method has a return type restriction" do - expect_no_issues subject, <<-CRYSTAL - def hello : String - "hello world" - end - - private def hello : String - "hello world" - end - - protected def hello : String - "hello world" - end - CRYSTAL - end - - it "passes if a private or protected method doesn't have a return type restriction" do - expect_no_issues subject, <<-CRYSTAL - private def hello - "hello world" - end - - protected def hello - "hello world" - end - CRYSTAL - end - - it "fails if a public method doesn't have a return type restriction" do - expect_issue subject, <<-CRYSTAL - def hello - # ^^^^^^^ error: Method should have a return type restriction - "hello world" - end - CRYSTAL - end - - context "properties" do - context "#private_methods" do - rule = MethodReturnTypeRestriction.new - rule.private_methods = true - - it "passes if a method has a return type restriction" do - expect_no_issues rule, <<-CRYSTAL - def hello : String - "hello world" - end - - private def hello : String - "hello world" - end - - protected def hello : String - "hello world" - end - CRYSTAL - end + describe MethodReturnTypeRestriction do + subject = MethodReturnTypeRestriction.new + + it "passes if a method has a return type restriction" do + expect_no_issues subject, <<-CRYSTAL + def hello : String + "hello world" + end + + private def hello : String + "hello world" + end + + protected def hello : String + "hello world" + end + CRYSTAL + end - it "passes if a protected method doesn't have a return type restriction" do - expect_no_issues rule, <<-CRYSTAL - protected def hello - "hello world" - end - CRYSTAL - end + it "passes if a private or protected method doesn't have a return type restriction" do + expect_no_issues subject, <<-CRYSTAL + private def hello + "hello world" + end - it "fails if a public or private method doesn't have a return type restriction" do - expect_issue rule, <<-CRYSTAL - def hello - # ^^^^^^^ error: Method should have a return type restriction - "hello world" - end - - private def hello - # ^^^^^^^^^ error: Method should have a return type restriction - "hello world" - end - CRYSTAL - end + protected def hello + "hello world" + end + CRYSTAL end - context "#protected_methods" do - rule = MethodReturnTypeRestriction.new - rule.protected_methods = true - - it "passes if a method has a return type restriction" do - expect_no_issues rule, <<-CRYSTAL - protected def hello : String - "hello world" - end - CRYSTAL - end + it "fails if a public method doesn't have a return type restriction" do + expect_issue subject, <<-CRYSTAL + def hello + # ^^^^^^^ error: Method should have a return type restriction + "hello world" + end + CRYSTAL + end - it "passes if a private method doesn't have a return type restriction" do - expect_no_issues rule, <<-CRYSTAL - private def hello - "hello world" - end - CRYSTAL + context "properties" do + context "#private_methods" do + rule = MethodReturnTypeRestriction.new + rule.private_methods = true + + it "passes if a method has a return type restriction" do + expect_no_issues rule, <<-CRYSTAL + def hello : String + "hello world" + end + + private def hello : String + "hello world" + end + + protected def hello : String + "hello world" + end + CRYSTAL + end + + it "passes if a protected method doesn't have a return type restriction" do + expect_no_issues rule, <<-CRYSTAL + protected def hello + "hello world" + end + CRYSTAL + end + + it "fails if a public or private method doesn't have a return type restriction" do + expect_issue rule, <<-CRYSTAL + def hello + # ^^^^^^^ error: Method should have a return type restriction + "hello world" + end + + private def hello + # ^^^^^^^^^ error: Method should have a return type restriction + "hello world" + end + CRYSTAL + end end - it "fails if a public or protected method doesn't have a return type restriction" do - expect_issue rule, <<-CRYSTAL - def hello - # ^^^^^^^ error: Method should have a return type restriction - "hello world" - end - - protected def hello - # ^^^^^^^^^ error: Method should have a return type restriction - "hello world" - end - CRYSTAL + context "#protected_methods" do + rule = MethodReturnTypeRestriction.new + rule.protected_methods = true + + it "passes if a method has a return type restriction" do + expect_no_issues rule, <<-CRYSTAL + protected def hello : String + "hello world" + end + CRYSTAL + end + + it "passes if a private method doesn't have a return type restriction" do + expect_no_issues rule, <<-CRYSTAL + private def hello + "hello world" + end + CRYSTAL + end + + it "fails if a public or protected method doesn't have a return type restriction" do + expect_issue rule, <<-CRYSTAL + def hello + # ^^^^^^^ error: Method should have a return type restriction + "hello world" + end + + protected def hello + # ^^^^^^^^^ error: Method should have a return type restriction + "hello world" + end + CRYSTAL + end end end end diff --git a/spec/ameba/rule/typing/proc_literal_return_type_restriction_spec.cr b/spec/ameba/rule/typing/proc_literal_return_type_restriction_spec.cr index dacb4da1d..d12427b8b 100644 --- a/spec/ameba/rule/typing/proc_literal_return_type_restriction_spec.cr +++ b/spec/ameba/rule/typing/proc_literal_return_type_restriction_spec.cr @@ -1,18 +1,20 @@ require "../../../spec_helper" module Ameba::Rule::Typing - subject = ProcLiteralReturnTypeRestriction.new + describe ProcLiteralReturnTypeRestriction do + subject = ProcLiteralReturnTypeRestriction.new - it "passes if a proc literal has a return type restriction" do - expect_no_issues subject, <<-CRYSTAL - my_proc = ->(var : String) : Nil { puts var } - CRYSTAL - end + it "passes if a proc literal has a return type restriction" do + expect_no_issues subject, <<-CRYSTAL + my_proc = ->(var : String) : Nil { puts var } + CRYSTAL + end - it "fails if a proc literal doesn't have a return type restriction" do - expect_issue subject, <<-CRYSTAL - my_proc = ->(var : String) { puts var } - # ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: Proc literal should have a return type restriction - CRYSTAL + it "fails if a proc literal doesn't have a return type restriction" do + expect_issue subject, <<-CRYSTAL + my_proc = ->(var : String) { puts var } + # ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: Proc literal should have a return type restriction + CRYSTAL + end end end diff --git a/spec/ameba/source_spec.cr b/spec/ameba/source_spec.cr index b653a8c8d..6238cd144 100644 --- a/spec/ameba/source_spec.cr +++ b/spec/ameba/source_spec.cr @@ -71,8 +71,8 @@ module Ameba end end - Ameba.ecr_supported? do - describe "#ast" do + describe "#ast" do + Ameba.ecr_supported? do it "parses an ECR file" do source = Source.new <<-ECR, "filename.ecr" hello <%= "world" %> diff --git a/src/ameba.cr b/src/ameba.cr index 9f4d689e9..a3a75843b 100644 --- a/src/ameba.cr +++ b/src/ameba.cr @@ -20,6 +20,12 @@ module Ameba VERSION = {{ `shards version "#{__DIR__}"`.chomp.stringify }} + macro ecr_supported?(&) + {% if compare_versions(Crystal::VERSION, "1.15.0") >= 0 %} + {{ yield }} + {% end %} + end + # Initializes `Ameba::Runner` and runs it. # Can be configured via `config` parameter. # @@ -32,12 +38,6 @@ module Ameba def run(config = Config.load) Runner.new(config).run end - - macro ecr_supported?(&) - {% if compare_versions(Crystal::VERSION, "1.15.0") >= 0 %} - {{ yield }} - {% end %} - end end require "./ameba/*" diff --git a/src/ameba/ast/branch.cr b/src/ameba/ast/branch.cr index 3c958f7d1..e2413d766 100644 --- a/src/ameba/ast/branch.cr +++ b/src/ameba/ast/branch.cr @@ -64,10 +64,9 @@ module Ameba::AST # Branch.of(assign_node, def_node) # ``` def self.of(node : Crystal::ASTNode, parent_node : Crystal::ASTNode) - BranchVisitor.new(node).tap(&.accept(parent_node)).branch + BranchVisitor.new(node, parent_node).branch end - # :nodoc: private class BranchVisitor < Crystal::Visitor include Util @@ -76,7 +75,8 @@ module Ameba::AST property branchable : Branchable? property branch : Branch? - def initialize(@node : Crystal::ASTNode) + def initialize(@node : Crystal::ASTNode, parent_node : Crystal::ASTNode) + accept parent_node end private def on_branchable_start(node, *branches) diff --git a/src/ameba/ast/visitors/counting_visitor.cr b/src/ameba/ast/visitors/counting_visitor.cr index 347e5ccd3..ba41e9e78 100644 --- a/src/ameba/ast/visitors/counting_visitor.cr +++ b/src/ameba/ast/visitors/counting_visitor.cr @@ -3,11 +3,15 @@ module Ameba::AST class CountingVisitor < Crystal::Visitor DEFAULT_COMPLEXITY = 1 + # Returns the number of keywords that were found in the node + getter count = DEFAULT_COMPLEXITY + + # Returns `true` if the node is within a macro condition getter? macro_condition = false # Creates a new counting visitor - def initialize(@scope : Crystal::ASTNode) - @complexity = DEFAULT_COMPLEXITY + def initialize(node : Crystal::ASTNode) + node.accept self end # :nodoc: @@ -15,19 +19,13 @@ module Ameba::AST true end - # Returns the number of keywords that were found in the node - def count - @scope.accept(self) - @complexity - end - # Uses the same logic than rubocop. See # https://github.com/rubocop-hq/rubocop/blob/master/lib/rubocop/cop/metrics/cyclomatic_complexity.rb#L21 # Except "for", because crystal doesn't have a "for" loop. {% for node in %i[if while until rescue or and] %} # :nodoc: def visit(node : Crystal::{{ node.id.capitalize }}) - @complexity += 1 unless macro_condition? + @count += 1 unless macro_condition? end {% end %} @@ -37,14 +35,14 @@ module Ameba::AST # Count the complexity of an exhaustive `Case` as 1 # Otherwise count the number of `When`s - @complexity += node.exhaustive? ? 1 : node.whens.size + @count += node.exhaustive? ? 1 : node.whens.size true end def visit(node : Crystal::MacroIf | Crystal::MacroFor) @macro_condition = true - @complexity = DEFAULT_COMPLEXITY + @count = DEFAULT_COMPLEXITY false end diff --git a/src/ameba/ast/visitors/top_level_nodes_visitor.cr b/src/ameba/ast/visitors/top_level_nodes_visitor.cr index 5e5ad9131..e4b8ddaf9 100644 --- a/src/ameba/ast/visitors/top_level_nodes_visitor.cr +++ b/src/ameba/ast/visitors/top_level_nodes_visitor.cr @@ -5,8 +5,8 @@ module Ameba::AST getter require_nodes = [] of Crystal::Require # Creates a new instance of visitor - def initialize(@scope : Crystal::ASTNode) - @scope.accept(self) + def initialize(node : Crystal::ASTNode) + node.accept self end # :nodoc: diff --git a/src/ameba/config.cr b/src/ameba/config.cr index d09fff347..0be608cf7 100644 --- a/src/ameba/config.cr +++ b/src/ameba/config.cr @@ -370,10 +370,9 @@ class Ameba::Config macro included GROUP_SEVERITY = { - Documentation: Ameba::Severity::Warning, - Lint: Ameba::Severity::Warning, - Metrics: Ameba::Severity::Warning, - Performance: Ameba::Severity::Warning, + Lint: Ameba::Severity::Warning, + Metrics: Ameba::Severity::Warning, + Performance: Ameba::Severity::Warning, } class_getter default_severity : Ameba::Severity do diff --git a/src/ameba/rule/documentation/documentation_admonition.cr b/src/ameba/rule/documentation/documentation_admonition.cr index a9fd7e8e9..fc8daa17e 100644 --- a/src/ameba/rule/documentation/documentation_admonition.cr +++ b/src/ameba/rule/documentation/documentation_admonition.cr @@ -36,6 +36,7 @@ module Ameba::Rule::Documentation properties do since_version "1.6.0" description "Reports documentation admonitions" + severity :warning admonitions %w[TODO FIXME BUG] timezone "UTC" end @@ -63,12 +64,10 @@ module Ameba::Rule::Documentation begin case expr = match["context"]?.presence when /\A\d{4}-\d{2}-\d{2}\Z/ # date - # ameba:disable Lint/NotNil - date = Time.parse(expr.not_nil!, "%F", location) + date = Time.parse($0, "%F", location) issue_for_date source, token, admonition, date when /\A\d{4}-\d{2}-\d{2} \d{2}:\d{2}(:\d{2})?\Z/ # date + time (no tz) - # ameba:disable Lint/NotNil - date = Time.parse(expr.not_nil!, "%F #{$1?.presence ? "%T" : "%R"}", location) + date = Time.parse($0, "%F #{$1?.presence ? "%T" : "%R"}", location) issue_for_date source, token, admonition, date else issue_for token, MSG % admonition diff --git a/src/ameba/rule/lint/formatting.cr b/src/ameba/rule/lint/formatting.cr index 8664261c2..643707247 100644 --- a/src/ameba/rule/lint/formatting.cr +++ b/src/ameba/rule/lint/formatting.cr @@ -39,12 +39,13 @@ module Ameba::Rule::Lint def test(source) source_code = source.code - result = Crystal.format(source_code, source.path) - return if result == source_code source_lines = source_code.lines return if source_lines.empty? + result = Crystal.format(source_code, source.path) + return if result == source_code + end_location = { source_lines.size, source_lines.last.size + 1, diff --git a/src/ameba/rule/lint/require_parentheses.cr b/src/ameba/rule/lint/require_parentheses.cr index c62cb82c6..db3e778cd 100644 --- a/src/ameba/rule/lint/require_parentheses.cr +++ b/src/ameba/rule/lint/require_parentheses.cr @@ -40,11 +40,11 @@ module Ameba::Rule::Lint node.name.in?(ALLOWED_CALL_NAMES) node.args.each do |arg| - if arg.is_a?(Crystal::BinaryOp) - if (right = arg.right).is_a?(Crystal::Call) - issue_for node, MSG unless right.args.empty? - end - end + next unless arg.is_a?(Crystal::BinaryOp) + next unless (right = arg.right).is_a?(Crystal::Call) + next if right.args.empty? + + issue_for node, MSG end end end diff --git a/src/ameba/rule/lint/trailing_rescue_exception.cr b/src/ameba/rule/lint/trailing_rescue_exception.cr index 426d11c40..9d803ea9e 100644 --- a/src/ameba/rule/lint/trailing_rescue_exception.cr +++ b/src/ameba/rule/lint/trailing_rescue_exception.cr @@ -1,30 +1,30 @@ module Ameba::Rule::Lint - # A rule that prohibits the common misconception about how trailing rescue statements work, - # preventing Paths (exception class names or otherwise) from being - # used as the trailing value. The value after the trailing rescue statement is the - # value to use if an exception occurs, not the exception for the rescue to capture. + # A rule that prohibits the misconception about how trailing `rescue` statements work, + # preventing Paths (exception class names or otherwise) from being used as the + # trailing value. The value after the trailing `rescue` statement is the value + # to use if an exception occurs, not the exception class to rescue from. # - # For example, this is considered invalid - if an exception occurs in `method.call`, - # `value` will be assigned the value of `MyException`: + # For example, this is considered invalid - if an exception occurs, + # `response` will be assigned with the value of `IO::Error` instead of `nil`: # # ``` - # value = method.call("param") rescue MyException + # response = HTTP::Client.get("http://www.example.com") rescue IO::Error # ``` # - # And should instead be written as this in order to capture only `MyException` exceptions: + # And should instead be written as this in order to capture only `IO::Error` exceptions: # # ``` - # value = begin - # method.call("param") - # rescue MyException + # response = begin + # HTTP::Client.get("http://www.example.com") + # rescue IO::Error # "default value" # end # ``` # - # Or to rescue all exceptions (instead of just `MyException`): + # Or to rescue all exceptions (instead of just `IO::Error`): # # ``` - # value = method.call("param") rescue "default value" + # response = HTTP::Client.get("http://www.example.com") rescue "default value" # ``` # # YAML configuration example: @@ -36,10 +36,10 @@ module Ameba::Rule::Lint class TrailingRescueException < Base properties do since_version "1.7.0" - description "Disallows trailing rescue with a path" + description "Disallows trailing `rescue` with a path" end - MSG = "Trailing rescues with a path aren't allowed, use a block rescue instead to filter by exception type" + MSG = "Use a block variant of `rescue` to filter by the exception type" def test(source, node : Crystal::ExceptionHandler) return unless node.suffix && diff --git a/src/ameba/rule/lint/typos.cr b/src/ameba/rule/lint/typos.cr index 20bdd3866..28e389241 100644 --- a/src/ameba/rule/lint/typos.cr +++ b/src/ameba/rule/lint/typos.cr @@ -10,7 +10,8 @@ module Ameba::Rule::Lint # Lint/Typos: # Enabled: true # BinPath: ~ - # FailOnError: false + # FailOnMissingBin: false + # FailOnError: true # ``` class Typos < Base properties do @@ -18,10 +19,11 @@ module Ameba::Rule::Lint description "Reports typos found in source files" bin_path nil, as: String? - fail_on_error false + fail_on_missing_bin false + fail_on_error true end - MSG = "Typo found: `%s` -> `%s`" + MSG = "Typo found: `%s` -> %s" BIN_PATH = Process.find_executable("typos") rescue nil @@ -79,7 +81,7 @@ module Ameba::Rule::Lint typos.try &.each do |typo| corrections = typo.corrections message = MSG % { - typo.typo, corrections.join(" | "), + typo.typo, corrections.map { |correction| "`#{correction}`" }.join(" | "), } if corrections.size == 1 issue_for typo.location, typo.end_location, message do |corrector| @@ -97,7 +99,7 @@ module Ameba::Rule::Lint if bin_path = self.bin_path return Typos.typos_from(bin_path, source) end - if fail_on_error? + if fail_on_missing_bin? raise RuntimeError.new "Could not find `typos` executable" end end diff --git a/src/ameba/rule/lint/unneeded_disable_directive.cr b/src/ameba/rule/lint/unneeded_disable_directive.cr index 5c447cbf1..0717c4be5 100644 --- a/src/ameba/rule/lint/unneeded_disable_directive.cr +++ b/src/ameba/rule/lint/unneeded_disable_directive.cr @@ -9,7 +9,7 @@ module Ameba::Rule::Lint # end # ``` # - # as the predicate name is correct and the comment directive does not + # As the predicate name is correct and the comment directive does not # have any effect, the snippet should be written as the following: # # ``` diff --git a/src/ameba/rule/lint/unused_generic_or_union.cr b/src/ameba/rule/lint/unused_generic_or_union.cr index 0651034a2..a34ceaed9 100644 --- a/src/ameba/rule/lint/unused_generic_or_union.cr +++ b/src/ameba/rule/lint/unused_generic_or_union.cr @@ -40,8 +40,8 @@ module Ameba::Rule::Lint description "Disallows unused generics or unions" end - GENERIC_MSG = "Generic is not used" - UNION_MSG = "Union is not used" + MSG_GENERIC = "Generic is not used" + MSG_UNION = "Union is not used" def test(source : Source) AST::ImplicitReturnVisitor.new(self, source) @@ -50,11 +50,11 @@ module Ameba::Rule::Lint def test(source, node : Crystal::Call, node_is_used : Bool) return if node_is_used || !path_or_generic_union?(node) - issue_for node, UNION_MSG + issue_for node, MSG_UNION end def test(source, node : Crystal::Generic, node_is_used : Bool) - issue_for node, GENERIC_MSG unless node_is_used + issue_for node, MSG_GENERIC unless node_is_used end private def path_or_generic_union?(node : Crystal::Call) : Bool diff --git a/src/ameba/rule/lint/unused_literal.cr b/src/ameba/rule/lint/unused_literal.cr index 33e504293..359b4e508 100644 --- a/src/ameba/rule/lint/unused_literal.cr +++ b/src/ameba/rule/lint/unused_literal.cr @@ -35,8 +35,6 @@ module Ameba::Rule::Lint # true # end # end - # - # my_proc = -> : Bool { true } # ``` # # YAML configuration example: diff --git a/src/ameba/rule/lint/useless_condition_in_when.cr b/src/ameba/rule/lint/useless_condition_in_when.cr index 00c0f3ec6..c32d20536 100644 --- a/src/ameba/rule/lint/useless_condition_in_when.cr +++ b/src/ameba/rule/lint/useless_condition_in_when.cr @@ -1,5 +1,5 @@ module Ameba::Rule::Lint - # A rule that disallows useless conditions in when clause + # A rule that disallows useless conditions in `when` clause # where it is guaranteed to always return the same result. # # For example, this is considered invalid: @@ -33,10 +33,10 @@ module Ameba::Rule::Lint class UselessConditionInWhen < Base properties do since_version "0.3.0" - description "Disallows useless conditions in when" + description "Disallows useless conditions in `when`" end - MSG = "Useless condition in when detected" + MSG = "Useless condition in `when` detected" # TODO: condition *cond* may be a complex ASTNode with # useless inner conditions. We might need to improve this @@ -52,7 +52,6 @@ module Ameba::Rule::Lint ConditionInWhenVisitor.new self, source, node end - # :nodoc: private class ConditionInWhenVisitor < Crystal::Visitor @source : Source @rule : UselessConditionInWhen diff --git a/src/ameba/rule/style/guard_clause.cr b/src/ameba/rule/style/guard_clause.cr index 936251ce2..311e26b57 100644 --- a/src/ameba/rule/style/guard_clause.cr +++ b/src/ameba/rule/style/guard_clause.cr @@ -178,7 +178,7 @@ module Ameba::Rule::Style end end - def guard_clause_source(source, guard_clause, parent) + private def guard_clause_source(source, guard_clause, parent) node = parent.is_a?(Crystal::BinaryOp) ? parent : guard_clause node_source(node, source.lines) diff --git a/src/ameba/rule/style/negated_conditions_in_unless.cr b/src/ameba/rule/style/negated_conditions_in_unless.cr index c7b633706..bd4156fdc 100644 --- a/src/ameba/rule/style/negated_conditions_in_unless.cr +++ b/src/ameba/rule/style/negated_conditions_in_unless.cr @@ -1,5 +1,5 @@ module Ameba::Rule::Style - # A rule that disallows negated conditions in unless. + # A rule that disallows negated conditions in `unless`. # # For example, this is considered invalid: # diff --git a/src/ameba/rule/style/parentheses_around_condition.cr b/src/ameba/rule/style/parentheses_around_condition.cr index 45710b8fc..4bf179b77 100644 --- a/src/ameba/rule/style/parentheses_around_condition.cr +++ b/src/ameba/rule/style/parentheses_around_condition.cr @@ -38,21 +38,6 @@ module Ameba::Rule::Style MSG_REDUNDANT = "Redundant parentheses" MSG_MISSING = "Missing parentheses" - protected def strip_parentheses?(node, in_ternary) : Bool - case node - when Crystal::BinaryOp, Crystal::ExceptionHandler - !in_ternary - when Crystal::Call - !in_ternary || node.has_parentheses? || node.args.empty? - when Crystal::Yield - !in_ternary || node.has_parentheses? || node.exps.empty? - when Crystal::Assign, Crystal::OpAssign, Crystal::MultiAssign - !in_ternary && !allow_safe_assignment? - else - true - end - end - def test(source, node : Crystal::If | Crystal::Unless | Crystal::Case | Crystal::While | Crystal::Until) cond = node.cond @@ -78,5 +63,20 @@ module Ameba::Rule::Style corrector.remove_leading(cond, 1) end end + + private def strip_parentheses?(node, in_ternary) : Bool + case node + when Crystal::BinaryOp, Crystal::ExceptionHandler + !in_ternary + when Crystal::Call + !in_ternary || node.has_parentheses? || node.args.empty? + when Crystal::Yield + !in_ternary || node.has_parentheses? || node.exps.empty? + when Crystal::Assign, Crystal::OpAssign, Crystal::MultiAssign + !in_ternary && !allow_safe_assignment? + else + true + end + end end end diff --git a/src/ameba/rule/style/redundant_begin.cr b/src/ameba/rule/style/redundant_begin.cr index 6ababbadb..ec00c87f2 100644 --- a/src/ameba/rule/style/redundant_begin.cr +++ b/src/ameba/rule/style/redundant_begin.cr @@ -1,5 +1,5 @@ module Ameba::Rule::Style - # A rule that disallows redundant begin blocks. + # A rule that disallows redundant `begin` blocks. # # Currently it is able to detect: # @@ -27,7 +27,7 @@ module Ameba::Rule::Style # end # ``` # - # 2. begin..end block as a top level block in a method. + # 2. `begin`..`end` block as a top level block in a method. # # For example this is considered invalid: # @@ -60,7 +60,7 @@ module Ameba::Rule::Style properties do since_version "0.3.0" - description "Disallows redundant begin blocks" + description "Disallows redundant `begin` blocks" end MSG = "Redundant `begin` block detected" diff --git a/src/ameba/rule/style/redundant_next.cr b/src/ameba/rule/style/redundant_next.cr index 63544c3d2..f856d6db1 100644 --- a/src/ameba/rule/style/redundant_next.cr +++ b/src/ameba/rule/style/redundant_next.cr @@ -1,5 +1,5 @@ module Ameba::Rule::Style - # A rule that disallows redundant next expressions. A `next` keyword allows + # A rule that disallows redundant `next` expressions. A `next` keyword allows # a block to skip to the next iteration early, however, it is considered # redundant in cases where it is the last expression in a block or combines # into the node which is the last in a block. @@ -50,7 +50,7 @@ module Ameba::Rule::Style # # 1. *allow_multi_next*, default: true # - # Allows end-user to configure whether to report or not the next statements + # Allows end-user to configure whether to report or not the `next` statements # which yield tuple literals i.e. # # ``` @@ -69,8 +69,8 @@ module Ameba::Rule::Style # # 2. *allow_empty_next*, default: true # - # Allows end-user to configure whether to report or not the next statements - # without arguments. Sometimes such statements are used to yild the `nil` value explicitly. + # Allows end-user to configure whether to report or not the `next` statements + # without arguments. Sometimes such statements are used to yield the `nil` value explicitly. # # ``` # block do @@ -101,7 +101,7 @@ module Ameba::Rule::Style properties do since_version "0.12.0" - description "Reports redundant next expressions" + description "Reports redundant `next` expressions" allow_multi_next true allow_empty_next true diff --git a/src/ameba/rule/style/redundant_return.cr b/src/ameba/rule/style/redundant_return.cr index ecfdfb6c5..4a6d98a67 100644 --- a/src/ameba/rule/style/redundant_return.cr +++ b/src/ameba/rule/style/redundant_return.cr @@ -1,5 +1,5 @@ module Ameba::Rule::Style - # A rule that disallows redundant return expressions. + # A rule that disallows redundant `return` expressions. # # For example, this is considered invalid: # @@ -47,7 +47,7 @@ module Ameba::Rule::Style # # 1. *allow_multi_return*, default: true # - # Allows end-user to configure whether to report or not the return statements + # Allows end-user to configure whether to report or not the `return` statements # which return tuple literals i.e. # # ``` @@ -66,7 +66,7 @@ module Ameba::Rule::Style # # 2. *allow_empty_return*, default: true # - # Allows end-user to configure whether to report or not the return statements + # Allows end-user to configure whether to report or not the `return` statements # without arguments. Sometimes such returns are used to return the `nil` value explicitly. # # ``` @@ -98,7 +98,7 @@ module Ameba::Rule::Style properties do since_version "0.9.0" - description "Reports redundant return expressions" + description "Reports redundant `return` expressions" allow_multi_return true allow_empty_return true diff --git a/src/ameba/rule/style/verbose_block.cr b/src/ameba/rule/style/verbose_block.cr index df81d5532..f7294d413 100644 --- a/src/ameba/rule/style/verbose_block.cr +++ b/src/ameba/rule/style/verbose_block.cr @@ -47,7 +47,7 @@ module Ameba::Rule::Style MSG = "Use short block notation instead: `%s`" CALL_PATTERN = "%s(%s&.%s)" - protected def same_location_lines?(a, b) + private def same_location_lines?(a, b) return unless a_location = name_location(a) return unless b_location = b.location @@ -58,26 +58,26 @@ module Ameba::Rule::Style private OPERATOR_CHARS = {'[', ']', '!', '=', '>', '<', '~', '+', '-', '*', '/', '%', '^', '|', '&'} - protected def prefix_operator?(node) + private def prefix_operator?(node) node.name.in?(PREFIX_OPERATORS) && node.args.empty? end - protected def operator?(name) + private def operator?(name) !name.empty? && name[0].in?(OPERATOR_CHARS) end - protected def setter?(name) + private def setter?(name) !name.empty? && name[0].letter? && name.ends_with?('=') end - protected def valid_length?(code) + private def valid_length?(code) if max_length = self.max_length return code.size <= max_length end true end - protected def valid_line_length?(node, code) + private def valid_line_length?(node, code) if max_line_length = self.max_line_length if location = name_location(node) final_line_length = location.column_number + code.size @@ -87,7 +87,7 @@ module Ameba::Rule::Style true end - protected def reference_count(node, obj : Crystal::Var) + private def reference_count(node, obj : Crystal::Var) i = 0 case node when Crystal::Call @@ -111,7 +111,7 @@ module Ameba::Rule::Style i end - protected def args_to_s(io : IO, node : Crystal::Call, short_block = nil, skip_last_arg = false) : Nil + private def args_to_s(io : IO, node : Crystal::Call, short_block = nil, skip_last_arg = false) : Nil args = node.args.dup args.pop? if skip_last_arg args.join io, ", " @@ -130,7 +130,7 @@ module Ameba::Rule::Style end end - protected def node_to_s(source, node : Crystal::Call) + private def node_to_s(source, node : Crystal::Call) String.build do |str| case name = node.name when "[]" @@ -158,7 +158,7 @@ module Ameba::Rule::Style end end - protected def short_block_code(source, node : Crystal::Call) + private def short_block_code(source, node : Crystal::Call) return unless block = node.block return unless block_location = block.location return unless block_end_location = block.body.end_location @@ -167,7 +167,7 @@ module Ameba::Rule::Style block_code if block_code.try(&.starts_with?("&.")) end - protected def call_code(source, call, body) + private def call_code(source, call, body) args = String.build { |io| args_to_s(io, call) }.presence args += ", " if args @@ -188,7 +188,7 @@ module Ameba::Rule::Style end # ameba:disable Metrics/CyclomaticComplexity - protected def issue_for_valid(source, call : Crystal::Call, block : Crystal::Block, body : Crystal::Call) + private def issue_for_valid(source, call : Crystal::Call, block : Crystal::Block, body : Crystal::Call) return if exclude_calls_with_block? && body.block return if exclude_multiple_line_blocks? && !same_location_lines?(call, body) return if exclude_prefix_operators? && prefix_operator?(body) diff --git a/src/ameba/rule/typing/macro_call_argument_type_restriction.cr b/src/ameba/rule/typing/macro_call_argument_type_restriction.cr index fab1e2d82..7f7805a73 100644 --- a/src/ameba/rule/typing/macro_call_argument_type_restriction.cr +++ b/src/ameba/rule/typing/macro_call_argument_type_restriction.cr @@ -37,7 +37,7 @@ module Ameba::Rule::Typing # # ``` # Typing/MacroCallArgumentTypeRestriction: - # Enabled: false + # Enabled: true # DefaultValue: false # MacroNames: # - getter @@ -84,9 +84,9 @@ module Ameba::Rule::Typing when Crystal::Assign next unless default_value? - issue_for arg.target, MSG, prefer_name_location: true + issue_for arg.target, MSG when Crystal::Var, Crystal::Call, Crystal::StringLiteral, Crystal::SymbolLiteral - issue_for arg, MSG, prefer_name_location: true + issue_for arg, MSG end end end diff --git a/src/ameba/rule/typing/method_parameter_type_restriction.cr b/src/ameba/rule/typing/method_parameter_type_restriction.cr index 1e4d5df47..f81f0f0a1 100644 --- a/src/ameba/rule/typing/method_parameter_type_restriction.cr +++ b/src/ameba/rule/typing/method_parameter_type_restriction.cr @@ -44,11 +44,11 @@ module Ameba::Rule::Typing # # ``` # Typing/MethodParameterTypeRestriction: - # Enabled: false + # Enabled: true # DefaultValue: false + # BlockParameters: false # PrivateMethods: false # ProtectedMethods: false - # BlockParameters: false # ``` class MethodParameterTypeRestriction < Base properties do @@ -56,32 +56,29 @@ module Ameba::Rule::Typing description "Recommends that method parameters have type restrictions" enabled false default_value false + block_parameters false private_methods false protected_methods false - block_parameters false end MSG = "Method parameter should have a type restriction" def test(source, node : Crystal::Def) - return if valid?(node) + return if valid_visibility?(node) node.args.each do |arg| - next if arg.restriction || arg.name.empty? || (!default_value? && arg.default_value) + next if arg.restriction || arg.name.empty? + next if !default_value? && arg.default_value issue_for arg, MSG end - if block_parameters? - node.block_arg.try do |block_arg| - next if block_arg.restriction - - issue_for block_arg, MSG - end + if block_parameters? && (block_arg = node.block_arg) && !block_arg.restriction + issue_for block_arg, MSG end end - private def valid?(node : Crystal::ASTNode) : Bool + private def valid_visibility?(node : Crystal::ASTNode) : Bool (!private_methods? && node.visibility.private?) || (!protected_methods? && node.visibility.protected?) end diff --git a/src/ameba/rule/typing/method_return_type_restriction.cr b/src/ameba/rule/typing/method_return_type_restriction.cr index 079dc7667..43d7b8bed 100644 --- a/src/ameba/rule/typing/method_return_type_restriction.cr +++ b/src/ameba/rule/typing/method_return_type_restriction.cr @@ -24,7 +24,7 @@ module Ameba::Rule::Typing # # ``` # Typing/MethodReturnTypeRestriction: - # Enabled: false + # Enabled: true # PrivateMethods: false # ProtectedMethods: false # ``` @@ -43,7 +43,7 @@ module Ameba::Rule::Typing issue_for node, MSG unless valid_return_type?(node) end - def valid_return_type?(node : Crystal::ASTNode) : Bool + private def valid_return_type?(node : Crystal::ASTNode) : Bool !!node.return_type || (node.visibility.private? && !private_methods?) || (node.visibility.protected? && !protected_methods?) diff --git a/src/ameba/rule/typing/proc_literal_return_type_restriction.cr b/src/ameba/rule/typing/proc_literal_return_type_restriction.cr index 05563e781..3112817dc 100644 --- a/src/ameba/rule/typing/proc_literal_return_type_restriction.cr +++ b/src/ameba/rule/typing/proc_literal_return_type_restriction.cr @@ -1,45 +1,43 @@ module Ameba::Rule::Typing # A rule that enforces that `Proc` literals have a return type. # - # For example, these are considered valid: + # For example, these are considered invalid: # # ``` - # greeter = ->(name : String) : String { "Hello #{name}" } + # greeter = ->(name : String) { "Hello #{name}" } # ``` # # ``` - # task = -> : Task { Task.new("execute this command") } + # task = -> { Task.new("execute this command") } # ``` # - # And these are invalid: + # And these are valid: # # ``` - # greeter = ->(name : String) { "Hello #{name}" } + # greeter = ->(name : String) : String { "Hello #{name}" } # ``` # # ``` - # task = -> { Task.new("execute this command") } + # task = -> : Task { Task.new("execute this command") } # ``` # # YAML configuration example: # # ``` # Typing/ProcLiteralReturnTypeRestriction: - # Enabled: false + # Enabled: true # ``` class ProcLiteralReturnTypeRestriction < Base properties do since_version "1.7.0" - description "Disallows Proc literals without return type restrictions" + description "Disallows proc literals without return type restriction" enabled false end MSG = "Proc literal should have a return type restriction" def test(source, node : Crystal::ProcLiteral) - return if node.def.return_type - - issue_for node, MSG + issue_for node, MSG unless node.def.return_type end end end diff --git a/src/ameba/source.cr b/src/ameba/source.cr index 89255de0c..13682a459 100644 --- a/src/ameba/source.cr +++ b/src/ameba/source.cr @@ -60,16 +60,16 @@ module Ameba code = @code Ameba.ecr_supported? do - if @path.ends_with?(".ecr") + if ecr? begin - code = ECR.process_string(code, @path) + code = ECR.process_string(code, path) rescue ex : ECR::Lexer::SyntaxException # Need to rescue to add the filename raise Crystal::SyntaxException.new( ex.message, ex.line_number, ex.column_number, - @path + path ) end end @@ -90,6 +90,11 @@ module Ameba path.ends_with?("_spec.cr") end + # Returns `true` if the source is an ECR template, `false` otherwise. + def ecr? + path.ends_with?(".ecr") + end + # Returns `true` if *filepath* matches the source's path, `false` otherwise. def matches_path?(filepath) fullpath == File.expand_path(filepath) diff --git a/src/ameba/source/rewriter/action.cr b/src/ameba/source/rewriter/action.cr index a13013c2d..cb5d14493 100644 --- a/src/ameba/source/rewriter/action.cr +++ b/src/ameba/source/rewriter/action.cr @@ -1,5 +1,6 @@ class Ameba::Source::Rewriter # :nodoc: + # # Actions are arranged in a tree and get combined so that: # - children are strictly contained by their parent # - siblings all disjoint from one another and ordered