Feature #14056
closedAdd Module#deprecate_public for deprecation of public methods
Description
The attached patch allows you to make a method private, but have
calling it publicly (either directly or via public_send) emit a
warning instead of raising a NoMethodError.
This is mostly useful in library development, where you want to
continue using a method internally, and you want to disallow external
use, but you want existing external users who are using the method to
receive a warning during a deprecation period instead of breaking their
code immediately.
I believe this feature is not possible without modifying the VM
(as the patch does). You can emit a deprecation message inside the
method, but I don't believe you can make it conditional on whether the
method was called publicly or privately, as that information isn't exposed.
Use is similar to public/protected/private when called with arguments:
class MyClass
def meth
1
end
deprecate_public :meth
end
MyClass.new.meth
# warning: calling private method meth on #<MyClass:0x00001c896dfb1a90> \
# via deprecated public interface
# => 1
Module#deprecate_public makes the method private, but sets a flag on
the method entry that it is deprecated, and if calling the method would
usually raise a NoMethodError due to visibility, instead a warning is
printed and then method call works as if it were declared public.
There are some issues with this implementation of deprecate_public:
- It doesn't handle scope visibility, so the following
does not work like public/protected/private:
class MyClass
deprecate_public
def meth
1
end
end
Currently, this deprecate_public call would do nothing
as no arguments were given. It's probably possible to
handle scope visibility as well, but it would require
additional internal changes.
-
It is rather inefficient, as it first exports the method
in the module as public and then private, before setting
the deprecation flag. However, this method is not likely
to be a bottleneck in any reasonable code. It was done this
way to reuse the most existing code and still ensure that
methods will be setup in the class itself and that method
caches will be cleared appropriately. -
When public_send is used, this does not print the receiver
of the public_send method, instead it prints the module
that used the deprecate_public call. I'm not sure whether
the calling information is available from rb_method_call_status,
or how to access it if it is available. -
This doesn't currently handle protected methods, but I
think changing it to do so isn't too difficult. -
The method name isn't great, hopefully someone can think of
a better one that isn't much longer.
Files