Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package rubygem-rubocop for openSUSE:Factory checked in at 2023-10-12 23:41:38 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/rubygem-rubocop (Old) and /work/SRC/openSUSE:Factory/.rubygem-rubocop.new.1807 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "rubygem-rubocop" Thu Oct 12 23:41:38 2023 rev:47 rq:1117131 version:1.57.0 Changes: -------- --- /work/SRC/openSUSE:Factory/rubygem-rubocop/rubygem-rubocop.changes 2023-10-10 21:00:56.727486209 +0200 +++ /work/SRC/openSUSE:Factory/.rubygem-rubocop.new.1807/rubygem-rubocop.changes 2023-10-12 23:43:00.566852924 +0200 @@ -1,0 +2,54 @@ +Wed Oct 11 19:32:07 UTC 2023 - Mykola Krachkovsky <w01dn...@gmail.com> + +- updated to version 1.57.0 + + ## 1.57.0 (2023-10-11) + + ### New features + + * [#12227](https://github.com/rubocop/rubocop/pull/12227): Add new `Style/SingleLineDoEndBlock` cop. ([@koic][]) + * [#12246](https://github.com/rubocop/rubocop/pull/12246): Make `Lint/RedundantSafeNavigation` aware of constant receiver. ([@koic][]) + * [#12257](https://github.com/rubocop/rubocop/issues/12257): Make `Style/RedundantDoubleSplatHashBraces` aware of `merge` methods. ([@koic][]) + + ### Bug fixes + + * [#12244](https://github.com/rubocop/rubocop/issues/12244): Fix a false negative for `Lint/Debugger` when using debugger method inside block. ([@koic][]) + * [#12231](https://github.com/rubocop/rubocop/issues/12231): Fix a false negative for `Metrics/ModuleLength` when defining a singleton class in a module. ([@koic][]) + * [#12249](https://github.com/rubocop/rubocop/issues/12249): Fix a false positive `Style/IdenticalConditionalBranches` when `if`..`else` with identical leading lines and assign to condition value. ([@koic][]) + * [#12253](https://github.com/rubocop/rubocop/pull/12253): Fix `Lint/LiteralInInterpolation` to accept an empty string literal interpolated in words literal. ([@knu][]) + * [#12198](https://github.com/rubocop/rubocop/issues/12198): Fix an error for flip-flop with beginless or endless ranges. ([@koic][]) + * [#12259](https://github.com/rubocop/rubocop/issues/12259): Fix an error for `Lint/MixedCaseRange` when using nested character class in regexp. ([@koic][]) + * [#12237](https://github.com/rubocop/rubocop/issues/12237): Fix an error for `Style/NestedTernaryOperator` when a ternary operator has a nested ternary operator within an `if`. ([@koic][]) + * [#12228](https://github.com/rubocop/rubocop/pull/12228): Fix false negatives for `Style/MultilineBlockChain` when using multiline block chain with safe navigation operator. ([@koic][]) + * [#12247](https://github.com/rubocop/rubocop/pull/12247): Fix false negatives for `Style/RedundantParentheses` when using logical or comparison expressions with redundant parentheses. ([@koic][]) + * [#12226](https://github.com/rubocop/rubocop/issues/12226): Fix false positives for `Layout/MultilineMethodCallIndentation` when aligning methods in multiline block chain. ([@koic][]) + * [#12076](https://github.com/rubocop/rubocop/issues/12076): Fixed an issue where the top-level cache folder was named differently during two consecutive rubocop runs. ([@K-S-A][]) + + ### Changes + + * [#12235](https://github.com/rubocop/rubocop/pull/12235): Enable auto parallel inspection when config file is specified. ([@aboutNisblee][]) + * [#12234](https://github.com/rubocop/rubocop/pull/12234): Enhance `Style/FormatString`'s autocorrection when using known conversion methods whose return value is not an array. ([@koic][]) + * [#12128](https://github.com/rubocop/rubocop/issues/12128): Make `Style/GuardClause` aware of `define_method`. ([@koic][]) + * [#12126](https://github.com/rubocop/rubocop/pull/12126): Make `Style/RedundantFilterChain` aware of `select.present?` when `ActiveSupportExtensionsEnabled` config is `true`. ([@koic][]) + * [#12250](https://github.com/rubocop/rubocop/pull/12250): Mark `Lint/RedundantRequireStatement` as unsafe autocorrect. ([@koic][]) + * [#12097](https://github.com/rubocop/rubocop/issues/12097): Mark unsafe autocorrect for `Style/ClassEqualityComparison`. ([@koic][]) + * [#12210](https://github.com/rubocop/rubocop/issues/12210): Mark `Style/RedundantFilterChain` as unsafe autocorrect. ([@koic][]) + + ## 1.56.4 (2023-09-28) + + ### Bug fixes + + * [#12221](https://github.com/rubocop/rubocop/issues/12221): Fix a false positive for `Layout/EmptyLineAfterGuardClause` when using `return` before guard condition with heredoc. ([@koic][]) + * [#12213](https://github.com/rubocop/rubocop/issues/12213): Fix a false positive for `Lint/OrderedMagicComments` when comment text `# encoding: ISO-8859-1` is embedded within example code as source code comment. ([@koic][]) + * [#12205](https://github.com/rubocop/rubocop/issues/12205): Fix an error for `Style/OperatorMethodCall` when using `foo bar./ baz`. ([@koic][]) + * [#12208](https://github.com/rubocop/rubocop/issues/12208): Fix an incorrect autocorrect for the `--disable-uncorrectable` command line option when registering an offense is outside a percent array. ([@koic][]) + * [#12203](https://github.com/rubocop/rubocop/pull/12203): Fix an incorrect autocorrect for `Lint/SafeNavigationChain` when using safe navigation with comparison operator as an expression of logical operator or comparison operator's operand. ([@koic][]) + * [#12206](https://github.com/rubocop/rubocop/pull/12206): Fix an incorrect autocorrect for `Style/OperatorMethodCall` when using `foo./bar`. ([@koic][]) + * [#12202](https://github.com/rubocop/rubocop/pull/12202): Fix an incorrect autocorrect for `Style/RedundantConditional` when unless/else with boolean results. ([@ydah][]) + * [#12199](https://github.com/rubocop/rubocop/issues/12199): Fix false negatives for `Layout/MultilineMethodCallIndentation` when using safe navigation operator. ([@koic][]) + + ### Changes + + * [#12197](https://github.com/rubocop/rubocop/pull/12197): Make `Style/CollectionMethods` aware of `collect_concat`. ([@koic][]) + +------------------------------------------------------------------- Old: ---- rubocop-1.56.3.gem New: ---- rubocop-1.57.0.gem ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ rubygem-rubocop.spec ++++++ --- /var/tmp/diff_new_pack.kIjZxw/_old 2023-10-12 23:43:01.574889413 +0200 +++ /var/tmp/diff_new_pack.kIjZxw/_new 2023-10-12 23:43:01.578889557 +0200 @@ -24,7 +24,7 @@ # Name: rubygem-rubocop -Version: 1.56.3 +Version: 1.57.0 Release: 0 %define mod_name rubocop %define mod_full_name %{mod_name}-%{version} ++++++ rubocop-1.56.3.gem -> rubocop-1.57.0.gem ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/README.md new/README.md --- old/README.md 2023-09-11 08:27:13.000000000 +0200 +++ new/README.md 2023-10-11 12:49:43.000000000 +0200 @@ -53,7 +53,7 @@ in your `Gemfile`: ```rb -gem 'rubocop', '~> 1.56', require: false +gem 'rubocop', '~> 1.57', require: false ``` See [our versioning policy](https://docs.rubocop.org/rubocop/versioning.html) for further details. Binary files old/checksums.yaml.gz and new/checksums.yaml.gz differ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/config/default.yml new/config/default.yml --- old/config/default.yml 2023-09-11 08:27:13.000000000 +0200 +++ new/config/default.yml 2023-10-11 12:49:43.000000000 +0200 @@ -2170,7 +2170,9 @@ Lint/RedundantRequireStatement: Description: 'Checks for unnecessary `require` statement.' Enabled: true + SafeAutoCorrect: false VersionAdded: '0.76' + VersionChanged: '1.57' Lint/RedundantSafeNavigation: Description: 'Checks for redundant safe navigation calls.' @@ -3354,7 +3356,9 @@ Description: 'Enforces the use of `Object#instance_of?` instead of class comparison for equality.' StyleGuide: '#instance-of-vs-class-comparison' Enabled: true + SafeAutoCorrect: false VersionAdded: '0.93' + VersionChanged: '1.57' AllowedMethods: - == - equal? @@ -3409,6 +3413,7 @@ PreferredMethods: collect: 'map' collect!: 'map!' + collect_concat: 'flat_map' inject: 'reduce' detect: 'find' find_all: 'select' @@ -4919,7 +4924,9 @@ Identifies usages of `any?`, `empty?`, `none?` or `one?` predicate methods chained to `select`/`filter`/`find_all` and change them to use predicate method instead. Enabled: pending + SafeAutoCorrect: false VersionAdded: '1.52' + VersionChanged: '1.57' Style/RedundantFreeze: Description: "Checks usages of Object#freeze on immutable objects." @@ -5181,6 +5188,11 @@ - acc - elem +Style/SingleLineDoEndBlock: + Description: 'Checks for single-line `do`...`end` blocks.' + Enabled: pending + VersionAdded: '1.57' + Style/SingleLineMethods: Description: 'Avoid single-line methods.' StyleGuide: '#no-single-line-methods' diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lib/rubocop/cli.rb new/lib/rubocop/cli.rb --- old/lib/rubocop/cli.rb 2023-09-11 08:27:13.000000000 +0200 +++ new/lib/rubocop/cli.rb 2023-10-11 12:49:43.000000000 +0200 @@ -11,7 +11,7 @@ STATUS_ERROR = 2 STATUS_INTERRUPTED = Signal.list['INT'] + 128 DEFAULT_PARALLEL_OPTIONS = %i[ - color debug display_style_guide display_time display_only_fail_level_offenses + color config debug display_style_guide display_time display_only_fail_level_offenses display_only_failed except extra_details fail_level fix_layout format ignore_disable_comments lint only only_guide_cops require safe autocorrect safe_autocorrect autocorrect_all diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lib/rubocop/cop/autocorrect_logic.rb new/lib/rubocop/cop/autocorrect_logic.rb --- old/lib/rubocop/cop/autocorrect_logic.rb 2023-09-11 08:27:13.000000000 +0200 +++ new/lib/rubocop/cop/autocorrect_logic.rb 2023-10-11 12:49:43.000000000 +0200 @@ -82,7 +82,9 @@ node.array_type? && node.percent_literal? end - percent_array.map(&:source_range).find { |range| range.overlaps?(offense_range) } + percent_array.map(&:source_range).find do |range| + offense_range.begin_pos > range.begin_pos && range.overlaps?(offense_range) + end end def range_of_first_line(range) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lib/rubocop/cop/internal_affairs/example_description.rb new/lib/rubocop/cop/internal_affairs/example_description.rb --- old/lib/rubocop/cop/internal_affairs/example_description.rb 2023-09-11 08:27:13.000000000 +0200 +++ new/lib/rubocop/cop/internal_affairs/example_description.rb 2023-10-11 12:49:43.000000000 +0200 @@ -26,9 +26,7 @@ # expect_no_offenses('...') # end class ExampleDescription < Base - class << self - attr_accessor :descriptions - end + extend AutoCorrector MSG = 'Description does not match use of `%<method_name>s`.' @@ -39,22 +37,31 @@ expect_no_corrections ].to_set.freeze - EXPECT_NO_OFFENSES_INCORRECT_DESCRIPTIONS = [ - /^(adds|registers|reports|finds) (an? )?offense/, - /^(flags|handles|works)\b/ - ].freeze - - EXPECT_OFFENSE_INCORRECT_DESCRIPTIONS = [ - /^(does not|doesn't) (register|find|flag|report)/, - /^(does not|doesn't) add (a|an|any )?offense/, - /^accepts\b/ - ].freeze - - EXPECT_NO_CORRECTIONS_INCORRECT_DESCRIPTIONS = [/^(auto[- ]?)?correct/].freeze - - EXPECT_CORRECTION_INCORRECT_DESCRIPTIONS = [ - /\b(does not|doesn't) (auto[- ]?)?correct/ - ].freeze + EXPECT_NO_OFFENSES_DESCRIPTION_MAPPING = { + /\A(adds|registers|reports|finds) (an? )?offense/ => 'does not register an offense', + /\A(flags|handles|works)\b/ => 'does not register' + }.freeze + + EXPECT_OFFENSE_DESCRIPTION_MAPPING = { + /\A(does not|doesn't) (register|find|flag|report)/ => 'registers', + /\A(does not|doesn't) add (a|an|any )?offense/ => 'registers an offense', + /\Aaccepts\b/ => 'registers' + }.freeze + + EXPECT_NO_CORRECTIONS_DESCRIPTION_MAPPING = { + /\A(auto[- ]?)?correct/ => 'does not correct' + }.freeze + + EXPECT_CORRECTION_DESCRIPTION_MAPPING = { + /\b(does not|doesn't) (auto[- ]?)?correct/ => 'autocorrects' + }.freeze + + EXAMPLE_DESCRIPTION_MAPPING = { + expect_no_offenses: EXPECT_NO_OFFENSES_DESCRIPTION_MAPPING, + expect_offense: EXPECT_OFFENSE_DESCRIPTION_MAPPING, + expect_no_corrections: EXPECT_NO_CORRECTIONS_DESCRIPTION_MAPPING, + expect_correction: EXPECT_CORRECTION_DESCRIPTION_MAPPING + }.freeze # @!method offense_example?(node) def_node_matcher :offense_example?, <<~PATTERN @@ -67,21 +74,34 @@ def on_send(node) parent = node.each_ancestor(:block).first - return unless parent && (description = offense_example?(parent)) + return unless parent && (current_description = offense_example?(parent)) method_name = node.method_name message = format(MSG, method_name: method_name) - regexp_group = self.class.const_get("#{method_name}_incorrect_descriptions".upcase) - check_description(description, regexp_group, message) + description_map = EXAMPLE_DESCRIPTION_MAPPING[method_name] + check_description(current_description, description_map, message) end private - def check_description(description, regexps, message) - return unless regexps.any? { |regexp| regexp.match?(string_contents(description)) } + def check_description(current_description, description_map, message) + description_text = string_contents(current_description) + return unless (new_description = correct_description(description_text, description_map)) + + add_offense(current_description, message: message) do |corrector| + corrector.replace(current_description, "'#{new_description}'") + end + end + + def correct_description(current_description, description_map) + description_map.each do |incorrect_description_pattern, preferred_description| + if incorrect_description_pattern.match?(current_description) + return current_description.gsub(incorrect_description_pattern, preferred_description) + end + end - add_offense(description, message: message) + nil end def string_contents(node) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lib/rubocop/cop/internal_affairs/useless_message_assertion.rb new/lib/rubocop/cop/internal_affairs/useless_message_assertion.rb --- old/lib/rubocop/cop/internal_affairs/useless_message_assertion.rb 2023-09-11 08:27:13.000000000 +0200 +++ new/lib/rubocop/cop/internal_affairs/useless_message_assertion.rb 2023-10-11 12:49:43.000000000 +0200 @@ -27,6 +27,8 @@ PATTERN def on_new_investigation + return if processed_source.blank? + assertions_using_described_class_msg.each { |node| add_offense(node) } end diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lib/rubocop/cop/layout/dot_position.rb new/lib/rubocop/cop/layout/dot_position.rb --- old/lib/rubocop/cop/layout/dot_position.rb 2023-09-11 08:27:13.000000000 +0200 +++ new/lib/rubocop/cop/layout/dot_position.rb 2023-10-11 12:49:43.000000000 +0200 @@ -32,7 +32,7 @@ end def on_send(node) - return unless node.dot? || ampersand_dot?(node) + return unless node.dot? || node.safe_navigation? return correct_style_detected if proper_dot_position?(node) @@ -133,10 +133,6 @@ # l.(1) has no selector, so we use the opening parenthesis instead node.loc.selector || node.loc.begin end - - def ampersand_dot?(node) - node.loc.respond_to?(:dot) && node.loc.dot && node.loc.dot.is?('&.') - end end end end diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lib/rubocop/cop/layout/empty_line_after_guard_clause.rb new/lib/rubocop/cop/layout/empty_line_after_guard_clause.rb --- old/lib/rubocop/cop/layout/empty_line_after_guard_clause.rb 2023-09-11 08:27:13.000000000 +0200 +++ new/lib/rubocop/cop/layout/empty_line_after_guard_clause.rb 2023-10-11 12:49:43.000000000 +0200 @@ -164,6 +164,8 @@ if node.if_branch.and_type? node.if_branch.children.first + elsif use_heredoc_in_condition?(node.condition) + node.condition else node.if_branch.children.last end @@ -180,6 +182,12 @@ node.respond_to?(:heredoc?) && node.heredoc? end + def use_heredoc_in_condition?(condition) + condition.descendants.any? do |descendant| + descendant.respond_to?(:heredoc?) && descendant.heredoc? + end + end + def offense_location(node) if node.loc.respond_to?(:end) && node.loc.end node.loc.end diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lib/rubocop/cop/layout/indentation_width.rb new/lib/rubocop/cop/layout/indentation_width.rb --- old/lib/rubocop/cop/layout/indentation_width.rb 2023-09-11 08:27:13.000000000 +0200 +++ new/lib/rubocop/cop/layout/indentation_width.rb 2023-10-11 12:49:43.000000000 +0200 @@ -354,7 +354,7 @@ # Don't check indentation if the line doesn't start with the body. # For example, lines like "else do_something". first_char_pos_on_line = body_node.source_range.source_line =~ /\S/ - true unless body_node.loc.column == first_char_pos_on_line + body_node.loc.column != first_char_pos_on_line end def offending_range(body_node, indentation) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lib/rubocop/cop/layout/multiline_method_call_indentation.rb new/lib/rubocop/cop/layout/multiline_method_call_indentation.rb --- old/lib/rubocop/cop/layout/multiline_method_call_indentation.rb 2023-09-11 08:27:13.000000000 +0200 +++ new/lib/rubocop/cop/layout/multiline_method_call_indentation.rb 2023-10-11 12:49:43.000000000 +0200 @@ -75,7 +75,7 @@ def right_hand_side(send_node) dot = send_node.loc.dot selector = send_node.loc.selector - if send_node.dot? && selector && same_line?(dot, selector) + if (send_node.dot? || send_node.safe_navigation?) && selector && same_line?(dot, selector) dot.join(selector) elsif selector selector @@ -179,7 +179,7 @@ # a.b # .c def semantic_alignment_base(node, rhs) - return unless rhs.source.start_with?('.') + return unless rhs.source.start_with?('.', '&.') node = semantic_alignment_node(node) return unless node&.loc&.selector @@ -204,6 +204,10 @@ dot_right_above = get_dot_right_above(node) return dot_right_above if dot_right_above + if (multiline_block_chain_node = find_multiline_block_chain_node(node)) + return multiline_block_chain_node + end + node = first_call_has_a_dot(node) return if node.loc.dot.line != node.first_line @@ -219,6 +223,13 @@ end end + def find_multiline_block_chain_node(node) + return unless (block_node = node.each_descendant(:block, :numblock).first) + return unless block_node.multiline? && block_node.parent.call_type? + + block_node.parent + end + def first_call_has_a_dot(node) # descend to root of method chain node = node.receiver while node.receiver diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lib/rubocop/cop/layout/space_inside_parens.rb new/lib/rubocop/cop/layout/space_inside_parens.rb --- old/lib/rubocop/cop/layout/space_inside_parens.rb 2023-09-11 08:27:13.000000000 +0200 +++ new/lib/rubocop/cop/layout/space_inside_parens.rb 2023-10-11 12:49:43.000000000 +0200 @@ -168,7 +168,7 @@ # follows, and that the rules for space inside don't apply. return true if token2.comment? - true unless same_line?(token1, token2) && !token1.space_after? + !same_line?(token1, token2) || token1.space_after? end end end diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lib/rubocop/cop/lint/debugger.rb new/lib/rubocop/cop/lint/debugger.rb --- old/lib/rubocop/cop/lint/debugger.rb 2023-09-11 08:27:13.000000000 +0200 +++ new/lib/rubocop/cop/lint/debugger.rb 2023-10-11 12:49:43.000000000 +0200 @@ -95,8 +95,11 @@ def assumed_usage_context?(node) # Basically, debugger methods are not used as a method argument without arguments. return false unless node.arguments.empty? && node.each_ancestor(:send, :csend).any? + return true if assumed_argument?(node) - node.each_ancestor.none?(&:lambda_or_proc?) + node.each_ancestor.none? do |ancestor| + ancestor.block_type? || ancestor.numblock_type? || ancestor.lambda_or_proc? + end end def chained_method_name(send_node) @@ -109,6 +112,12 @@ end chained_method_name end + + def assumed_argument?(node) + parent = node.parent + + parent.call_type? || parent.literal? || parent.pair_type? + end end end end diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lib/rubocop/cop/lint/empty_block.rb new/lib/rubocop/cop/lint/empty_block.rb --- old/lib/rubocop/cop/lint/empty_block.rb 2023-09-11 08:27:13.000000000 +0200 +++ new/lib/rubocop/cop/lint/empty_block.rb 2023-10-11 12:49:43.000000000 +0200 @@ -5,7 +5,7 @@ module Lint # Checks for blocks without a body. # Such empty blocks are typically an oversight or we should provide a comment - # be clearer what we're aiming for. + # to clarify what we're aiming for. # # Empty lambdas and procs are ignored by default. # diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lib/rubocop/cop/lint/literal_in_interpolation.rb new/lib/rubocop/cop/lint/literal_in_interpolation.rb --- old/lib/rubocop/cop/lint/literal_in_interpolation.rb 2023-09-11 08:27:13.000000000 +0200 +++ new/lib/rubocop/cop/lint/literal_in_interpolation.rb 2023-10-11 12:49:43.000000000 +0200 @@ -34,7 +34,7 @@ # interpolation should not be removed if the expanded value # contains a space character. expanded_value = autocorrected_value(final_node) - return if in_array_percent_literal?(begin_node) && /\s/.match?(expanded_value) + return if in_array_percent_literal?(begin_node) && /\s|\A\z/.match?(expanded_value) add_offense(final_node) do |corrector| return if final_node.dstr_type? # nested, fixed in next iteration diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lib/rubocop/cop/lint/mixed_case_range.rb new/lib/rubocop/cop/lint/mixed_case_range.rb --- old/lib/rubocop/cop/lint/mixed_case_range.rb 2023-09-11 08:27:13.000000000 +0200 +++ new/lib/rubocop/cop/lint/mixed_case_range.rb 2023-10-11 12:49:43.000000000 +0200 @@ -95,7 +95,7 @@ def skip_range?(range_start, range_end) [range_start, range_end].any? do |bound| - bound.type == :escape + bound.type != :literal end end diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lib/rubocop/cop/lint/non_atomic_file_operation.rb new/lib/rubocop/cop/lint/non_atomic_file_operation.rb --- old/lib/rubocop/cop/lint/non_atomic_file_operation.rb 2023-09-11 08:27:13.000000000 +0200 +++ new/lib/rubocop/cop/lint/non_atomic_file_operation.rb 2023-10-11 12:49:43.000000000 +0200 @@ -43,7 +43,6 @@ # class NonAtomicFileOperation < Base extend AutoCorrector - include Alignment MSG_REMOVE_FILE_EXIST_CHECK = 'Remove unnecessary existence check ' \ '`%<receiver>s.%<method_name>s`.' diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lib/rubocop/cop/lint/redundant_require_statement.rb new/lib/rubocop/cop/lint/redundant_require_statement.rb --- old/lib/rubocop/cop/lint/redundant_require_statement.rb 2023-09-11 08:27:13.000000000 +0200 +++ new/lib/rubocop/cop/lint/redundant_require_statement.rb 2023-10-11 12:49:43.000000000 +0200 @@ -24,6 +24,10 @@ # # This cop target those features. # + # @safety + # This cop's autocorrection is unsafe because if `require 'pp'` is removed from one file, + # `NameError` can be encountered when another file uses `PP.pp`. + # # @example # # bad # require 'unloaded_feature' diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lib/rubocop/cop/lint/redundant_safe_navigation.rb new/lib/rubocop/cop/lint/redundant_safe_navigation.rb --- old/lib/rubocop/cop/lint/redundant_safe_navigation.rb 2023-09-11 08:27:13.000000000 +0200 +++ new/lib/rubocop/cop/lint/redundant_safe_navigation.rb 2023-10-11 12:49:43.000000000 +0200 @@ -4,8 +4,12 @@ module Cop module Lint # Checks for redundant safe navigation calls. - # `instance_of?`, `kind_of?`, `is_a?`, `eql?`, `respond_to?`, and `equal?` methods - # are checked by default. These are customizable with `AllowedMethods` option. + # Use cases where a constant is `nil` are rare and an offense is detected + # when the receiver is a constant. + # + # For all receivers, the `instance_of?`, `kind_of?`, `is_a?`, `eql?`, `respond_to?`, + # and `equal?` methods are checked by default. + # These are customizable with `AllowedMethods` option. # # The `AllowedMethods` option specifies nil-safe methods, # in other words, it is a method that is allowed to skip safe navigation. @@ -22,6 +26,9 @@ # # @example # # bad + # Const&.do_something + # + # # bad # do_something if attrs&.respond_to?(:[]) # # # good @@ -33,6 +40,9 @@ # end # # # good + # Const.do_something + # + # # good # while node.is_a?(BeginNode) # node = node.parent # end @@ -63,8 +73,10 @@ PATTERN def on_csend(node) - return unless check?(node) && allowed_method?(node.method_name) - return if respond_to_nil_specific_method?(node) + unless node.receiver.const_type? + return unless check?(node) && allowed_method?(node.method_name) + return if respond_to_nil_specific_method?(node) + end range = range_between(node.loc.dot.begin_pos, node.source_range.end_pos) add_offense(range) { |corrector| corrector.replace(node.loc.dot, '.') } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lib/rubocop/cop/lint/safe_navigation_chain.rb new/lib/rubocop/cop/lint/safe_navigation_chain.rb --- old/lib/rubocop/cop/lint/safe_navigation_chain.rb 2023-09-11 08:27:13.000000000 +0200 +++ new/lib/rubocop/cop/lint/safe_navigation_chain.rb 2023-10-11 12:49:43.000000000 +0200 @@ -82,16 +82,23 @@ def autocorrect(corrector, offense_range:, send_node:) corrector.replace( offense_range, - add_safe_navigation_operator( - offense_range: offense_range, - send_node: send_node - ) + add_safe_navigation_operator(offense_range: offense_range, send_node: send_node) ) + + corrector.wrap(send_node, '(', ')') if require_parentheses?(send_node) end def brackets?(send_node) send_node.method?(:[]) || send_node.method?(:[]=) end + + def require_parentheses?(send_node) + return false unless send_node.comparison_method? + return false unless (node = send_node.parent) + + (node.respond_to?(:logical_operator?) && node.logical_operator?) || + (node.respond_to?(:comparison_method?) && node.comparison_method?) + end end end end diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lib/rubocop/cop/metrics/block_length.rb new/lib/rubocop/cop/metrics/block_length.rb --- old/lib/rubocop/cop/metrics/block_length.rb 2023-09-11 08:27:13.000000000 +0200 +++ new/lib/rubocop/cop/metrics/block_length.rb 2023-10-11 12:49:43.000000000 +0200 @@ -12,6 +12,7 @@ # Available are: 'array', 'hash', 'heredoc', and 'method_call'. Each construct # will be counted as one line regardless of its actual size. # + # NOTE: This cop does not apply for `Struct` definitions. # # NOTE: The `ExcludedMethods` configuration is deprecated and only kept # for backwards compatibility. Please use `AllowedMethods` and `AllowedPatterns` @@ -40,7 +41,6 @@ # ) # end # 6 points # - # NOTE: This cop does not apply for `Struct` definitions. class BlockLength < Base include CodeLength include AllowedMethods diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lib/rubocop/cop/metrics/class_length.rb new/lib/rubocop/cop/metrics/class_length.rb --- old/lib/rubocop/cop/metrics/class_length.rb 2023-09-11 08:27:13.000000000 +0200 +++ new/lib/rubocop/cop/metrics/class_length.rb 2023-10-11 12:49:43.000000000 +0200 @@ -11,6 +11,8 @@ # Available are: 'array', 'hash', 'heredoc', and 'method_call'. Each construct # will be counted as one line regardless of its actual size. # + # NOTE: This cop also applies for `Struct` definitions. + # # @example CountAsOne: ['array', 'heredoc', 'method_call'] # # class Foo @@ -34,8 +36,6 @@ # ) # end # 6 points # - # - # NOTE: This cop also applies for `Struct` definitions. class ClassLength < Base include CodeLength diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lib/rubocop/cop/metrics/utils/code_length_calculator.rb new/lib/rubocop/cop/metrics/utils/code_length_calculator.rb --- old/lib/rubocop/cop/metrics/utils/code_length_calculator.rb 2023-09-11 08:27:13.000000000 +0200 +++ new/lib/rubocop/cop/metrics/utils/code_length_calculator.rb 2023-10-11 12:49:43.000000000 +0200 @@ -10,7 +10,7 @@ include Util FOLDABLE_TYPES = %i[array hash heredoc send csend].freeze - CLASSLIKE_TYPES = %i[class module sclass].freeze + CLASSLIKE_TYPES = %i[class module].freeze private_constant :FOLDABLE_TYPES, :CLASSLIKE_TYPES def initialize(node, processed_source, count_comments: false, foldable_types: []) @@ -145,7 +145,7 @@ def extract_body(node) case node.type - when :class, :module, :block, :numblock, :def, :defs + when :class, :module, :sclass, :block, :numblock, :def, :defs node.body when :casgn _scope, _name, value = *node diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lib/rubocop/cop/mixin/multiline_expression_indentation.rb new/lib/rubocop/cop/mixin/multiline_expression_indentation.rb --- old/lib/rubocop/cop/mixin/multiline_expression_indentation.rb 2023-09-11 08:27:13.000000000 +0200 +++ new/lib/rubocop/cop/mixin/multiline_expression_indentation.rb 2023-10-11 12:49:43.000000000 +0200 @@ -20,16 +20,17 @@ range = offending_range(node, lhs, rhs, style) check(range, node, lhs, rhs) end + alias on_csend on_send private - # In a chain of method calls, we regard the top send node as the base + # In a chain of method calls, we regard the top call node as the base # for indentation of all lines following the first. For example: # a. # b c { block }. <-- b is indented relative to a # d <-- d is indented relative to a def left_hand_side(lhs) - while lhs.parent&.send_type? && lhs.parent.loc.dot && !lhs.parent.assignment_method? + while lhs.parent&.call_type? && lhs.parent.loc.dot && !lhs.parent.assignment_method? lhs = lhs.parent end lhs diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lib/rubocop/cop/style/class_equality_comparison.rb new/lib/rubocop/cop/style/class_equality_comparison.rb --- old/lib/rubocop/cop/style/class_equality_comparison.rb 2023-09-11 08:27:13.000000000 +0200 +++ new/lib/rubocop/cop/style/class_equality_comparison.rb 2023-10-11 12:49:43.000000000 +0200 @@ -8,6 +8,11 @@ # `==`, `equal?`, and `eql?` custom method definitions are allowed by default. # These are customizable with `AllowedMethods` option. # + # @safety + # This cop's autocorrection is unsafe because there is no guarantee that + # the constant `Foo` exists when autocorrecting `var.class.name == 'Foo'` to + # `var.instance_of?(Foo)`. + # # @example # # bad # var.class == Date diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lib/rubocop/cop/style/collection_methods.rb new/lib/rubocop/cop/style/collection_methods.rb --- old/lib/rubocop/cop/style/collection_methods.rb 2023-09-11 08:27:13.000000000 +0200 +++ new/lib/rubocop/cop/style/collection_methods.rb 2023-10-11 12:49:43.000000000 +0200 @@ -25,6 +25,7 @@ # # bad # items.collect # items.collect! + # items.collect_concat # items.inject # items.detect # items.find_all @@ -33,6 +34,7 @@ # # good # items.map # items.map! + # items.flat_map # items.reduce # items.find # items.select diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lib/rubocop/cop/style/format_string.rb new/lib/rubocop/cop/style/format_string.rb --- old/lib/rubocop/cop/style/format_string.rb 2023-09-11 08:27:13.000000000 +0200 +++ new/lib/rubocop/cop/style/format_string.rb 2023-10-11 12:49:43.000000000 +0200 @@ -4,13 +4,25 @@ module Cop module Style # Enforces the use of a single string formatting utility. - # Valid options include Kernel#format, Kernel#sprintf and String#%. + # Valid options include `Kernel#format`, `Kernel#sprintf`, and `String#%`. # - # The detection of String#% cannot be implemented in a reliable + # The detection of `String#%` cannot be implemented in a reliable # manner for all cases, so only two scenarios are considered - # if the first argument is a string literal and if the second # argument is an array literal. # + # Autocorrection will be applied when using argument is a literal or known built-in conversion + # methods such as `to_d`, `to_f`, `to_h`, `to_i`, `to_r`, `to_s`, and `to_sym` on variables, + # provided that their return value is not an array. For example, when using `to_s`, + # `'%s' % [1, 2, 3].to_s` can be autocorrected without any incompatibility: + # + # [source,ruby] + # ---- + # '%s' % [1, 2, 3] #=> '1' + # format('%s', [1, 2, 3]) #=> '[1, 2, 3]' + # '%s' % [1, 2, 3].to_s #=> '[1, 2, 3]' + # ---- + # # @example EnforcedStyle: format (default) # # bad # puts sprintf('%10s', 'hoge') @@ -42,6 +54,9 @@ MSG = 'Favor `%<prefer>s` over `%<current>s`.' RESTRICT_ON_SEND = %i[format sprintf %].freeze + # Known conversion methods whose return value is not an array. + AUTOCORRECTABLE_METHODS = %i[to_d to_f to_h to_i to_r to_s to_sym].freeze + # @!method formatter(node) def_node_matcher :formatter, <<~PATTERN { @@ -53,7 +68,7 @@ # @!method variable_argument?(node) def_node_matcher :variable_argument?, <<~PATTERN - (send {str dstr} :% {send_type? lvar_type?}) + (send {str dstr} :% #autocorrectable?) PATTERN def on_send(node) @@ -70,6 +85,12 @@ private + def autocorrectable?(node) + return true if node.lvar_type? + + node.send_type? && !AUTOCORRECTABLE_METHODS.include?(node.method_name) + end + def message(detected_style) format(MSG, prefer: method_name(style), current: method_name(detected_style)) end diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lib/rubocop/cop/style/guard_clause.rb new/lib/rubocop/cop/style/guard_clause.rb --- old/lib/rubocop/cop/style/guard_clause.rb 2023-09-11 08:27:13.000000000 +0200 +++ new/lib/rubocop/cop/style/guard_clause.rb 2023-10-11 12:49:43.000000000 +0200 @@ -55,6 +55,25 @@ # foo || raise('exception') if something # ok # + # # bad + # define_method(:test) do + # if something + # work + # end + # end + # + # # good + # define_method(:test) do + # return unless something + # + # work + # end + # + # # also good + # define_method(:test) do + # work if something + # end + # # @example AllowConsecutiveConditionals: false (default) # # bad # def test @@ -110,6 +129,13 @@ end alias on_defs on_def + def on_block(node) + return unless node.method?(:define_method) || node.method?(:define_singleton_method) + + on_def(node) + end + alias on_numblock on_block + def on_if(node) return if accepted_form?(node) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lib/rubocop/cop/style/identical_conditional_branches.rb new/lib/rubocop/cop/style/identical_conditional_branches.rb --- old/lib/rubocop/cop/style/identical_conditional_branches.rb 2023-09-11 08:27:13.000000000 +0200 +++ new/lib/rubocop/cop/style/identical_conditional_branches.rb 2023-10-11 12:49:43.000000000 +0200 @@ -136,7 +136,7 @@ private - # rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity + # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity def check_branches(node, branches) # return if any branch is empty. An empty branch can be an `if` # without an `else` or a branch that contains only comments. @@ -149,9 +149,15 @@ branches.any? { |branch| single_child_branch?(branch) } heads = branches.map { |branch| head(branch) } - check_expressions(node, heads, :before_condition) if duplicated_expressions?(node, heads) + + return unless duplicated_expressions?(node, heads) + + condition_variable = assignable_condition_value(node) + return if heads.first.assignment? && condition_variable == heads.first.name.to_s + + check_expressions(node, heads, :before_condition) end - # rubocop:enable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity + # rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity def duplicated_expressions?(node, expressions) unique_expressions = expressions.uniq @@ -164,6 +170,14 @@ node.condition.child_nodes.none? { |n| n.source == lhs.source if n.variable? } end + def assignable_condition_value(node) + if node.condition.call_type? + (receiver = node.condition.receiver) ? receiver.source : node.condition.source + elsif node.condition.variable? + node.condition.source + end + end + # rubocop:disable Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity def check_expressions(node, expressions, insert_position) return if expressions.any?(&:nil?) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lib/rubocop/cop/style/multiline_block_chain.rb new/lib/rubocop/cop/style/multiline_block_chain.rb --- old/lib/rubocop/cop/style/multiline_block_chain.rb 2023-09-11 08:27:13.000000000 +0200 +++ new/lib/rubocop/cop/style/multiline_block_chain.rb 2023-10-11 12:49:43.000000000 +0200 @@ -28,7 +28,7 @@ MSG = 'Avoid multi-line chains of blocks.' def on_block(node) - node.send_node.each_node(:send) do |send_node| + node.send_node.each_node(:send, :csend) do |send_node| receiver = send_node.receiver next unless (receiver&.block_type? || receiver&.numblock_type?) && receiver&.multiline? diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lib/rubocop/cop/style/nested_ternary_operator.rb new/lib/rubocop/cop/style/nested_ternary_operator.rb --- old/lib/rubocop/cop/style/nested_ternary_operator.rb 2023-09-11 08:27:13.000000000 +0200 +++ new/lib/rubocop/cop/style/nested_ternary_operator.rb 2023-10-11 12:49:43.000000000 +0200 @@ -27,24 +27,16 @@ node.each_descendant(:if).select(&:ternary?).each do |nested_ternary| add_offense(nested_ternary) do |corrector| - if_node = if_node(nested_ternary) - next if part_of_ignored_node?(if_node) + next if part_of_ignored_node?(node) - autocorrect(corrector, if_node) - ignore_node(if_node) + autocorrect(corrector, node) + ignore_node(node) end end end private - def if_node(node) - node = node.parent - return node if node.if_type? - - if_node(node) - end - def autocorrect(corrector, if_node) replace_loc_and_whitespace(corrector, if_node.loc.question, "\n") replace_loc_and_whitespace(corrector, if_node.loc.colon, "\nelse\n") diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lib/rubocop/cop/style/operator_method_call.rb new/lib/rubocop/cop/style/operator_method_call.rb --- old/lib/rubocop/cop/style/operator_method_call.rb 2023-09-11 08:27:13.000000000 +0200 +++ new/lib/rubocop/cop/style/operator_method_call.rb 2023-10-11 12:49:43.000000000 +0200 @@ -23,6 +23,7 @@ MSG = 'Redundant dot detected.' RESTRICT_ON_SEND = %i[| ^ & <=> == === =~ > >= < <= << >> + - * / % ** ~ ! != !~].freeze + # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity def on_send(node) return unless (dot = node.loc.dot) return if node.receiver.const_type? || !node.arguments.one? @@ -33,8 +34,12 @@ add_offense(dot) do |corrector| wrap_in_parentheses_if_chained(corrector, node) corrector.replace(dot, ' ') + + selector = node.loc.selector + corrector.insert_after(selector, ' ') if selector.end_pos == rhs.source_range.begin_pos end end + # rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity private @@ -54,6 +59,7 @@ def wrap_in_parentheses_if_chained(corrector, node) return unless node.parent&.call_type? + return if node.parent.first_argument == node operator = node.loc.selector diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lib/rubocop/cop/style/redundant_begin.rb new/lib/rubocop/cop/style/redundant_begin.rb --- old/lib/rubocop/cop/style/redundant_begin.rb 2023-09-11 08:27:13.000000000 +0200 +++ new/lib/rubocop/cop/style/redundant_begin.rb 2023-10-11 12:49:43.000000000 +0200 @@ -114,7 +114,7 @@ if node.parent&.assignment? replace_begin_with_statement(corrector, offense_range, node) else - corrector.remove(offense_range) + remove_begin(corrector, offense_range, node) end if use_modifier_form_after_multiline_begin_block?(node) @@ -136,6 +136,14 @@ restore_removed_comments(corrector, offense_range, node, first_child) end + def remove_begin(corrector, offense_range, node) + if node.parent.respond_to?(:endless?) && node.parent.endless? + offense_range = range_with_surrounding_space(offense_range, newlines: true) + end + + corrector.remove(offense_range) + end + # Restore comments that occur between "begin" and "first_child". # These comments will be moved to above the assignment line. def restore_removed_comments(corrector, offense_range, node, first_child) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lib/rubocop/cop/style/redundant_conditional.rb new/lib/rubocop/cop/style/redundant_conditional.rb --- old/lib/rubocop/cop/style/redundant_conditional.rb 2023-09-11 08:27:13.000000000 +0200 +++ new/lib/rubocop/cop/style/redundant_conditional.rb 2023-10-11 12:49:43.000000000 +0200 @@ -70,19 +70,11 @@ def replacement_condition(node) condition = node.condition.source - expression = invert_expression?(node) ? "!(#{condition})" : condition + expression = redundant_condition_inverted?(node) ? "!(#{condition})" : condition node.elsif? ? indented_else_node(expression, node) : expression end - def invert_expression?(node) - ( - (node.if? || node.elsif? || node.ternary?) && redundant_condition_inverted?(node) - ) || ( - node.unless? && redundant_condition?(node) - ) - end - def indented_else_node(expression, node) "else\n#{indentation(node)}#{expression}" end diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lib/rubocop/cop/style/redundant_double_splat_hash_braces.rb new/lib/rubocop/cop/style/redundant_double_splat_hash_braces.rb --- old/lib/rubocop/cop/style/redundant_double_splat_hash_braces.rb 2023-09-11 08:27:13.000000000 +0200 +++ new/lib/rubocop/cop/style/redundant_double_splat_hash_braces.rb 2023-10-11 12:49:43.000000000 +0200 @@ -13,25 +13,50 @@ # # good # do_something(foo: bar, baz: qux) # + # # bad + # do_something(**{foo: bar, baz: qux}.merge(options)) + # + # # good + # do_something(foo: bar, baz: qux, **options) + # class RedundantDoubleSplatHashBraces < Base extend AutoCorrector MSG = 'Remove the redundant double splat and braces, use keyword arguments directly.' + MERGE_METHODS = %i[merge merge!].freeze + # rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity def on_hash(node) - return if node.pairs.empty? || node.pairs.any?(&:hash_rocket?) + return if !node.braces? || node.pairs.empty? || node.pairs.any?(&:hash_rocket?) return unless (parent = node.parent) - return unless parent.kwsplat_type? + return unless (kwsplat = node.each_ancestor(:kwsplat).first) + return if parent.call_type? && !merge_method?(parent) - add_offense(parent) do |corrector| - corrector.remove(parent.loc.operator) - corrector.remove(opening_brace(node)) - corrector.remove(closing_brace(node)) + add_offense(kwsplat) do |corrector| + autocorrect(corrector, node, kwsplat) end end + # rubocop:enable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity private + def autocorrect(corrector, node, kwsplat) + corrector.remove(kwsplat.loc.operator) + corrector.remove(opening_brace(node)) + corrector.remove(closing_brace(node)) + + merge_methods = select_merge_method_nodes(kwsplat) + return if merge_methods.empty? + + autocorrect_merge_methods(corrector, merge_methods, kwsplat) + end + + def select_merge_method_nodes(kwsplat) + extract_send_methods(kwsplat).select do |node| + merge_method?(node) + end + end + def opening_brace(node) node.loc.begin.join(node.children.first.source_range.begin) end @@ -39,6 +64,44 @@ def closing_brace(node) node.children.last.source_range.end.join(node.loc.end) end + + def autocorrect_merge_methods(corrector, merge_methods, kwsplat) + range = range_of_merge_methods(merge_methods) + + new_kwsplat_arguments = extract_send_methods(kwsplat).map do |descendant| + convert_to_new_arguments(descendant) + end + new_source = new_kwsplat_arguments.compact.reverse.unshift('').join(', ') + + corrector.replace(range, new_source) + end + + def range_of_merge_methods(merge_methods) + begin_merge_method = merge_methods.last + end_merge_method = merge_methods.first + + begin_merge_method.loc.dot.begin.join(end_merge_method.source_range.end) + end + + def extract_send_methods(kwsplat) + @extract_send_methods ||= kwsplat.each_descendant(:send, :csend) + end + + def convert_to_new_arguments(node) + return unless merge_method?(node) + + node.arguments.map do |arg| + if arg.hash_type? + arg.source + else + "**#{arg.source}" + end + end + end + + def merge_method?(node) + MERGE_METHODS.include?(node.method_name) + end end end end diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lib/rubocop/cop/style/redundant_filter_chain.rb new/lib/rubocop/cop/style/redundant_filter_chain.rb --- old/lib/rubocop/cop/style/redundant_filter_chain.rb 2023-09-11 08:27:13.000000000 +0200 +++ new/lib/rubocop/cop/style/redundant_filter_chain.rb 2023-10-11 12:49:43.000000000 +0200 @@ -6,6 +6,12 @@ # Identifies usages of `any?`, `empty?` or `none?` predicate methods # chained to `select`/`filter`/`find_all` and change them to use predicate method instead. # + # @safety + # This cop's autocorrection is unsafe because `array.select.any?` evaluates all elements + # through the `select` method, while `array.any?` uses short-circuit evaluation. + # In other words, `array.select.any?` guarantees the evaluation of every element, + # but `array.any?` does not necessarily evaluate all of them. + # # @example # # bad # arr.select { |x| x > 1 }.any? @@ -28,6 +34,9 @@ # # good # arr.select { |x| x > 1 }.many? # + # # good + # arr.select { |x| x > 1 }.present? + # # @example AllCops:ActiveSupportExtensionsEnabled: true # # bad # arr.select { |x| x > 1 }.many? @@ -35,12 +44,18 @@ # # good # arr.many? { |x| x > 1 } # + # # bad + # arr.select { |x| x > 1 }.present? + # + # # good + # arr.any? { |x| x > 1 } + # class RedundantFilterChain < Base extend AutoCorrector MSG = 'Use `%<prefer>s` instead of `%<first_method>s.%<second_method>s`.' - RAILS_METHODS = %i[many?].freeze + RAILS_METHODS = %i[many? present?].freeze RESTRICT_ON_SEND = (%i[any? empty? none? one?] + RAILS_METHODS).freeze # @!method select_predicate?(node) @@ -58,7 +73,8 @@ empty?: :none?, none?: :none?, one?: :one?, - many?: :many? + many?: :many?, + present?: :any? }.freeze private_constant :REPLACEMENT_METHODS diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lib/rubocop/cop/style/redundant_parentheses.rb new/lib/rubocop/cop/style/redundant_parentheses.rb --- old/lib/rubocop/cop/style/redundant_parentheses.rb 2023-09-11 08:27:13.000000000 +0200 +++ new/lib/rubocop/cop/style/redundant_parentheses.rb 2023-10-11 12:49:43.000000000 +0200 @@ -126,16 +126,32 @@ def check(begin_node) node = begin_node.children.first - return offense(begin_node, 'a keyword') if keyword_with_redundant_parentheses?(node) - return offense(begin_node, 'a literal') if disallowed_literal?(begin_node, node) - return offense(begin_node, 'a variable') if node.variable? - return offense(begin_node, 'a constant') if node.const_type? - return offense(begin_node, 'an interpolated expression') if interpolation?(begin_node) + if (message = find_offense_message(begin_node, node)) + return offense(begin_node, message) + end check_send(begin_node, node) if node.call_type? end + # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity + def find_offense_message(begin_node, node) + return 'a keyword' if keyword_with_redundant_parentheses?(node) + return 'a literal' if disallowed_literal?(begin_node, node) + return 'a variable' if node.variable? + return 'a constant' if node.const_type? + return 'an interpolated expression' if interpolation?(begin_node) + + return if begin_node.chained? || !begin_node.parent.nil? + + if node.and_type? || node.or_type? + 'a logical expression' + elsif node.respond_to?(:comparison_method?) && node.comparison_method? + 'a comparison expression' + end + end + # rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity + # @!method interpolation?(node) def_node_matcher :interpolation?, '[^begin ^^dstr]' diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lib/rubocop/cop/style/return_nil.rb new/lib/rubocop/cop/style/return_nil.rb --- old/lib/rubocop/cop/style/return_nil.rb 2023-09-11 08:27:13.000000000 +0200 +++ new/lib/rubocop/cop/style/return_nil.rb 2023-10-11 12:49:43.000000000 +0200 @@ -3,9 +3,13 @@ module RuboCop module Cop module Style - # Enforces consistency between 'return nil' and 'return'. + # Enforces consistency between `return nil` and `return`. # - # Supported styles are: return, return_nil. + # This cop is disabled by default. Because there seems to be a perceived semantic difference + # between `return` and `return nil`. The former can be seen as just halting evaluation, + # while the latter might be used when the return value is of specific concern. + # + # Supported styles are `return` and `return_nil`. # # @example EnforcedStyle: return (default) # # bad diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lib/rubocop/cop/style/single_line_do_end_block.rb new/lib/rubocop/cop/style/single_line_do_end_block.rb --- old/lib/rubocop/cop/style/single_line_do_end_block.rb 1970-01-01 01:00:00.000000000 +0100 +++ new/lib/rubocop/cop/style/single_line_do_end_block.rb 2023-10-11 12:49:43.000000000 +0200 @@ -0,0 +1,65 @@ +# frozen_string_literal: true + +module RuboCop + module Cop + module Style + # Checks for single-line `do`...`end` block. + # + # In practice a single line `do`...`end` is autocorrected when `EnforcedStyle: semantic` + # in `Style/BlockDelimiters`. The autocorrection maintains the `do` ... `end` syntax to + # preserve semantics and does not change it to `{`...`}` block. + # + # @example + # + # # bad + # foo do |arg| bar(arg) end + # + # # good + # foo do |arg| + # bar(arg) + # end + # + # # bad + # ->(arg) do bar(arg) end + # + # # good + # ->(arg) { bar(arg) } + # + class SingleLineDoEndBlock < Base + extend AutoCorrector + + MSG = 'Prefer multiline `do`...`end` block.' + + def on_block(node) + return if !node.single_line? || node.braces? + + add_offense(node) do |corrector| + corrector.insert_after(do_line(node), "\n") + + node_body = node.body + + if node_body.respond_to?(:heredoc?) && node_body.heredoc? + corrector.remove(node.loc.end) + corrector.insert_after(node_body.loc.heredoc_end, "\nend") + else + corrector.insert_after(node_body, "\n") + end + end + end + alias on_numblock on_block + + private + + def do_line(node) + if node.numblock_type? || node.arguments.children.empty? || node.send_node.lambda_literal? + node.loc.begin + else + node.arguments + end + end + + def x(corrector, node); end + end + end + end +end diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lib/rubocop/magic_comment.rb new/lib/rubocop/magic_comment.rb --- old/lib/rubocop/magic_comment.rb 2023-09-11 08:27:13.000000000 +0200 +++ new/lib/rubocop/magic_comment.rb 2023-10-11 12:49:43.000000000 +0200 @@ -7,7 +7,7 @@ class MagicComment # IRB's pattern for matching magic comment tokens. # @see https://github.com/ruby/ruby/blob/b4a55c1/lib/irb/magic-file.rb#L5 - TOKEN = /[[:alnum:]\-_]+/.freeze + TOKEN = '(?<token>[[:alnum:]\-_]+)' KEYWORDS = { encoding: '(?:en)?coding', frozen_string_literal: 'frozen[_-]string[_-]literal', @@ -129,7 +129,7 @@ # @return [String] if pattern matched # @return [nil] otherwise def extract(pattern) - @comment[pattern, 1] + @comment[pattern, :token] end # Parent to Vim and Emacs magic comment handling. @@ -157,10 +157,10 @@ # @return [String] extracted value if it is found # @return [nil] otherwise def match(keyword) - pattern = /\A#{keyword}\s*#{self.class::OPERATOR}\s*(#{TOKEN})\z/ + pattern = /\A#{keyword}\s*#{self.class::OPERATOR}\s*#{TOKEN}\z/ tokens.each do |token| - next unless (value = token[pattern, 1]) + next unless (value = token[pattern, :token]) return value.downcase end @@ -188,7 +188,7 @@ # @see https://www.gnu.org/software/emacs/manual/html_node/emacs/Specify-Coding.html # @see https://github.com/ruby/ruby/blob/3f306dc/parse.y#L6873-L6892 Emacs handling in parse.y class EmacsComment < EditorComment - REGEXP = /-\*-(.+)-\*-/.freeze + REGEXP = /-\*-(?<token>.+)-\*-/.freeze FORMAT = '# -*- %s -*-' SEPARATOR = ';' OPERATOR = ':' @@ -216,7 +216,7 @@ # # comment.encoding # => 'ascii-8bit' class VimComment < EditorComment - REGEXP = /#\s*vim:\s*(.+)/.freeze + REGEXP = /#\s*vim:\s*(?<token>.+)/.freeze FORMAT = '# vim: %s' SEPARATOR = ', ' OPERATOR = '=' @@ -259,9 +259,11 @@ # comment2.frozen_string_literal # => nil # comment2.encoding # => 'utf-8' class SimpleComment < MagicComment + FSTRING_LITERAL_COMMENT = 'frozen_string_literal:\s*(true|false)' + # Match `encoding` or `coding` def encoding - extract(/\A\s*\#.*\b#{KEYWORDS[:encoding]}: (#{TOKEN})/io) + extract(/\A\s*\#\s*(#{FSTRING_LITERAL_COMMENT})?\s*#{KEYWORDS[:encoding]}: (#{TOKEN})/io) end # Rewrite the comment without a given token type @@ -283,15 +285,15 @@ # Case-insensitive and dashes/underscores are acceptable. # @see https://github.com/ruby/ruby/blob/78b95b4/parse.y#L7134-L7138 def extract_frozen_string_literal - extract(/\A\s*#\s*#{KEYWORDS[:frozen_string_literal]}:\s*(#{TOKEN})\s*\z/io) + extract(/\A\s*#\s*#{KEYWORDS[:frozen_string_literal]}:\s*#{TOKEN}\s*\z/io) end def extract_shareable_constant_value - extract(/\A\s*#\s*#{KEYWORDS[:shareable_constant_value]}:\s*(#{TOKEN})\s*\z/io) + extract(/\A\s*#\s*#{KEYWORDS[:shareable_constant_value]}:\s*#{TOKEN}\s*\z/io) end def extract_typed - extract(/\A\s*#\s*#{KEYWORDS[:typed]}:\s*(#{TOKEN})\s*\z/io) + extract(/\A\s*#\s*#{KEYWORDS[:typed]}:\s*#{TOKEN}\s*\z/io) end end end diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lib/rubocop/server/cache.rb new/lib/rubocop/server/cache.rb --- old/lib/rubocop/server/cache.rb 2023-09-11 08:27:13.000000000 +0200 +++ new/lib/rubocop/server/cache.rb 2023-10-11 12:49:43.000000000 +0200 @@ -1,5 +1,6 @@ # frozen_string_literal: true +require 'fileutils' require 'pathname' require_relative '../cache_config' require_relative '../config_finder' diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lib/rubocop/version.rb new/lib/rubocop/version.rb --- old/lib/rubocop/version.rb 2023-09-11 08:27:13.000000000 +0200 +++ new/lib/rubocop/version.rb 2023-10-11 12:49:43.000000000 +0200 @@ -3,7 +3,7 @@ module RuboCop # This module holds the RuboCop version information. module Version - STRING = '1.56.3' + STRING = '1.57.0' MSG = '%<version>s (using Parser %<parser_version>s, ' \ 'rubocop-ast %<rubocop_ast_version>s, ' \ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/lib/rubocop.rb new/lib/rubocop.rb --- old/lib/rubocop.rb 2023-09-11 08:27:13.000000000 +0200 +++ new/lib/rubocop.rb 2023-10-11 12:49:43.000000000 +0200 @@ -580,6 +580,7 @@ require_relative 'rubocop/cop/style/redundant_self_assignment' require_relative 'rubocop/cop/style/redundant_self_assignment_branch' require_relative 'rubocop/cop/style/require_order' +require_relative 'rubocop/cop/style/single_line_do_end_block' require_relative 'rubocop/cop/style/sole_nested_conditional' require_relative 'rubocop/cop/style/static_class' require_relative 'rubocop/cop/style/map_compact_with_conditional_block' diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/metadata new/metadata --- old/metadata 2023-09-11 08:27:13.000000000 +0200 +++ new/metadata 2023-10-11 12:49:43.000000000 +0200 @@ -1,16 +1,16 @@ --- !ruby/object:Gem::Specification name: rubocop version: !ruby/object:Gem::Version - version: 1.56.3 + version: 1.57.0 platform: ruby authors: - Bozhidar Batsov - Jonas Arvidsson - Yuji Nakayama -autorequire: +autorequire: bindir: exe cert_chain: [] -date: 2023-09-11 00:00:00.000000000 Z +date: 2023-10-11 00:00:00.000000000 Z dependencies: - !ruby/object:Gem::Dependency name: base64 @@ -74,14 +74,14 @@ requirements: - - ">=" - !ruby/object:Gem::Version - version: 3.2.2.3 + version: 3.2.2.4 type: :runtime prerelease: false version_requirements: !ruby/object:Gem::Requirement requirements: - - ">=" - !ruby/object:Gem::Version - version: 3.2.2.3 + version: 3.2.2.4 - !ruby/object:Gem::Dependency name: rainbow requirement: !ruby/object:Gem::Requirement @@ -895,6 +895,7 @@ - lib/rubocop/cop/style/signal_exception.rb - lib/rubocop/cop/style/single_argument_dig.rb - lib/rubocop/cop/style/single_line_block_params.rb +- lib/rubocop/cop/style/single_line_do_end_block.rb - lib/rubocop/cop/style/single_line_methods.rb - lib/rubocop/cop/style/slicing_with_range.rb - lib/rubocop/cop/style/sole_nested_conditional.rb @@ -1038,10 +1039,10 @@ homepage_uri: https://rubocop.org/ changelog_uri: https://github.com/rubocop/rubocop/blob/master/CHANGELOG.md source_code_uri: https://github.com/rubocop/rubocop/ - documentation_uri: https://docs.rubocop.org/rubocop/1.56/ + documentation_uri: https://docs.rubocop.org/rubocop/1.57/ bug_tracker_uri: https://github.com/rubocop/rubocop/issues rubygems_mfa_required: 'true' -post_install_message: +post_install_message: rdoc_options: [] require_paths: - lib @@ -1056,8 +1057,8 @@ - !ruby/object:Gem::Version version: '0' requirements: [] -rubygems_version: 3.4.6 -signing_key: +rubygems_version: 3.3.7 +signing_key: specification_version: 4 summary: Automatic Ruby code style checking tool. test_files: []