From 59ff1ba30d9f4d34b4d478104cc3f453e553c67a Mon Sep 17 00:00:00 2001
From: "yuuji.yaginuma" <yuuji.yaginuma@gmail.com>
Date: Fri, 7 Dec 2018 16:03:18 +0900
Subject: Make `deprecate` work for non-exists methods

Before #33325, `deprecate` works for non-exist methods.
This is necessary, for example, if want to deprecate dynamically defined
methods like attributes methods.

Fixes #34646
---
 .../active_support/deprecation/method_wrappers.rb  | 38 ++++++++++++++--------
 activesupport/test/deprecation_test.rb             |  7 ++++
 2 files changed, 31 insertions(+), 14 deletions(-)

(limited to 'activesupport')

diff --git a/activesupport/lib/active_support/deprecation/method_wrappers.rb b/activesupport/lib/active_support/deprecation/method_wrappers.rb
index 81482092fe..f0c3e37e65 100644
--- a/activesupport/lib/active_support/deprecation/method_wrappers.rb
+++ b/activesupport/lib/active_support/deprecation/method_wrappers.rb
@@ -52,27 +52,37 @@ module ActiveSupport
         options = method_names.extract_options!
         deprecator = options.delete(:deprecator) || self
         method_names += options.keys
+        mod = Module.new
 
         method_names.each do |method_name|
-          aliased_method, punctuation = method_name.to_s.sub(/([?!=])$/, ""), $1
-          with_method = "#{aliased_method}_with_deprecation#{punctuation}"
-          without_method = "#{aliased_method}_without_deprecation#{punctuation}"
+          if target_module.method_defined?(method_name) || target_module.private_method_defined?(method_name)
+            aliased_method, punctuation = method_name.to_s.sub(/([?!=])$/, ""), $1
+            with_method = "#{aliased_method}_with_deprecation#{punctuation}"
+            without_method = "#{aliased_method}_without_deprecation#{punctuation}"
 
-          target_module.send(:define_method, with_method) do |*args, &block|
-            deprecator.deprecation_warning(method_name, options[method_name])
-            send(without_method, *args, &block)
-          end
+            target_module.send(:define_method, with_method) do |*args, &block|
+              deprecator.deprecation_warning(method_name, options[method_name])
+              send(without_method, *args, &block)
+            end
 
-          target_module.send(:alias_method, without_method, method_name)
-          target_module.send(:alias_method, method_name, with_method)
+            target_module.send(:alias_method, without_method, method_name)
+            target_module.send(:alias_method, method_name, with_method)
 
-          case
-          when target_module.protected_method_defined?(without_method)
-            target_module.send(:protected, method_name)
-          when target_module.private_method_defined?(without_method)
-            target_module.send(:private, method_name)
+            case
+            when target_module.protected_method_defined?(without_method)
+              target_module.send(:protected, method_name)
+            when target_module.private_method_defined?(without_method)
+              target_module.send(:private, method_name)
+            end
+          else
+            mod.send(:define_method, method_name) do |*args, &block|
+              deprecator.deprecation_warning(method_name, options[method_name])
+              super(*args, &block)
+            end
           end
         end
+
+        target_module.prepend(mod) unless mod.instance_methods(false).empty?
       end
     end
   end
diff --git a/activesupport/test/deprecation_test.rb b/activesupport/test/deprecation_test.rb
index 105153584d..95e7174391 100644
--- a/activesupport/test/deprecation_test.rb
+++ b/activesupport/test/deprecation_test.rb
@@ -31,6 +31,9 @@ class Deprecatee
   def f=(v); end
   deprecate :f=
 
+  deprecate :g
+  def g ;end
+
   module B
     C = 1
   end
@@ -425,6 +428,10 @@ class DeprecationTest < ActiveSupport::TestCase
     end
   end
 
+  def test_deprecate_work_before_define_method
+    assert_deprecated { @dtc.g }
+  end
+
   private
     def deprecator_with_messages
       klass = Class.new(ActiveSupport::Deprecation)
-- 
cgit v1.2.3