有没有一种整洁的方法可以将整个模块标记为已弃用?

时间:2018-06-19 11:51:06

标签: ruby

我有一个ruby类,其中包含很多不再使用的逻辑,但是我需要保持(至少一段时间)以实现向后兼容。

我的计划是将这些方法移至LegacyStuff之类的模块中并将其包含在类中。我想知道是否有一种巧妙的方法来添加一些东西,以便在调用模块中的任何方法时都会生成警告,而不必在每个单独的方法主体中实际添加warn语句。

我猜我正在寻找的是整个模块上的“调用前”或“调用后”钩子这样的行为。我猜这里的子问题是“这甚至是个好主意吗?”

2 个答案:

答案 0 :(得分:4)

虽然这并不是您所要求的(“立即标记所有方法”),并且在ruby本身或大型框架(如rails)中可能存在类似的内容,但对某些人仍然有用。

module DeprecatedMethods
  def deprecated(method_name)
    prepend(Module.new do
      define_method method_name do |*args|
        puts "calling deprecated method #{method_name}"
        super(*args)
      end
    end)
  end

end

module AncientCode
  extend DeprecatedMethods

  deprecated def foo # selectively mark methods as deprecated
    puts "doing foo"
  end

  def bar
    puts "doing bar"
  end
end

class Host
  include AncientCode
end

host = Host.new
host.foo
host.bar
# >> calling deprecated method foo
# >> doing foo
# >> doing bar

当前,这会按不推荐使用的方法注入模块,这很浪费。您可以通过以下操作将所有不赞成使用的方法放在一个模块中:

deprecated_methods :foo, :bar

答案 1 :(得分:2)

代码

首先创建一个包含单个模块方法setup的模块。可以根据需要将此模块放入一个文件中。该模块方法将从包含要包含在给定类中的实例方法的模块中调用。它使用别名修改那些实例方法,以在执行其余代码之前打印一条消息(包含方法名称)。

模块AddMessage

module AddMessage
  def self.setup(mod, msg_pre, msg_post)
    mod.instance_methods(false).
        each do |m|
          am = "_#{m}".to_sym
          mod.send(:alias_method, am, m)
          mod.send(:private, am)
          mod.send(:define_method, m) do |*args, &block|
            puts "%s %s %s" % [msg_pre, m, msg_post] 
            send(am, *args, &block)
          end
        end
  end
end

要包含在类中的模块

module LegacyStuff
  def old1
    "hi"
  end
  def old2(a, b)
    yield(a, b)
  end
  AddMessage.setup(self, "Warning:", "is deprecated")
end

AddMessage::setup传递了三个参数,即调用模块的名称和消息前缀和消息后缀,它们用于形成警告消息。当类实例执行此模块中的实例方法m时,在执行其余计算之前,将打印消息"Warning: #{m} is deprecated"(例如"Warning: old1 is deprecated")。

使用

LegacyStuff仅包含在类中。

class C
  include LegacyStuff
  # <constants, methods and so forth go here>
end

c = C.new
c.old1
  # Warning: old1 is deprecated
  #=> "hi"
c.old2(1,2) { |a,b| a+b }
  # Warning: old2 is deprecated
  #=> 3
c.cat
  #=> NoMethodError: undefined method `cat' for #<C:0x000000008ef0a8>

模块方法AddMessage:setup 的说明

此方法使用以下(通常不太熟悉的)方法:Module#instance_methodsModule#alias_methodModule#privateModule#define_method

对于模块m中定义的每个实例方法mod(例如,数组LegacyStuff.instance_methods(false)的元素)执行以下三个步骤。

mod.send(:alias_method, am, m)

为该方法创建别名am(例如,_:old1old1)。

mod.send(:private, am)

将别名am设为私有方法(例如_old1)。

mod.send(:define_method, m) do |*args, &block| ... end

重新定义方法m(例如old1)以打印指示字符串,然后执行别名am(例如_old1)。