From ae682c0bb583d8912f07fd922dde544cf424dd0c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?fn=20=E2=8C=83=20=E2=8C=A5?= <70830482+FnControlOption@users.noreply.github.com> Date: Fri, 2 Sep 2022 17:23:14 -0700 Subject: [PATCH] Add autocorrect for `Style/StaticClass` --- ..._add_autocorrect_for_style_static_class.md | 1 + lib/rubocop/cop/style/static_class.rb | 33 +++++++++++++++- spec/rubocop/cop/style/static_class_spec.rb | 39 +++++++++++++++++++ 3 files changed, 72 insertions(+), 1 deletion(-) create mode 100644 changelog/new_add_autocorrect_for_style_static_class.md diff --git a/changelog/new_add_autocorrect_for_style_static_class.md b/changelog/new_add_autocorrect_for_style_static_class.md new file mode 100644 index 00000000000..ea6e2ae69bf --- /dev/null +++ b/changelog/new_add_autocorrect_for_style_static_class.md @@ -0,0 +1 @@ +* Add autocorrect for `Style/StaticClass`. ([@FnControlOption][]) diff --git a/lib/rubocop/cop/style/static_class.rb b/lib/rubocop/cop/style/static_class.rb index 446b90f5f3a..2cdaa99824c 100644 --- a/lib/rubocop/cop/style/static_class.rb +++ b/lib/rubocop/cop/style/static_class.rb @@ -44,18 +44,49 @@ module Style # end # class StaticClass < Base + include RangeHelp include VisibilityHelp + extend AutoCorrector MSG = 'Prefer modules to classes with only class methods.' def on_class(class_node) return if class_node.parent_class + return unless class_convertible_to_module?(class_node) - add_offense(class_node) if class_convertible_to_module?(class_node) + add_offense(class_node) do |corrector| + autocorrect(corrector, class_node) + end end private + def autocorrect(corrector, class_node) + corrector.replace(class_node.loc.keyword, 'module') + corrector.insert_after(class_node.loc.name, "\nmodule_function\n") + + class_elements(class_node).each do |node| + if node.defs_type? + autocorrect_def(corrector, node) + elsif node.sclass_type? + autocorrect_sclass(corrector, node) + end + end + end + + def autocorrect_def(corrector, node) + corrector.remove( + range_between(node.receiver.source_range.begin_pos, node.loc.name.begin_pos) + ) + end + + def autocorrect_sclass(corrector, node) + corrector.remove( + range_between(node.loc.keyword.begin_pos, node.identifier.source_range.end_pos) + ) + corrector.remove(node.loc.end) + end + def class_convertible_to_module?(class_node) nodes = class_elements(class_node) return false if nodes.empty? diff --git a/spec/rubocop/cop/style/static_class_spec.rb b/spec/rubocop/cop/style/static_class_spec.rb index 26cab4e0a16..0ffb33ec0d4 100644 --- a/spec/rubocop/cop/style/static_class_spec.rb +++ b/spec/rubocop/cop/style/static_class_spec.rb @@ -8,6 +8,14 @@ class C def self.class_method; end end RUBY + + expect_correction(<<~RUBY) + module C + module_function + + def class_method; end + end + RUBY end it 'registers an offense when class has `class << self` with class methods' do @@ -21,6 +29,18 @@ def other_class_method; end end end RUBY + + expect_correction(<<~RUBY) + module C + module_function + + def class_method; end + + #{trailing_whitespace} + def other_class_method; end + #{trailing_whitespace} + end + RUBY end it 'does not register an offense when class has `class << self` with macro calls' do @@ -44,6 +64,16 @@ class C def self.class_method; end end RUBY + + expect_correction(<<~RUBY) + module C + module_function + + CONST = 1 + + def class_method; end + end + RUBY end it 'does not register an offense when class has instance method' do @@ -103,6 +133,15 @@ class C def self.class_method; end end RUBY + + expect_correction(<<~RUBY) + module C + module_function + + extend M + def class_method; end + end + RUBY end it 'does not register an offense for modules' do