在Ruby中标记不赞成使用的代码的最佳实践?


127

我想将一个方法标记为不推荐使用,以便使用它的人可以轻松地检查其代码并进行跟踪。在Java中,您设置@Deprecated,每个人都知道这意味着什么。

那么,有没有一种首选的方法(甚至工具)来标记和检查Ruby中的弃用?


公平地讲,Java的注释很烂,因为它没有价值指向潜在的替换对象
Heiko Rupp

Answers:


160

在几乎所有情况下,依靠库或元编程进行过时都是过分的。只需在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

不推荐使用:表示不推荐使用该方法,并将在以后的版本中将其删除。您应该使用它来记录那些公开的方法,但是在下一个主要版本中将被删除。


同样,不要忘记在将来的某个版本(并正确存储)中删除不推荐使用的方法。不要犯与Java库相同的错误。


4
我不确定这与Java部分有太大的“错误”,而是一个巨大的向后兼容性问题(请参阅stackoverflow.com/questions/314540),盲人可能不需要为他的Ruby代码考虑。
VonC

38
代码是一种责任。您维护的代码越少越好。弃用对于暂时的向后兼容性很有用,但是随着时间的流逝,它变得残酷了。如果人们需要使用淘汰的方法,则应改用较旧版本的库。
Ryan McGeary

2
出色的响应。我只是想添加一个链接到我表明我最近使用的方法的反应,这依赖于Ruby的标准库:stackoverflow.com/questions/293981/...
里卡多Valeriano

1
@RicardoValeriano我同意,您的回应应该是综合的(或较高投票,或两者都:))。
费利克斯

53

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.

请注意,使用这种方法,您将获得有关呼叫发生位置的免费信息。


很好,在标准库中对此一无所知。
克里斯(Kris)

2
0数字文字的前导使其变为八进制,因此应将其删除。
马特·惠普尔

3
谢谢你的提示。我弃用了整个班级,并建议使用较新的班级:deprecate :initialize, UseThisClassInstead, 2017, 5
Jon Kern

很好的用法示例,乔恩。真的很好。
里卡多·瓦莱里亚诺

5
先前的正确答案已被弃用,现在应使用Ricardo Valueriano的答案
simon

14

如果您想成为卑鄙的人(出于帮助的目的),则可以在警告期间打印出调用堆栈的第一行,以使开发人员知道他们使用不赞成使用的调用的位置。

这是因为我很确定这会影响性能。

warn Kernel.caller.first + " whatever deprecation message here"

如果使用正确,它将包括文件和使用弃用调用所在行的绝对路径。有关Kernel :: caller的更多信息,请点击此处


5
我不认为这个意思。与必须追逐不赞成使用的调用所在的位置相比,对性能造成的小的影响要好得多,而与最终删除该方法时造成的破坏相比要好得多。
内森·朗

13

使用ActiveSupport:

class Player < ActiveRecord::Base
  def to_s
    ActiveSupport::Deprecation.warn('Use presenter instead')
    partner_uid
  end
end

默认情况下,警告在生产环境中处于关闭状态


12

您也可以这样使用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)

8

您确实有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

该链接将我带到有关Debian软件包的页面。这似乎很相似(如果不一样),是一个RubyGem:rubygems.org/gems/deprecated
Benjamin Oakes

3

您可以使用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



1

我最终提出了一个轻量级的方法:

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

它是声明性的,并提供带有相关信息的日志记录。我不太喜欢Ruby,因此可能需要进行一些调整/ YMMV。


0

我们可以使用内部宏方法。例:

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 oa

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.