在Ruby中弃用旧的模块名称?

时间:2018-06-27 16:38:16

标签: ruby

如何最好地以向后兼容的方式重命名Ruby模块?我有ActiveSupport,因此可以通过这种方式调用弃用警告,但是在这种情况下,我弃用了旧的模块名称,而不是方法名称。

示例如下:

module OldName
  def self.method1
    ...
  end
end

将成为:

module NewName
  def self.method1
    ...
  end
end

我想生成警告,指示开发人员使用NewName::method1而不是OldName::method1

有什么建议吗?

5 个答案:

答案 0 :(得分:2)

ActiveSupport提供了两种弃用常量的方法:DeprecatedConstantAccessorDeprecatedConstantProxy。它们在显示警告的时间(访问器是在访问它的时候;代理是在其方法被调用时)以及它们通常如何行为方面的取舍和限制。您可能想要同时尝试这两种方法,看看哪种方法适合您的用例。

答案 1 :(得分:2)

Rails 4.1.8 Ruby 2.2.0p0

module Fred
  extend self
  def aaa; end
  def bbb; end
  def ccc; end
  def ddd; end
  def eee; end
end

module Bar
  extend self
  def ccc; end
end


ActiveSupport::Deprecation.deprecate_methods(Fred, :aaa, bbb: :zzz, ccc: 'use Bar#ccc instead')


Fred.aaa
DEPRECATION WARNING: aaa is deprecated and will be removed from Rails 4.2. (called from __pry__ at (pry):15)
=> nil

在Rails 5.2.0中尝试了相同的代码,但没有 DEPRECATION WARNING

Rails 5.2.0 Ruby 2.5.1p57

class Fred
 def aaa; end
 def bbb; end
 def ccc; end
 def ddd; end
 def eee; end
end

class Bar
 def ccc; end
end

ActiveSupport::Deprecation.deprecate_methods(Fred, :aaa, bbb: :zzz, ccc: 'use Bar#ccc instead')

> Fred.new.aaa
DEPRECATION WARNING: aaa is deprecated and will be removed from Rails 6.0 (called from irb_binding at (irb):13)
 => nil 

答案 2 :(得分:1)

您可以使用类似的内容:

module Bar
  def self.aaa
    'Bar::aaa'
  end

  def baz
    'Bar#baz'
  end
end 

module Foo
  {included: :include,extended: :extend,prepended: :prepend}.each do |mod_method, called_method| 
    singleton_class.define_method(mod_method) do |base|
      warn "Foo is deprecated please use Bar instead"
      base.send(called_method,Bar) 
    end
  end
  def self.method_missing(meth,*args,&block)
    warn "Foo is deprecated please use Bar instead"
    Bar.respond_to?(meth) ? Bar.send(meth,*args,&block) : super
  end
end

class A 
  include Foo # this will throw a warning
end

然后

Foo.aaa
# Foo is deprecated please use Bar instead
#=> 'Bar::aaa'

A.new.baz  
#=> 'Bar#baz'

答案 3 :(得分:0)

module OldName
  def instance_method(*args)
    yield(args)
  end

  instance_methods.each do |im|
    alias_name = "_#{im.to_s}"
    alias_method alias_name, im
    define_method(im) do |*args, &block|
      warn "Foo is deprecated please use Bar instead"
      public_send(alias_name, *args, &block)
    end
  end
end

class C
  include OldName
end

C.instance_methods && [:im, :_im]
  #=> [:im, :_im]

c = C.new
c._instance_method(2,3) { |a,b| a+b }
  #=> 5
c.instance_method(2,3) { |a,b| a+b }
  # Foo is deprecated please use Bar instead
  #=> 5

或者,public_send(alias_name, *args, &block)可以替换为method(alias_name).call(*args, &block)

答案 4 :(得分:0)

我被修补的宝石中的一个错误所困扰,这导致了一些错误的开始,但是最终答案非常简单,我将工作代码作为其他示例的例子:

require 'active_support'

OldName = ActiveSupport::Deprecation::DeprecatedConstantProxy.new('OldName', 'NewName')

module NewName
  def self.method1
    puts 'Hello World!'
  end
end


NewName.method1
  #=> Hello World!

OldName.method1
  #=> DEPRECATION WARNING: OldName is deprecated! Use NewName instead. (called from ..)
  #=> Hello World!

简单!

感谢@matthewd向我指出了正确的方向。