diff --git a/.ameba.yml b/.ameba.yml index e9816260..f679ef08 100644 --- a/.ameba.yml +++ b/.ameba.yml @@ -4,4 +4,4 @@ Documentation/DocumentationAdmonition: Lint/Typos: Excluded: - - spec/ameba/rule/lint/typos_spec.cr + - spec/ameba/rule/lint/typos_spec.cr diff --git a/README.md b/README.md index 4b696f58..9791a5e3 100644 --- a/README.md +++ b/README.md @@ -118,7 +118,6 @@ Add this to your application's `shard.yml`: development_dependencies: ameba: github: crystal-ameba/ameba - version: ~> 1.4.0 ``` Build `bin/ameba` binary within your project directory while running `shards install`. @@ -165,7 +164,7 @@ Generate new file by running `ameba --gen-config`. **List of sources to run Ameba on can be configured globally via:** - `Globs` section - an array of wildcards (or paths) to include to the - inspection. Defaults to `%w(**/*.cr !lib)`, meaning it includes all project + inspection. Defaults to `%w[**/*.cr !lib]`, meaning it includes all project files with `*.cr` extension except those which exist in `lib` folder. - `Excluded` section - an array of wildcards (or paths) to exclude from the source list defined by `Globs`. Defaults to an empty array. @@ -186,8 +185,8 @@ Excluded: ``` yaml Style/RedundantBegin: Excluded: - - src/server/processor.cr - - src/server/api.cr + - src/server/processor.cr + - src/server/api.cr ``` ### Rules @@ -240,4 +239,4 @@ time = Time.epoch(1483859302) # ameba:disable Style, Lint ## Contributors - [veelenga](https://github.com/veelenga) Vitalii Elenhaupt - creator, maintainer -- [Sija](https://github.com/Sija) Sijawusz Pur Rahnama - maintainer +- [Sija](https://github.com/Sija) Sijawusz Pur Rahnama - contributor, maintainer diff --git a/shard.yml b/shard.yml index b0242637..5ebd6c8b 100644 --- a/shard.yml +++ b/shard.yml @@ -1,21 +1,22 @@ name: ameba -version: 1.5.0 +version: 1.6.0 authors: - Vitalii Elenhaupt + - Sijawusz Pur Rahnama targets: ameba: main: src/cli.cr scripts: - # TODO: remove pre-compiled executable in future releases postinstall: shards build -Dpreview_mt +# TODO: remove pre-compiled executable in future releases executables: - ameba - ameba.cr -crystal: "~> 1.9.0" +crystal: ~> 1.10 license: MIT diff --git a/spec/ameba/ast/util_spec.cr b/spec/ameba/ast/util_spec.cr index ea3cb8d2..56169fed 100644 --- a/spec/ameba/ast/util_spec.cr +++ b/spec/ameba/ast/util_spec.cr @@ -36,6 +36,43 @@ module Ameba::AST end end + describe "#static/dynamic_literal?" do + [ + Crystal::ArrayLiteral.new, + Crystal::ArrayLiteral.new([Crystal::StringLiteral.new("foo")] of Crystal::ASTNode), + Crystal::BoolLiteral.new(false), + Crystal::CharLiteral.new('a'), + Crystal::HashLiteral.new, + Crystal::NamedTupleLiteral.new, + Crystal::NilLiteral.new, + Crystal::NumberLiteral.new(42), + Crystal::RegexLiteral.new(Crystal::StringLiteral.new("")), + Crystal::StringLiteral.new("foo"), + Crystal::SymbolLiteral.new("foo"), + Crystal::TupleLiteral.new([] of Crystal::ASTNode), + Crystal::TupleLiteral.new([Crystal::StringLiteral.new("foo")] of Crystal::ASTNode), + Crystal::RangeLiteral.new( + Crystal::NumberLiteral.new(0), + Crystal::NumberLiteral.new(10), + true), + ].each do |literal| + it "properly identifies static node #{literal}" do + subject.static_literal?(literal).should be_true + subject.dynamic_literal?(literal).should be_false + end + end + + [ + Crystal::ArrayLiteral.new([Crystal::Path.new(%w[IO])] of Crystal::ASTNode), + Crystal::TupleLiteral.new([Crystal::Path.new(%w[IO])] of Crystal::ASTNode), + ].each do |literal| + it "properly identifies dynamic node #{literal}" do + subject.dynamic_literal?(literal).should be_true + subject.static_literal?(literal).should be_false + end + end + end + describe "#node_source" do it "returns original source of the node" do s = <<-CRYSTAL diff --git a/spec/ameba/base_spec.cr b/spec/ameba/base_spec.cr index d3afb5c8..81fe1145 100644 --- a/spec/ameba/base_spec.cr +++ b/spec/ameba/base_spec.cr @@ -10,7 +10,7 @@ module Ameba::Rule end it "contains rules across all the available groups" do - Rule.rules.map(&.group_name).uniq!.reject!(&.empty?).sort.should eq %w( + Rule.rules.map(&.group_name).uniq!.reject!(&.empty?).sort.should eq %w[ Ameba Documentation Layout @@ -19,7 +19,7 @@ module Ameba::Rule Naming Performance Style - ) + ] end end @@ -50,25 +50,25 @@ module Ameba::Rule it "returns false if source is not excluded from this rule" do rule = DummyRule.new - rule.excluded = %w(some_source.cr) + rule.excluded = %w[some_source.cr] rule.excluded?(Source.new "", "another_source.cr").should_not be_true end it "returns true if source is excluded from this rule" do rule = DummyRule.new - rule.excluded = %w(source.cr) + rule.excluded = %w[source.cr] rule.excluded?(Source.new "", "source.cr").should be_true end it "returns true if source matches the wildcard" do rule = DummyRule.new - rule.excluded = %w(**/*.cr) + rule.excluded = %w[**/*.cr] rule.excluded?(Source.new "", __FILE__).should be_true end it "returns false if source does not match the wildcard" do rule = DummyRule.new - rule.excluded = %w(*_spec.cr) + rule.excluded = %w[*_spec.cr] rule.excluded?(Source.new "", "source.cr").should be_false end end diff --git a/spec/ameba/cli/cmd_spec.cr b/spec/ameba/cli/cmd_spec.cr index c98d8f71..f02707ea 100644 --- a/spec/ameba/cli/cmd_spec.cr +++ b/spec/ameba/cli/cmd_spec.cr @@ -5,27 +5,27 @@ module Ameba::Cli describe "Cmd" do describe ".run" do it "runs ameba" do - r = Cli.run %w(-f silent -c spec/fixtures/config.yml spec/fixtures/source.cr) + r = Cli.run %w[-f silent -c spec/fixtures/config.yml spec/fixtures/source.cr] r.should be_nil end end describe ".parse_args" do - %w(-s --silent).each do |flag| + %w[-s --silent].each do |flag| it "accepts #{flag} flag" do c = Cli.parse_args [flag] c.formatter.should eq :silent end end - %w(-c --config).each do |flag| + %w[-c --config].each do |flag| it "accepts #{flag} flag" do c = Cli.parse_args [flag, "config.yml"] c.config.should eq Path["config.yml"] end end - %w(-f --format).each do |flag| + %w[-f --format].each do |flag| it "accepts #{flag} flag" do c = Cli.parse_args [flag, "my-formatter"] c.formatter.should eq "my-formatter" @@ -34,68 +34,68 @@ module Ameba::Cli it "accepts --only flag" do c = Cli.parse_args ["--only", "RULE1,RULE2"] - c.only.should eq %w(RULE1 RULE2) + c.only.should eq %w[RULE1 RULE2] end it "accepts --except flag" do c = Cli.parse_args ["--except", "RULE1,RULE2"] - c.except.should eq %w(RULE1 RULE2) + c.except.should eq %w[RULE1 RULE2] end it "defaults rules? flag to false" do - c = Cli.parse_args %w(spec/fixtures/source.cr) + c = Cli.parse_args %w[spec/fixtures/source.cr] c.rules?.should be_false end it "defaults skip_reading_config? flag to false" do - c = Cli.parse_args %w(spec/fixtures/source.cr) + c = Cli.parse_args %w[spec/fixtures/source.cr] c.skip_reading_config?.should be_false end it "accepts --rules flag" do - c = Cli.parse_args %w(--rules) + c = Cli.parse_args %w[--rules] c.rules?.should eq true end it "defaults all? flag to false" do - c = Cli.parse_args %w(spec/fixtures/source.cr) + c = Cli.parse_args %w[spec/fixtures/source.cr] c.all?.should be_false end it "accepts --all flag" do - c = Cli.parse_args %w(--all) + c = Cli.parse_args %w[--all] c.all?.should eq true end it "accepts --gen-config flag" do - c = Cli.parse_args %w(--gen-config) + c = Cli.parse_args %w[--gen-config] c.formatter.should eq :todo end it "accepts --no-color flag" do - c = Cli.parse_args %w(--no-color) + c = Cli.parse_args %w[--no-color] c.colors?.should be_false end it "accepts --without-affected-code flag" do - c = Cli.parse_args %w(--without-affected-code) + c = Cli.parse_args %w[--without-affected-code] c.without_affected_code?.should be_true end it "doesn't disable colors by default" do - c = Cli.parse_args %w(--all) + c = Cli.parse_args %w[--all] c.colors?.should be_true end it "ignores --config if --gen-config flag passed" do - c = Cli.parse_args %w(--gen-config --config my_config.yml) + c = Cli.parse_args %w[--gen-config --config my_config.yml] c.formatter.should eq :todo c.skip_reading_config?.should be_true end describe "-e/--explain" do it "configures file/line/column" do - c = Cli.parse_args %w(--explain spec/fixtures/source.cr:3:5) + c = Cli.parse_args %w[--explain spec/fixtures/source.cr:3:5] location_to_explain = c.location_to_explain.should_not be_nil location_to_explain[:file].should eq "spec/fixtures/source.cr" @@ -105,59 +105,59 @@ module Ameba::Cli it "raises an error if location is not valid" do expect_raises(Exception, "location should have PATH:line:column") do - Cli.parse_args %w(--explain spec/fixtures/source.cr:3) + Cli.parse_args %w[--explain spec/fixtures/source.cr:3] end end it "raises an error if line number is not valid" do expect_raises(Exception, "location should have PATH:line:column") do - Cli.parse_args %w(--explain spec/fixtures/source.cr:a:3) + Cli.parse_args %w[--explain spec/fixtures/source.cr:a:3] end end it "raises an error if column number is not valid" do expect_raises(Exception, "location should have PATH:line:column") do - Cli.parse_args %w(--explain spec/fixtures/source.cr:3:&) + Cli.parse_args %w[--explain spec/fixtures/source.cr:3:&] end end it "raises an error if line/column are missing" do expect_raises(Exception, "location should have PATH:line:column") do - Cli.parse_args %w(--explain spec/fixtures/source.cr) + Cli.parse_args %w[--explain spec/fixtures/source.cr] end end end context "--fail-level" do it "configures fail level Convention" do - c = Cli.parse_args %w(--fail-level convention) + c = Cli.parse_args %w[--fail-level convention] c.fail_level.should eq Severity::Convention end it "configures fail level Warning" do - c = Cli.parse_args %w(--fail-level Warning) + c = Cli.parse_args %w[--fail-level Warning] c.fail_level.should eq Severity::Warning end it "configures fail level Error" do - c = Cli.parse_args %w(--fail-level error) + c = Cli.parse_args %w[--fail-level error] c.fail_level.should eq Severity::Error end it "raises if fail level is incorrect" do expect_raises(Exception, "Incorrect severity name JohnDoe") do - Cli.parse_args %w(--fail-level JohnDoe) + Cli.parse_args %w[--fail-level JohnDoe] end end end it "accepts unknown args as globs" do - c = Cli.parse_args %w(source1.cr source2.cr) - c.globs.should eq %w(source1.cr source2.cr) + c = Cli.parse_args %w[source1.cr source2.cr] + c.globs.should eq %w[source1.cr source2.cr] end it "accepts one unknown arg as explain location if it has correct format" do - c = Cli.parse_args %w(source.cr:3:22) + c = Cli.parse_args %w[source.cr:3:22] location_to_explain = c.location_to_explain.should_not be_nil location_to_explain[:file].should eq "source.cr" diff --git a/spec/ameba/config_spec.cr b/spec/ameba/config_spec.cr index 036c458f..bfc9994c 100644 --- a/spec/ameba/config_spec.cr +++ b/spec/ameba/config_spec.cr @@ -32,7 +32,7 @@ module Ameba Globs: src/*.cr CONFIG config = Config.new(yml) - config.globs.should eq %w(src/*.cr) + config.globs.should eq %w[src/*.cr] end it "initializes globs as array" do @@ -43,7 +43,7 @@ module Ameba - "!spec" CONFIG config = Config.new(yml) - config.globs.should eq %w(src/*.cr !spec) + config.globs.should eq %w[src/*.cr !spec] end it "raises if Globs has a wrong type" do @@ -62,7 +62,7 @@ module Ameba Excluded: spec CONFIG config = Config.new(yml) - config.excluded.should eq %w(spec) + config.excluded.should eq %w[spec] end it "initializes excluded as array" do @@ -73,7 +73,7 @@ module Ameba - lib/*.cr CONFIG config = Config.new(yml) - config.excluded.should eq %w(spec lib/*.cr) + config.excluded.should eq %w[spec lib/*.cr] end it "raises if Excluded has a wrong type" do @@ -145,12 +145,12 @@ module Ameba end it "returns a list of sources matching globs" do - config.globs = %w(**/config_spec.cr) + config.globs = %w[**/config_spec.cr] config.sources.size.should eq(1) end it "returns a list of sources excluding 'Excluded'" do - config.excluded = %w(**/config_spec.cr) + config.excluded = %w[**/config_spec.cr] config.sources.any?(&.fullpath.==(__FILE__)).should be_false end end @@ -192,7 +192,7 @@ module Ameba it "updates excluded property" do name = DummyRule.rule_name - excluded = %w(spec/source.cr) + excluded = %w[spec/source.cr] config.update_rule name, excluded: excluded rule = config.rules.find!(&.name.== name) rule.excluded.should eq excluded @@ -211,7 +211,7 @@ module Ameba it "updates multiple rules by excluded property" do name = DummyRule.rule_name - excluded = %w(spec/source.cr) + excluded = %w[spec/source.cr] config.update_rules [name], excluded: excluded rule = config.rules.find!(&.name.== name) rule.excluded.should eq excluded @@ -226,7 +226,7 @@ module Ameba it "updates a group by excluded property" do name = DummyRule.group_name - excluded = %w(spec/source.cr) + excluded = %w[spec/source.cr] config.update_rules [name], excluded: excluded rule = config.rules.find!(&.name.== DummyRule.rule_name) rule.excluded.should eq excluded diff --git a/spec/ameba/rule/lint/empty_expression_spec.cr b/spec/ameba/rule/lint/empty_expression_spec.cr index d45e4626..671f7ef6 100644 --- a/spec/ameba/rule/lint/empty_expression_spec.cr +++ b/spec/ameba/rule/lint/empty_expression_spec.cr @@ -4,16 +4,16 @@ module Ameba subject = Rule::Lint::EmptyExpression.new private def it_detects_empty_expression(code, *, file = __FILE__, line = __LINE__) - it %(detects empty expression "#{code}"), file, line do - s = Source.new code + it "detects empty expression #{code.inspect}", file, line do + source = Source.new code rule = Rule::Lint::EmptyExpression.new - rule.catch(s).should_not be_valid, file: file, line: line + rule.catch(source).should_not be_valid, file: file, line: line end end describe Rule::Lint::EmptyExpression do it "passes if there is no empty expression" do - s = Source.new <<-CRYSTAL + expect_no_issues subject, <<-CRYSTAL def method() end @@ -31,7 +31,6 @@ module Ameba begin "" end [nil] << nil CRYSTAL - subject.catch(s).should be_valid end it_detects_empty_expression %(()) @@ -91,10 +90,10 @@ module Ameba ) it "does not report empty expression in macro" do - s = Source.new %q( + expect_no_issues subject, <<-CRYSTAL module MyModule macro conditional_error_for_inline_callbacks - \{% + \\{% raise "" %} end @@ -102,8 +101,7 @@ module Ameba macro before_save(x = nil) end end - ) - subject.catch(s).should be_valid + CRYSTAL end end end diff --git a/spec/ameba/rule/lint/percent_arrays_spec.cr b/spec/ameba/rule/lint/percent_arrays_spec.cr index 6f44367d..c279671a 100644 --- a/spec/ameba/rule/lint/percent_arrays_spec.cr +++ b/spec/ameba/rule/lint/percent_arrays_spec.cr @@ -6,41 +6,41 @@ module Ameba::Rule::Lint it "passes if percent arrays are written correctly" do s = Source.new %q( - %i(one two three) - %w(one two three) + %i[one two three] + %w[one two three] - %i(1 2 3) - %w(1 2 3) + %i[1 2 3] + %w[1 2 3] - %i() - %w() + %i[] + %w[] ) subject.catch(s).should be_valid end it "fails if string percent array has commas" do - s = Source.new %( %w(one, two) ) + s = Source.new %( %w[one, two] ) subject.catch(s).should_not be_valid end it "fails if string percent array has quotes" do - s = Source.new %( %w("one" "two") ) + s = Source.new %( %w["one" "two"] ) subject.catch(s).should_not be_valid end it "fails if symbols percent array has commas" do - s = Source.new %( %i(one, two) ) + s = Source.new %( %i[one, two] ) subject.catch(s).should_not be_valid end it "fails if symbols percent array has a colon" do - s = Source.new %( %i(:one :two) ) + s = Source.new %( %i[:one :two] ) subject.catch(s).should_not be_valid end it "reports rule, location and message for %i" do s = Source.new %( - %i(:one) + %i[:one] ), "source.cr" subject.catch(s).should_not be_valid @@ -54,7 +54,7 @@ module Ameba::Rule::Lint it "reports rule, location and message for %w" do s = Source.new %( - %w("one") + %w["one"] ), "source.cr" subject.catch(s).should_not be_valid @@ -71,14 +71,14 @@ module Ameba::Rule::Lint it "#string_array_unwanted_symbols" do rule = PercentArrays.new rule.string_array_unwanted_symbols = "," - s = Source.new %( %w("one") ) + s = Source.new %( %w["one"] ) rule.catch(s).should be_valid end it "#symbol_array_unwanted_symbols" do rule = PercentArrays.new rule.symbol_array_unwanted_symbols = "," - s = Source.new %( %i(:one) ) + s = Source.new %( %i[:one] ) rule.catch(s).should be_valid end end diff --git a/spec/ameba/rule/lint/typos_spec.cr b/spec/ameba/rule/lint/typos_spec.cr index 9c9ef249..544b81fe 100644 --- a/spec/ameba/rule/lint/typos_spec.cr +++ b/spec/ameba/rule/lint/typos_spec.cr @@ -19,12 +19,15 @@ module Ameba::Rule::Lint # ^^^^^^^^^ error: Typo found: arugments -> arguments def tpos # ^^^^ error: Typo found: tpos -> typos + :otput + # ^^^^^ error: Typo found: otput -> output end CRYSTAL expect_correction source, <<-CRYSTAL # method with no arguments def typos + :output end CRYSTAL end diff --git a/spec/ameba/rule/lint/useless_assign_spec.cr b/spec/ameba/rule/lint/useless_assign_spec.cr index 5f44edf0..d764a7da 100644 --- a/spec/ameba/rule/lint/useless_assign_spec.cr +++ b/spec/ameba/rule/lint/useless_assign_spec.cr @@ -977,7 +977,7 @@ module Ameba::Rule::Lint s = Source.new %( foo = 22 - {% for x in %w(foo) %} + {% for x in %w[foo] %} add({{ x.id }}) {% end %} ) @@ -988,7 +988,7 @@ module Ameba::Rule::Lint s = Source.new %( foo = 22 - {% for x in %w(bar) %} + {% for x in %w[bar] %} puts {{ "foo".id }} {% end %} ) diff --git a/spec/ameba/rule/naming/predicate_name_spec.cr b/spec/ameba/rule/naming/predicate_name_spec.cr index 8386b5cc..27e2851d 100644 --- a/spec/ameba/rule/naming/predicate_name_spec.cr +++ b/spec/ameba/rule/naming/predicate_name_spec.cr @@ -21,8 +21,18 @@ module Ameba::Rule::Naming it "fails if predicate name is wrong" do expect_issue subject, <<-CRYSTAL + class Image + def self.is_valid?(x) + # ^^^^^^^^^ error: Favour method name 'valid?' over 'is_valid?' + end + end + def is_valid?(x) - # ^^^^^^^^^^^^^^ error: Favour method name 'valid?' over 'is_valid?' + # ^^^^^^^^^ error: Favour method name 'valid?' over 'is_valid?' + end + + def is_valid(x) + # ^^^^^^^^ error: Favour method name 'valid?' over 'is_valid' end CRYSTAL end diff --git a/spec/ameba/rule/naming/type_names_spec.cr b/spec/ameba/rule/naming/type_names_spec.cr index aa96f649..555b21c8 100644 --- a/spec/ameba/rule/naming/type_names_spec.cr +++ b/spec/ameba/rule/naming/type_names_spec.cr @@ -7,8 +7,8 @@ module Ameba 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}, but it was %{name} + %{type} %{name}; end + _{type} # ^{name} error: Type name should be camelcased: #{expected}, but it was %{name} CRYSTAL end end @@ -46,7 +46,7 @@ module Ameba it "reports alias name" do expect_issue subject, <<-CRYSTAL alias Numeric_value = Int32 - # ^{} error: Type name should be camelcased: NumericValue, but it was Numeric_value + # ^^^^^^^^^^^^^ error: Type name should be camelcased: NumericValue, but it was Numeric_value CRYSTAL end end diff --git a/spec/ameba/rule/performance/any_after_filter_spec.cr b/spec/ameba/rule/performance/any_after_filter_spec.cr index f902ae0b..e7c122ea 100644 --- a/spec/ameba/rule/performance/any_after_filter_spec.cr +++ b/spec/ameba/rule/performance/any_after_filter_spec.cr @@ -48,7 +48,7 @@ module Ameba::Rule::Performance context "properties" do it "#filter_names" do rule = AnyAfterFilter.new - rule.filter_names = %w(select) + rule.filter_names = %w[select] expect_no_issues rule, <<-CRYSTAL [1, 2, 3].reject { |e| e > 2 }.any? 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 eaef1a8f..a72590ad 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 @@ -46,7 +46,7 @@ module Ameba::Rule::Performance context "properties" do it "#call_names" do rule = ChainedCallWithNoBang.new - rule.call_names = %w(uniq) + rule.call_names = %w[uniq] expect_no_issues rule, <<-CRYSTAL [1, 2, 3].select { |e| e > 2 }.reverse 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 7d0f320f..49aa46e7 100644 --- a/spec/ameba/rule/performance/first_last_after_filter_spec.cr +++ b/spec/ameba/rule/performance/first_last_after_filter_spec.cr @@ -64,7 +64,7 @@ module Ameba::Rule::Performance context "properties" do it "#filter_names" do rule = FirstLastAfterFilter.new - rule.filter_names = %w(reject) + rule.filter_names = %w[reject] expect_no_issues rule, <<-CRYSTAL [1, 2, 3].select { |e| e > 2 }.first diff --git a/spec/ameba/rule/performance/size_after_filter_spec.cr b/spec/ameba/rule/performance/size_after_filter_spec.cr index 1b081738..62d8d1ee 100644 --- a/spec/ameba/rule/performance/size_after_filter_spec.cr +++ b/spec/ameba/rule/performance/size_after_filter_spec.cr @@ -46,7 +46,7 @@ module Ameba::Rule::Performance context "properties" do it "#filter_names" do rule = SizeAfterFilter.new - rule.filter_names = %w(select) + rule.filter_names = %w[select] expect_no_issues rule, <<-CRYSTAL [1, 2, 3].reject(&.empty?).size diff --git a/spec/ameba/rule/style/is_a_filter_spec.cr b/spec/ameba/rule/style/is_a_filter_spec.cr index 234c2600..a1b34da4 100644 --- a/spec/ameba/rule/style/is_a_filter_spec.cr +++ b/spec/ameba/rule/style/is_a_filter_spec.cr @@ -44,7 +44,7 @@ module Ameba::Rule::Style context "properties" do it "#filter_names" do rule = IsAFilter.new - rule.filter_names = %w(select) + rule.filter_names = %w[select] expect_no_issues rule, <<-CRYSTAL [1, 2, nil].reject(&.nil?) diff --git a/spec/ameba/rule/style/large_numbers_spec.cr b/spec/ameba/rule/style/large_numbers_spec.cr index 37cdf231..68833d82 100644 --- a/spec/ameba/rule/style/large_numbers_spec.cr +++ b/spec/ameba/rule/style/large_numbers_spec.cr @@ -123,7 +123,7 @@ module Ameba it "#int_min_digits" do rule = Rule::Style::LargeNumbers.new rule.int_min_digits = 10 - expect_no_issues rule, %q(1200000) + expect_no_issues rule, "1200000" end end end diff --git a/spec/ameba/rule/style/parentheses_around_condition_spec.cr b/spec/ameba/rule/style/parentheses_around_condition_spec.cr index a8a174ad..d4adb811 100644 --- a/spec/ameba/rule/style/parentheses_around_condition_spec.cr +++ b/spec/ameba/rule/style/parentheses_around_condition_spec.cr @@ -4,7 +4,7 @@ module Ameba::Rule::Style subject = ParenthesesAroundCondition.new describe ParenthesesAroundCondition do - {% for keyword in %w(if unless while until) %} + {% for keyword in %w[if unless while until] %} context "{{ keyword.id }}" do it "reports if redundant parentheses are found" do source = expect_issue subject, <<-CRYSTAL, keyword: {{ keyword }} diff --git a/spec/ameba/tokenizer_spec.cr b/spec/ameba/tokenizer_spec.cr index b014a30d..1c777227 100644 --- a/spec/ameba/tokenizer_spec.cr +++ b/spec/ameba/tokenizer_spec.cr @@ -22,23 +22,23 @@ module Ameba DELIMITER_START STRING INTERPOLATION_START NUMBER } DELIMITER_END EOF ) - it_tokenizes %(%w(1 2)), - %w(STRING_ARRAY_START STRING STRING STRING_ARRAY_END EOF) + it_tokenizes %(%w[1 2]), + %w[STRING_ARRAY_START STRING STRING STRING_ARRAY_END EOF] - it_tokenizes %(%i(one two)), - %w(SYMBOL_ARRAY_START STRING STRING STRING_ARRAY_END EOF) + it_tokenizes %(%i[one two]), + %w[SYMBOL_ARRAY_START STRING STRING STRING_ARRAY_END EOF] it_tokenizes %( - class A - def method - puts "hello" - end + class A + def method + puts "hello" end - ), %w( + end + ), %w[ NEWLINE SPACE IDENT SPACE CONST NEWLINE SPACE IDENT SPACE IDENT NEWLINE SPACE IDENT SPACE DELIMITER_START STRING DELIMITER_END NEWLINE SPACE IDENT NEWLINE SPACE IDENT NEWLINE SPACE EOF - ) + ] end end end diff --git a/src/ameba/ast/variabling/assignment.cr b/src/ameba/ast/variabling/assignment.cr index aee0489d..3ab1ba7f 100644 --- a/src/ameba/ast/variabling/assignment.cr +++ b/src/ameba/ast/variabling/assignment.cr @@ -75,34 +75,5 @@ module Ameba::AST node end end - - # TODO: Remove in a next release. BC for crystal <= 1.9. - # refs https://github.com/crystal-ameba/ameba/pull/407 - # - # Indicates whether the node is a transformed assignment by the compiler. - # i.e. - # - # ``` - # collection.each do |(a, b)| - # puts b - # end - # ``` - # - # is transformed to: - # - # ``` - # collection.each do |__arg0| - # a = __arg0[0] - # b = __arg0[1] - # puts(b) - # end - # ``` - def transformed? - return false unless (assign = node).is_a?(Crystal::Assign) - return false unless (value = assign.value).is_a?(Crystal::Call) - return false unless (obj = value.obj).is_a?(Crystal::Var) - - obj.name.starts_with? "__arg" - end end end diff --git a/src/ameba/ast/visitors/counting_visitor.cr b/src/ameba/ast/visitors/counting_visitor.cr index 7bb0bb7c..347e5ccd 100644 --- a/src/ameba/ast/visitors/counting_visitor.cr +++ b/src/ameba/ast/visitors/counting_visitor.cr @@ -24,7 +24,7 @@ module Ameba::AST # 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) %} + {% for node in %i[if while until rescue or and] %} # :nodoc: def visit(node : Crystal::{{ node.id.capitalize }}) @complexity += 1 unless macro_condition? diff --git a/src/ameba/config.cr b/src/ameba/config.cr index b6e1d3a5..428b89ec 100644 --- a/src/ameba/config.cr +++ b/src/ameba/config.cr @@ -200,13 +200,13 @@ class Ameba::Config # # ``` # config = Ameba::Config.load - # config.update_rules %w(Rule1 Rule2), enabled: true + # config.update_rules %w[Rule1 Rule2], enabled: true # ``` # # also it allows to update groups of rules: # # ``` - # config.update_rules %w(Group1 Group2), enabled: true + # config.update_rules %w[Group1 Group2], enabled: true # ``` def update_rules(names, enabled = true, excluded = nil) names.try &.each do |name| diff --git a/src/ameba/rule/base.cr b/src/ameba/rule/base.cr index 7d656d8e..f28c83d0 100644 --- a/src/ameba/rule/base.cr +++ b/src/ameba/rule/base.cr @@ -114,7 +114,7 @@ module Ameba::Rule # Adds an issue to the *source* macro issue_for(*args, **kwargs, &block) - source.add_issue(self, {{ *args }}, {{ **kwargs }}) {{ block }} + source.add_issue(self, {{ args.splat }}, {{ kwargs.double_splat }}) {{ block }} end protected def self.rule_name diff --git a/src/ameba/rule/lint/comparison_to_boolean.cr b/src/ameba/rule/lint/comparison_to_boolean.cr index cc9eda9e..abd4efc7 100644 --- a/src/ameba/rule/lint/comparison_to_boolean.cr +++ b/src/ameba/rule/lint/comparison_to_boolean.cr @@ -28,7 +28,7 @@ module Ameba::Rule::Lint end MSG = "Comparison to a boolean is pointless" - OP_NAMES = %w(== != ===) + OP_NAMES = %w[== != ===] def test(source, node : Crystal::Call) return unless node.name.in?(OP_NAMES) diff --git a/src/ameba/rule/lint/debug_calls.cr b/src/ameba/rule/lint/debug_calls.cr index fc4e3e2f..b2958295 100644 --- a/src/ameba/rule/lint/debug_calls.cr +++ b/src/ameba/rule/lint/debug_calls.cr @@ -18,7 +18,7 @@ module Ameba::Rule::Lint class DebugCalls < Base properties do description "Disallows debug-related calls" - method_names %w(p p! pp pp!) + method_names %w[p p! pp pp!] end MSG = "Possibly forgotten debug-related `%s` call detected" diff --git a/src/ameba/rule/lint/empty_expression.cr b/src/ameba/rule/lint/empty_expression.cr index 9ceb2147..bac570c9 100644 --- a/src/ameba/rule/lint/empty_expression.cr +++ b/src/ameba/rule/lint/empty_expression.cr @@ -28,8 +28,6 @@ module Ameba::Rule::Lint # Enabled: true # ``` class EmptyExpression < Base - include AST::Util - properties do description "Disallows empty expressions" end diff --git a/src/ameba/rule/lint/literals_comparison.cr b/src/ameba/rule/lint/literals_comparison.cr index 24b7b805..9f9a7fee 100644 --- a/src/ameba/rule/lint/literals_comparison.cr +++ b/src/ameba/rule/lint/literals_comparison.cr @@ -23,7 +23,7 @@ module Ameba::Rule::Lint description "Identifies comparisons between literals" end - OP_NAMES = %w(=== == !=) + OP_NAMES = %w[=== == !=] MSG = "Comparison always evaluates to %s" MSG_LIKELY = "Comparison most likely evaluates to %s" diff --git a/src/ameba/rule/lint/not_nil_after_no_bang.cr b/src/ameba/rule/lint/not_nil_after_no_bang.cr index ff50454d..1f9f3394 100644 --- a/src/ameba/rule/lint/not_nil_after_no_bang.cr +++ b/src/ameba/rule/lint/not_nil_after_no_bang.cr @@ -27,11 +27,11 @@ module Ameba::Rule::Lint description "Identifies usage of `index/rindex/find/match` calls followed by `not_nil!`" end - BLOCK_CALL_NAMES = %w(index rindex find) - CALL_NAMES = %w(index rindex match) - MSG = "Use `%s! {...}` instead of `%s {...}.not_nil!`" + BLOCK_CALL_NAMES = %w[index rindex find] + CALL_NAMES = %w[index rindex match] + def test(source) AST::NodeVisitor.new self, source, skip: :macro end diff --git a/src/ameba/rule/lint/percent_array.cr b/src/ameba/rule/lint/percent_array.cr index 1bccd987..987d87d8 100644 --- a/src/ameba/rule/lint/percent_array.cr +++ b/src/ameba/rule/lint/percent_array.cr @@ -4,15 +4,15 @@ module Ameba::Rule::Lint # For example, this is usually written by mistake: # # ``` - # %i(:one, :two) - # %w("one", "two") + # %i[:one, :two] + # %w["one", "two"] # ``` # # And the expected example is: # # ``` - # %i(one two) - # %w(one two) + # %i[one two] + # %w[one two] # ``` # # YAML configuration example: @@ -42,7 +42,7 @@ module Ameba::Rule::Lint start_token = token.dup when .string? if (_start = start_token) && !issue - issue = array_entry_invalid?(token.value, _start.raw) + issue = array_entry_invalid?(token.value.to_s, _start.raw) end when .string_array_end? if (_start = start_token) && (_issue = issue) @@ -63,7 +63,7 @@ module Ameba::Rule::Lint end private def check_array_entry(entry, symbols, literal) - MSG % {symbols, literal} if entry =~ /[#{symbols}]/ + MSG % {symbols, literal} if entry.matches?(/[#{Regex.escape(symbols)}]/) end end end diff --git a/src/ameba/rule/lint/spec_focus.cr b/src/ameba/rule/lint/spec_focus.cr index 5cdb9e1c..b165145a 100644 --- a/src/ameba/rule/lint/spec_focus.cr +++ b/src/ameba/rule/lint/spec_focus.cr @@ -49,8 +49,9 @@ module Ameba::Rule::Lint description "Reports focused spec items" end - MSG = "Focused spec item detected" - SPEC_ITEM_NAMES = %w(describe context it pending) + MSG = "Focused spec item detected" + + SPEC_ITEM_NAMES = %w[describe context it pending] def test(source) return unless source.spec? diff --git a/src/ameba/rule/lint/typos.cr b/src/ameba/rule/lint/typos.cr index 12925022..09077240 100644 --- a/src/ameba/rule/lint/typos.cr +++ b/src/ameba/rule/lint/typos.cr @@ -15,7 +15,7 @@ module Ameba::Rule::Lint class Typos < Base properties do description "Reports typos found in source files" - bin_path nil.as(String?) + bin_path : String? = nil fail_on_error false end diff --git a/src/ameba/rule/lint/unreachable_code.cr b/src/ameba/rule/lint/unreachable_code.cr index f289c53e..f3c28439 100644 --- a/src/ameba/rule/lint/unreachable_code.cr +++ b/src/ameba/rule/lint/unreachable_code.cr @@ -42,8 +42,6 @@ module Ameba::Rule::Lint # Enabled: true # ``` class UnreachableCode < Base - include AST::Util - properties do description "Reports unreachable code" end diff --git a/src/ameba/rule/lint/unused_block_argument.cr b/src/ameba/rule/lint/unused_block_argument.cr index a3497b02..65a7255d 100644 --- a/src/ameba/rule/lint/unused_block_argument.cr +++ b/src/ameba/rule/lint/unused_block_argument.cr @@ -31,8 +31,6 @@ module Ameba::Rule::Lint # Enabled: true # ``` class UnusedBlockArgument < Base - include AST::Util - properties do description "Disallows unused block arguments" end @@ -58,7 +56,8 @@ module Ameba::Rule::Lint location = block_arg.node.location end_location = location.try &.adjust(column_number: block_arg.name.size - 1) - if scope.yields? + case + when scope.yields? if location && end_location issue_for location, end_location, MSG_YIELDED do |corrector| corrector.remove(location, end_location) @@ -66,8 +65,7 @@ module Ameba::Rule::Lint else issue_for block_arg.node, MSG_YIELDED end - else - return if block_arg.ignored? + when !block_arg.ignored? if location && end_location issue_for location, end_location, MSG_UNUSED % block_arg.name do |corrector| corrector.insert_before(location, '_') diff --git a/src/ameba/rule/lint/useless_assign.cr b/src/ameba/rule/lint/useless_assign.cr index f0319329..85ac424f 100644 --- a/src/ameba/rule/lint/useless_assign.cr +++ b/src/ameba/rule/lint/useless_assign.cr @@ -42,7 +42,7 @@ module Ameba::Rule::Lint next if scope.assigns_type_dec?(var.name) var.assignments.each do |assign| - next if assign.referenced? || assign.transformed? + next if assign.referenced? issue_for assign.target_node, MSG % var.name end end diff --git a/src/ameba/rule/naming/constant_names.cr b/src/ameba/rule/naming/constant_names.cr index 76a09aee..88f815fb 100644 --- a/src/ameba/rule/naming/constant_names.cr +++ b/src/ameba/rule/naming/constant_names.cr @@ -30,7 +30,8 @@ module Ameba::Rule::Naming def test(source, node : Crystal::Assign) return unless (target = node.target).is_a?(Crystal::Path) - name = target.names.first + + name = target.to_s expected = name.upcase return if name.in?(expected, name.camelcase) diff --git a/src/ameba/rule/naming/method_names.cr b/src/ameba/rule/naming/method_names.cr index d938caa1..d434d9a7 100644 --- a/src/ameba/rule/naming/method_names.cr +++ b/src/ameba/rule/naming/method_names.cr @@ -45,9 +45,11 @@ module Ameba::Rule::Naming MSG = "Method name should be underscore-cased: %s, not %s" def test(source, node : Crystal::Def) - return if (expected = node.name.underscore) == node.name + name = node.name.to_s - issue_for node, MSG % {expected, node.name}, prefer_name_location: true + return if (expected = name.underscore) == name + + issue_for node, MSG % {expected, name}, prefer_name_location: true end end end diff --git a/src/ameba/rule/naming/predicate_name.cr b/src/ameba/rule/naming/predicate_name.cr index f37a8343..b3935f2b 100644 --- a/src/ameba/rule/naming/predicate_name.cr +++ b/src/ameba/rule/naming/predicate_name.cr @@ -31,10 +31,10 @@ module Ameba::Rule::Naming MSG = "Favour method name '%s?' over '%s'" def test(source, node : Crystal::Def) - return unless node.name =~ /^is_([a-z]\w*)\?$/ + return unless node.name =~ /^is_([a-z]\w*)\??$/ alternative = $1 - issue_for node, MSG % {alternative, node.name} + issue_for node, MSG % {alternative, node.name}, prefer_name_location: true end end end diff --git a/src/ameba/rule/naming/query_bool_methods.cr b/src/ameba/rule/naming/query_bool_methods.cr index 1cb9f59c..a0ecaebb 100644 --- a/src/ameba/rule/naming/query_bool_methods.cr +++ b/src/ameba/rule/naming/query_bool_methods.cr @@ -48,9 +48,7 @@ module Ameba::Rule::Naming .select!(&.name.in?(CALL_NAMES)) end - return unless calls - - calls.each do |exp| + calls.try &.each do |exp| exp.args.each do |arg| name_node, is_bool = case arg diff --git a/src/ameba/rule/naming/type_names.cr b/src/ameba/rule/naming/type_names.cr index 59ce05a7..fb472471 100644 --- a/src/ameba/rule/naming/type_names.cr +++ b/src/ameba/rule/naming/type_names.cr @@ -60,10 +60,10 @@ module Ameba::Rule::Naming def test(source, node : Crystal::Alias | Crystal::ClassDef | Crystal::ModuleDef | Crystal::LibDef | Crystal::EnumDef) name = node.name.to_s - expected = name.camelcase - return if name == expected - issue_for node, MSG % {expected, name} + return if (expected = name.camelcase) == name + + issue_for node.name, MSG % {expected, name} end end end diff --git a/src/ameba/rule/naming/variable_names.cr b/src/ameba/rule/naming/variable_names.cr index 061fc028..fe28b3eb 100644 --- a/src/ameba/rule/naming/variable_names.cr +++ b/src/ameba/rule/naming/variable_names.cr @@ -35,8 +35,8 @@ module Ameba::Rule::Naming def test(source, node : Crystal::Var | Crystal::InstanceVar | Crystal::ClassVar) name = node.name.to_s - expected = name.underscore - return if name == expected + + return if (expected = name.underscore) == name issue_for node, MSG % {expected, name} end diff --git a/src/ameba/rule/performance/any_after_filter.cr b/src/ameba/rule/performance/any_after_filter.cr index e4f7bcaf..c51f6b28 100644 --- a/src/ameba/rule/performance/any_after_filter.cr +++ b/src/ameba/rule/performance/any_after_filter.cr @@ -31,7 +31,7 @@ module Ameba::Rule::Performance properties do description "Identifies usage of `any?` calls that follow filters" - filter_names %w(select reject) + filter_names %w[select reject] end MSG = "Use `any? {...}` instead of `%s {...}.any?`" diff --git a/src/ameba/rule/performance/chained_call_with_no_bang.cr b/src/ameba/rule/performance/chained_call_with_no_bang.cr index a6ed0d54..a5d2d0e7 100644 --- a/src/ameba/rule/performance/chained_call_with_no_bang.cr +++ b/src/ameba/rule/performance/chained_call_with_no_bang.cr @@ -45,18 +45,18 @@ module Ameba::Rule::Performance # All of those have bang method variants returning `self` # and are not modifying the receiver type (like `compact` does), # thus are safe to switch to the bang variant. - call_names %w(uniq sort sort_by shuffle reverse) + call_names %w[uniq sort sort_by shuffle reverse] end - # All these methods are allocating a new object - ALLOCATING_METHOD_NAMES = %w( + MSG = "Use bang method variant `%s!` after chained `%s` call" + + # All these methods allocate a new object + ALLOCATING_METHOD_NAMES = %w[ keys values values_at map map_with_index flat_map compact_map flatten compact select reject sample group_by chunks tally merge combinations repeated_combinations permutations repeated_permutations transpose invert chars captures named_captures clone - ) - - MSG = "Use bang method variant `%s!` after chained `%s` call" + ] def test(source) AST::NodeVisitor.new self, source, skip: :macro diff --git a/src/ameba/rule/performance/first_last_after_filter.cr b/src/ameba/rule/performance/first_last_after_filter.cr index 68836a02..4290ba4c 100644 --- a/src/ameba/rule/performance/first_last_after_filter.cr +++ b/src/ameba/rule/performance/first_last_after_filter.cr @@ -30,13 +30,14 @@ module Ameba::Rule::Performance properties do description "Identifies usage of `first/last/first?/last?` calls that follow filters" - filter_names %w(select) + filter_names %w[select] end - CALL_NAMES = %w(first last first? last?) MSG = "Use `find {...}` instead of `%s {...}.%s`" MSG_REVERSE = "Use `reverse_each.find {...}` instead of `%s {...}.%s`" + CALL_NAMES = %w[first last first? last?] + def test(source) AST::NodeVisitor.new self, source, skip: :macro end diff --git a/src/ameba/rule/performance/map_instead_of_block.cr b/src/ameba/rule/performance/map_instead_of_block.cr index 5831710b..cb4f6fd6 100644 --- a/src/ameba/rule/performance/map_instead_of_block.cr +++ b/src/ameba/rule/performance/map_instead_of_block.cr @@ -29,9 +29,9 @@ module Ameba::Rule::Performance description "Identifies usage of `sum/product` calls that follow `map`" end - CALL_NAMES = %w(sum product) - MAP_NAME = "map" - MSG = "Use `%s {...}` instead of `map {...}.%s`" + MSG = "Use `%s {...}` instead of `map {...}.%s`" + + CALL_NAMES = %w[sum product] def test(source) AST::NodeVisitor.new self, source, skip: :macro @@ -40,7 +40,7 @@ module Ameba::Rule::Performance def test(source, node : Crystal::Call) return unless node.name.in?(CALL_NAMES) && (obj = node.obj) return unless obj.is_a?(Crystal::Call) && obj.block - return unless obj.name == MAP_NAME + return unless obj.name == "map" issue_for name_location(obj), name_end_location(node), MSG % {node.name, node.name} diff --git a/src/ameba/rule/performance/size_after_filter.cr b/src/ameba/rule/performance/size_after_filter.cr index ea58112f..254576de 100644 --- a/src/ameba/rule/performance/size_after_filter.cr +++ b/src/ameba/rule/performance/size_after_filter.cr @@ -37,7 +37,7 @@ module Ameba::Rule::Performance properties do description "Identifies usage of `size` calls that follow filter" - filter_names %w(select reject) + filter_names %w[select reject] end MSG = "Use `count {...}` instead of `%s {...}.size`." diff --git a/src/ameba/rule/style/is_a_filter.cr b/src/ameba/rule/style/is_a_filter.cr index b2847fce..1a252fc0 100644 --- a/src/ameba/rule/style/is_a_filter.cr +++ b/src/ameba/rule/style/is_a_filter.cr @@ -43,12 +43,13 @@ module Ameba::Rule::Style properties do description "Identifies usage of `is_a?/nil?` calls within filters" - filter_names %w(select reject any? all? none? one?) + filter_names %w[select reject any? all? none? one?] end MSG = "Use `%s` instead of `%s`" - NEW = "%s(%s)" + OLD = "%s {...}" + NEW = "%s(%s)" def test(source) AST::NodeVisitor.new self, source, skip: :macro diff --git a/src/ameba/rule/style/verbose_block.cr b/src/ameba/rule/style/verbose_block.cr index aec0ea38..aaa66d20 100644 --- a/src/ameba/rule/style/verbose_block.cr +++ b/src/ameba/rule/style/verbose_block.cr @@ -227,9 +227,6 @@ module Ameba::Rule::Style arg = block.args.first - # we skip auto-generated blocks - `(1..3).any?(&.odd?)` - return if arg.name.starts_with?("__arg") - # we filter out the blocks that are of call type - `i.to_i64.odd?` return unless (body = block.body).is_a?(Crystal::Call) diff --git a/src/ameba/runner.cr b/src/ameba/runner.cr index dc60433c..5a526fac 100644 --- a/src/ameba/runner.cr +++ b/src/ameba/runner.cr @@ -67,7 +67,7 @@ module Ameba @unneeded_disable_directive_rule = config.rules - .find &.name.==(Rule::Lint::UnneededDisableDirective.rule_name) + .find &.class.==(Rule::Lint::UnneededDisableDirective) end protected def initialize(@rules, @sources, @formatter, @severity, @autocorrect = false) diff --git a/src/ameba/source.cr b/src/ameba/source.cr index 50d3a658..29d9d199 100644 --- a/src/ameba/source.cr +++ b/src/ameba/source.cr @@ -74,7 +74,7 @@ module Ameba # Returns `true` if *filepath* matches the source's path, `false` otherwise. def matches_path?(filepath) - path.in?(filepath, File.expand_path(filepath)) + fullpath == File.expand_path(filepath) end # Converts an AST location to a string position. diff --git a/src/ameba/source/rewriter.cr b/src/ameba/source/rewriter.cr index 1deda8ec..ec71bd13 100644 --- a/src/ameba/source/rewriter.cr +++ b/src/ameba/source/rewriter.cr @@ -72,12 +72,15 @@ class Ameba::Source # Replaces the code of the given range with *content*. def replace(begin_pos, end_pos, content) - combine(begin_pos, end_pos, replacement: content.to_s) + combine begin_pos, end_pos, + replacement: content.to_s end # Inserts the given strings before and after the given range. def wrap(begin_pos, end_pos, insert_before, insert_after) - combine(begin_pos, end_pos, insert_before: insert_before.to_s, insert_after: insert_after.to_s) + combine begin_pos, end_pos, + insert_before: insert_before.to_s, + insert_after: insert_after.to_s end # Shortcut for `replace(begin_pos, end_pos, "")`