From: merch-redmine@... Date: 2017-10-26T00:05:05+00:00 Subject: [ruby-core:83568] [Ruby trunk Feature#14056] Add Module#deprecate_public for deprecation of public methods Issue #14056 has been reported by jeremyevans0 (Jeremy Evans). ---------------------------------------- Feature #14056: Add Module#deprecate_public for deprecation of public methods https://bugs.ruby-lang.org/issues/14056 * Author: jeremyevans0 (Jeremy Evans) * Status: Open * Priority: Normal * Assignee: * Target version: ---------------------------------------- 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: ~~~ruby class MyClass def meth 1 end deprecate_public :meth end MyClass.new.meth # warning: calling private method meth on # \ # 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: 1) It doesn't handle scope visibility, so the following does not work like public/protected/private: ~~~ruby 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. 2) 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. 3) 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. 4) This doesn't currently handle protected methods, but I think changing it to do so isn't too difficult. 5) The method name isn't great, hopefully someone can think of a better one that isn't much longer. ---Files-------------------------------- 0001-Add-Module-deprecate_public-for-deprecation-of-publi.patch (11.1 KB) -- https://bugs.ruby-lang.org/ Unsubscribe: