【发布时间】:2008-11-16 15:20:13
【问题描述】:
我想将一个方法标记为已弃用,以便使用它的人可以轻松检查他们的代码并赶上进度。在 Java 中,你设置了@Deprecated,每个人都知道这是什么意思。
那么在 Ruby 中是否有首选的方法(甚至工具)来标记和检查弃用?
【问题讨论】:
-
公平地说,Java 的注解很烂,因为它没有任何价值指向潜在的替代品
标签: ruby deprecated
我想将一个方法标记为已弃用,以便使用它的人可以轻松检查他们的代码并赶上进度。在 Java 中,你设置了@Deprecated,每个人都知道这是什么意思。
那么在 Ruby 中是否有首选的方法(甚至工具)来标记和检查弃用?
【问题讨论】:
标签: ruby deprecated
对于几乎所有情况,依赖于库或元编程来弃用是过分的。只需在 rdoc 中添加注释并调用 Kernel#warn 方法。例如:
class Foo
# <b>DEPRECATED:</b> Please use <tt>useful</tt> instead.
def useless
warn "[DEPRECATION] `useless` is deprecated. Please use `useful` instead."
useful
end
def useful
# ...
end
end
如果您使用的是Yard 而不是rdoc,您的文档注释应如下所示:
# @deprecated Please use {#useful} instead
最后,如果你坚持tomdoc,请让你的评论看起来像这样:
# Deprecated: Please use `useful` instead
已弃用:表示该方法已弃用,将在未来版本中删除。您应该使用它来记录公开但将在下一个主要版本中删除的方法。
另外,不要忘记在将来的某个版本(以及正确的semver'd)版本中删除已弃用的方法。不要犯与 Java 库一样的错误。
【讨论】:
Ruby 标准库有一个带有警告逻辑的模块:https://ruby-doc.org/stdlib/libdoc/rubygems/rdoc/Gem/Deprecate.html。我倾向于以“标准”方式维护我的弃用消息:
# my_file.rb
class MyFile
extend Gem::Deprecate
def no_more
close
end
deprecate :no_more, :close, 2015, 5
def close
# new logic here
end
end
MyFile.new.no_more
# => NOTE: MyFile#no_more is deprecated; use close instead. It will be removed on or after 2015-05-01.
# => MyFile#no_more called from my_file.rb:16.
请注意,通过这种方法,您将免费获得有关通话地点的信息。
【讨论】:
0 使其成为八进制,因此应该删除。
deprecate :initialize, UseThisClassInstead, 2017, 5
使用 ActiveSupport:
class Player < ActiveRecord::Base
def to_s
ActiveSupport::Deprecation.warn('Use presenter instead')
partner_uid
end
end
生产环境默认关闭警告
【讨论】:
如果您想变得刻薄(以提供帮助为幌子),您可以在警告期间打印出调用堆栈的第一行,让开发人员知道他们在哪里使用了已弃用的调用。
这很刻薄,因为我很确定这会影响性能。
warn Kernel.caller.first + " whatever deprecation message here"
如果使用正确,这将包括文件的绝对路径和使用过时调用的行。有关 Kernel::caller 的更多信息,请访问here
【讨论】:
您也可以使用ActiveSupport::Deprecation(4.0+ 版本提供),例如:
require 'active_support/deprecation'
require 'active_support/core_ext/module/deprecation'
class MyGem
def self.deprecator
ActiveSupport::Deprecation.new('2.0', 'MyGem')
end
def old_method
end
def new_method
end
deprecate old_method: :new_method, deprecator: deprecator
end
MyGem.new.old_method
# => DEPRECATION WARNING: old_method is deprecated and will be removed from MyGem 2.0 (use new_method instead). (called from <main> at file.rb:18)
【讨论】:
您确实有 libdeprecated-ruby(2010-2012,2015 年不再在 rubygem 上提供)
一个小型库,旨在帮助开发人员处理已弃用的代码。
这个想法来自“D”编程语言,开发人员可以在其中将某些代码标记为已弃用,然后允许/禁止执行已弃用代码的能力。
require 'lib/deprecated.rb'
require 'test/unit'
# this class is used to test the deprecate functionality
class DummyClass
def monkey
return true
end
deprecate :monkey
end
# we want exceptions for testing here.
Deprecate.set_action(:throw)
class DeprecateTest < Test::Unit::TestCase
def test_set_action
assert_raise(DeprecatedError) { raise StandardError.new unless DummyClass.new.monkey }
Deprecate.set_action(proc { |msg| raise DeprecatedError.new("#{msg} is deprecated.") })
assert_raise(DeprecatedError) { raise StandardError.new unless DummyClass.new.monkey }
# set to warn and make sure our return values are getting through.
Deprecate.set_action(:warn)
assert_nothing_raised(DeprecatedError) { raise StandardError.new unless DummyClass.new.monkey }
end
end
【讨论】:
您可以使用 Class Macros 模式并编写如下内容:
class Module
def deprecate(old_method, new_method)
define_method(old_method) do |*args, &block|
warn "Method #{old_method}() depricated. Use #{new_method}() instead"
send(new_method, *args, &block)
end
end
end
class Test
def my_new_method
p "My method"
end
deprecate :my_old_method, :my_method
end
【讨论】:
使用 Rails 时,您有 Module#deprecate 方法。
【讨论】:
我最终拼凑出一个轻量级的方法:
def deprecate(msg)
method = caller_locations(1, 1).first.label
source = caller(2, 1).first
warn "#{method} is deprecated: #{msg}\ncalled at #{source}"
end
然后要弃用方法,在方法主体(或类的构造函数)中插入调用
def foo
deprecate 'prefer bar, will be removed in version 3'
...
end
它具有相当的声明性,并提供相关信息的日志记录。我不是一个 Rubyist,所以它可能需要一些调整/YMMV。
【讨论】:
我们可以使用内部宏方法。 示例:
class Foo
def get_a; puts "I'm an A" end
def get_b; puts "I'm an B" end
def get_c; puts "I'm an C" end
def self.deprecate(old_method, new_method)
define_method(old_method) do |*args, &block|
puts "Warning: #{old_method} is deprecated! Use #{new_method} instead"
send(new_method, *args, &block)
结束 结束
弃用 :a, :get_a 弃用 :b, :get_b 弃用 :c, :get_c 结束
o = Foo.new p o.a
【讨论】: