From 889bf7c64e51c29206c6b523d8305fc7956bac14 Mon Sep 17 00:00:00 2001 From: Andrei Eres Date: Thu, 22 Apr 2021 21:49:11 +0300 Subject: [PATCH 1/3] Refactor DeprecatedClassMethods to split deprecated and replacement objects --- .../cop/lint/deprecated_class_methods.rb | 99 +++++++++++-------- 1 file changed, 60 insertions(+), 39 deletions(-) diff --git a/lib/rubocop/cop/lint/deprecated_class_methods.rb b/lib/rubocop/cop/lint/deprecated_class_methods.rb index 0fccf7aa8c8..cc5b6b977e2 100644 --- a/lib/rubocop/cop/lint/deprecated_class_methods.rb +++ b/lib/rubocop/cop/lint/deprecated_class_methods.rb @@ -24,16 +24,15 @@ class DeprecatedClassMethods < Base extend AutoCorrector # Inner class to DeprecatedClassMethods. - # This class exists to add abstraction and clean naming to the - # objects that are going to be operated on. + # This class exists to add abstraction and clean naming + # to the deprecated objects class DeprecatedClassMethod include RuboCop::AST::Sexp - attr_reader :class_constant, :deprecated_method, :replacement_method + attr_reader :method, :class_constant - def initialize(deprecated:, replacement:, class_constant: nil) - @deprecated_method = deprecated - @replacement_method = replacement + def initialize(method, class_constant: nil) + @method = method @class_constant = class_constant end @@ -48,28 +47,62 @@ def class_nodes [nil] end end + + def to_s + [class_constant, method].compact.join(delimeter) + end + + private + + def delimeter + CLASS_METHOD_DELIMETER + end + end + + # Inner class to DeprecatedClassMethods. + # This class exists to add abstraction and clean naming + # to the replacements for deprecated objects + class Replacement + attr_reader :method, :class_constant + + def initialize(method, class_constant: nil) + @method = method + @class_constant = class_constant + end + + def to_s + [class_constant, method].compact.join(delimeter) + end + + private + + def delimeter + CLASS_METHOD_DELIMETER + end end MSG = '`%s` is deprecated in favor of `%s`.' - DEPRECATED_METHODS_OBJECT = [ - DeprecatedClassMethod.new(deprecated: :exists?, - replacement: :exist?, - class_constant: :File), - DeprecatedClassMethod.new(deprecated: :exists?, - replacement: :exist?, - class_constant: :Dir), - DeprecatedClassMethod.new(deprecated: :iterator?, replacement: :block_given?) - ].freeze - - RESTRICT_ON_SEND = DEPRECATED_METHODS_OBJECT.map(&:deprecated_method).freeze + + DEPRECATED_METHODS_OBJECT = { + DeprecatedClassMethod.new(:exists?, class_constant: :File) => + Replacement.new(:exist?, class_constant: :File), + + DeprecatedClassMethod.new(:exists?, class_constant: :Dir) => + Replacement.new(:exist?, class_constant: :Dir), + + DeprecatedClassMethod.new(:iterator?) => Replacement.new(:block_given?) + }.freeze + + RESTRICT_ON_SEND = DEPRECATED_METHODS_OBJECT.keys.map(&:method).freeze + + CLASS_METHOD_DELIMETER = '.' def on_send(node) - check(node) do |data| - message = format(MSG, current: deprecated_method(data), - prefer: replacement_method(data)) + check(node) do |deprecated| + message = format(MSG, current: deprecated, prefer: replacement(deprecated)) add_offense(node.loc.selector, message: message) do |corrector| - corrector.replace(node.loc.selector, data.replacement_method.to_s) + corrector.replace(node.loc.selector, replacement(deprecated).method) end end end @@ -77,28 +110,16 @@ def on_send(node) private def check(node) - DEPRECATED_METHODS_OBJECT.each do |data| - next unless data.class_nodes.include?(node.receiver) - next unless node.method?(data.deprecated_method) + DEPRECATED_METHODS_OBJECT.each_key do |deprecated| + next unless deprecated.class_nodes.include?(node.receiver) + next unless node.method?(deprecated.method) - yield data + yield deprecated end end - def deprecated_method(data) - method_call(data.class_constant, data.deprecated_method) - end - - def replacement_method(data) - method_call(data.class_constant, data.replacement_method) - end - - def method_call(class_constant, method) - if class_constant - format('%s.%s', constant: class_constant, method: method) - else - format('%s', method: method) - end + def replacement(deprecated) + DEPRECATED_METHODS_OBJECT[deprecated] end end end From 51379b8d15f7fa520026a54abab730e934743601 Mon Sep 17 00:00:00 2001 From: Andrei Eres Date: Thu, 22 Apr 2021 22:08:51 +0300 Subject: [PATCH 2/3] Support deprecated Socket.gethostbyaddr and Socket.gethostbyname --- .../cop/lint/deprecated_class_methods.rb | 29 +++++++++-- .../cop/lint/deprecated_class_methods_spec.rb | 48 +++++++++++++++++++ 2 files changed, 72 insertions(+), 5 deletions(-) diff --git a/lib/rubocop/cop/lint/deprecated_class_methods.rb b/lib/rubocop/cop/lint/deprecated_class_methods.rb index cc5b6b977e2..67240755c22 100644 --- a/lib/rubocop/cop/lint/deprecated_class_methods.rb +++ b/lib/rubocop/cop/lint/deprecated_class_methods.rb @@ -31,9 +31,10 @@ class DeprecatedClassMethod attr_reader :method, :class_constant - def initialize(method, class_constant: nil) + def initialize(method, class_constant: nil, correctable: true) @method = method @class_constant = class_constant + @correctable = correctable end def class_nodes @@ -48,6 +49,10 @@ def class_nodes end end + def correctable? + @correctable + end + def to_s [class_constant, method].compact.join(delimeter) end @@ -65,9 +70,10 @@ def delimeter class Replacement attr_reader :method, :class_constant - def initialize(method, class_constant: nil) + def initialize(method, class_constant: nil, instance_method: false) @method = method @class_constant = class_constant + @instance_method = instance_method end def to_s @@ -77,7 +83,11 @@ def to_s private def delimeter - CLASS_METHOD_DELIMETER + instance_method? ? INSTANCE_METHOD_DELIMETER : CLASS_METHOD_DELIMETER + end + + def instance_method? + @instance_method end end @@ -90,19 +100,28 @@ def delimeter DeprecatedClassMethod.new(:exists?, class_constant: :Dir) => Replacement.new(:exist?, class_constant: :Dir), - DeprecatedClassMethod.new(:iterator?) => Replacement.new(:block_given?) + DeprecatedClassMethod.new(:iterator?) => Replacement.new(:block_given?), + + DeprecatedClassMethod.new(:gethostbyaddr, class_constant: :Socket, correctable: false) => + Replacement.new(:getnameinfo, class_constant: :Addrinfo, instance_method: true), + + DeprecatedClassMethod.new(:gethostbyname, class_constant: :Socket, correctable: false) => + Replacement.new(:getaddrinfo, class_constant: :Addrinfo, instance_method: true) }.freeze RESTRICT_ON_SEND = DEPRECATED_METHODS_OBJECT.keys.map(&:method).freeze CLASS_METHOD_DELIMETER = '.' + INSTANCE_METHOD_DELIMETER = '#' def on_send(node) check(node) do |deprecated| message = format(MSG, current: deprecated, prefer: replacement(deprecated)) add_offense(node.loc.selector, message: message) do |corrector| - corrector.replace(node.loc.selector, replacement(deprecated).method) + if deprecated.correctable? + corrector.replace(node.loc.selector, replacement(deprecated).method) + end end end end diff --git a/spec/rubocop/cop/lint/deprecated_class_methods_spec.rb b/spec/rubocop/cop/lint/deprecated_class_methods_spec.rb index f25b4804b62..5578cbcb935 100644 --- a/spec/rubocop/cop/lint/deprecated_class_methods_spec.rb +++ b/spec/rubocop/cop/lint/deprecated_class_methods_spec.rb @@ -81,4 +81,52 @@ expect_no_offenses('Foo.iterator?') end end + + context 'prefer `Addrinfo#getnameinfo` over `Socket.gethostbyaddr`' do + it 'registers an offense for Socket.gethostbyaddr' do + expect_offense(<<~RUBY) + Socket.gethostbyaddr([221,186,184,68].pack("CCCC")) + ^^^^^^^^^^^^^ `Socket.gethostbyaddr` is deprecated in favor of `Addrinfo#getnameinfo`. + RUBY + + expect_no_corrections + end + + it 'registers an offense for ::Socket.gethostbyaddr' do + expect_offense(<<~RUBY) + ::Socket.gethostbyaddr([221,186,184,68].pack("CCCC")) + ^^^^^^^^^^^^^ `Socket.gethostbyaddr` is deprecated in favor of `Addrinfo#getnameinfo`. + RUBY + + expect_no_corrections + end + + it 'does not register an offense for method `gethostbyaddr` on other receivers' do + expect_no_offenses('Foo.gethostbyaddr') + end + end + + context 'prefer `Addrinfo#getaddrinfo` over `Socket.gethostbyname`' do + it 'registers an offense for Socket.gethostbyname' do + expect_offense(<<~RUBY) + Socket.gethostbyname("hal") + ^^^^^^^^^^^^^ `Socket.gethostbyname` is deprecated in favor of `Addrinfo#getaddrinfo`. + RUBY + + expect_no_corrections + end + + it 'registers an offense for ::Socket.gethostbyname' do + expect_offense(<<~RUBY) + ::Socket.gethostbyname("hal") + ^^^^^^^^^^^^^ `Socket.gethostbyname` is deprecated in favor of `Addrinfo#getaddrinfo`. + RUBY + + expect_no_corrections + end + + it 'does not register an offense for method `gethostbyname` on other receivers' do + expect_no_offenses('Foo.gethostbyname') + end + end end From 91f34069a7d08964f2615f6e78a9bdcf76801dc3 Mon Sep 17 00:00:00 2001 From: Andrei Eres Date: Fri, 23 Apr 2021 15:31:42 +0300 Subject: [PATCH 3/3] Add changelog --- changelog/fix_support_deprecated_socket.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 changelog/fix_support_deprecated_socket.md diff --git a/changelog/fix_support_deprecated_socket.md b/changelog/fix_support_deprecated_socket.md new file mode 100644 index 00000000000..cbf0c182077 --- /dev/null +++ b/changelog/fix_support_deprecated_socket.md @@ -0,0 +1 @@ +* [#9732](https://github.com/rubocop/rubocop/pull/9732): Support deprecated Socket.gethostbyaddr and Socket.gethostbyname. ([@AndreiEres][])