Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Lint/MissingSuper: exclude method_missing and respond_to_missing? #9072

Merged
merged 2 commits into from
Nov 21, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
* [#9072](https://github.com/rubocop-hq/rubocop/pull/9072): `Lint/MissingSuper`: exclude `method_missing` and `respond_to_missing?`. ([@marcandre][])
1 change: 1 addition & 0 deletions config/default.yml
Original file line number Diff line number Diff line change
Expand Up @@ -1684,6 +1684,7 @@ Lint/MissingSuper:
without calls to `super`'.
Enabled: true
VersionAdded: '0.89'
VersionChanged: '<<next>>'

Lint/MixedRegexpCaptureTypes:
Description: 'Do not mix named captures and numbered captures in a Regexp literal.'
Expand Down
11 changes: 7 additions & 4 deletions lib/rubocop/cop/lint/missing_super.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,11 @@ module Lint
# This cop checks for the presence of constructors and lifecycle callbacks
# without calls to `super`.
#
# This cop does not consider `method_missing` (and `respond_to_missing?`)
# because in some cases it makes sense to overtake what is considered a
# missing method. In other cases, the theoretical ideal handling could be
# challenging or verbose for no actual gain.
#
# @example
# # bad
# class Employee < Person
Expand Down Expand Up @@ -43,15 +48,13 @@ class MissingSuper < Base

STATELESS_CLASSES = %w[BasicObject Object].freeze

OBJECT_LIFECYCLE_CALLBACKS = %i[method_missing respond_to_missing?].freeze
CLASS_LIFECYCLE_CALLBACKS = %i[inherited].freeze
METHOD_LIFECYCLE_CALLBACKS = %i[method_added method_removed method_undefined
singleton_method_added singleton_method_removed
singleton_method_undefined].freeze

CALLBACKS = (OBJECT_LIFECYCLE_CALLBACKS +
CLASS_LIFECYCLE_CALLBACKS +
METHOD_LIFECYCLE_CALLBACKS).to_set.freeze
CALLBACKS = (CLASS_LIFECYCLE_CALLBACKS +
METHOD_LIFECYCLE_CALLBACKS).to_set.freeze

def on_def(node)
return unless offender?(node)
Expand Down
10 changes: 6 additions & 4 deletions spec/project_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
.map(&:cop_name)
end

version_regexp = /\A\d+\.\d+\z|\A<<next>>\z/

describe 'default configuration file' do
subject(:config) { RuboCop::ConfigLoader.load_file('config/default.yml') }

Expand All @@ -32,8 +34,8 @@
version = config[name]['VersionAdded']
expect(version.nil?).to(be(false),
"VersionAdded is required for #{name}.")
expect(version).to(match(/\A\d+\.\d+\z/),
"#{version} should be format ('X.Y') for #{name}.")
expect(version).to(match(version_regexp),
"#{version} should be format ('X.Y' or '<<next>>') for #{name}.")
end
end

Expand All @@ -43,8 +45,8 @@
version = config[name][version_type]
next unless version

expect(version).to(match(/\A\d+\.\d+\z/),
"#{version} should be format ('X.Y') for #{name}.")
expect(version).to(match(version_regexp),
"#{version} should be format ('X.Y' or '<<next>>') for #{name}.")
end
end
end
Expand Down
32 changes: 1 addition & 31 deletions spec/rubocop/cop/lint/missing_super_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -94,41 +94,11 @@ def method_added(*)
RUBY
end

it 'registers an offense for instance level `method_missing?` with no `super` call' do
expect_offense(<<~RUBY)
class Foo
def method_missing(*args)
^^^^^^^^^^^^^^^^^^^^^^^^^ Call `super` to invoke callback defined in the parent class.
end
end
RUBY
end

it 'registers an offense for class level `method_missing?` with no `super` call' do
expect_offense(<<~RUBY)
class Foo
def self.method_missing(*args)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Call `super` to invoke callback defined in the parent class.
end
end
RUBY
end

it 'does not register an offense when `method_missing?` contains `super` call' do
expect_no_offenses(<<~RUBY)
class Foo
def method_missing(*args)
super
do_something
end
end
RUBY
end

it 'does not register an offense when callback has a `super` call' do
expect_no_offenses(<<~RUBY)
class Foo
def self.inherited(base)
do_something
super
end
end
Expand Down