Best practice to mark deprecated code in Ruby?

Viewed 31424

I'd like to mark a method as deprecated, so the people using it can easily check their code and catch up. In Java you set @Deprecated and everybody knows what this means.

So is there a preferred way (or even tools) to mark and check for deprecations in Ruby?

11 Answers

For almost all cases, depending on a library or metaprogramming for a deprecation is overkill. Just add a comment to the rdoc and call the Kernel#warn method. For example:

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

If you're using Yard instead of rdoc, your doc comment should look like this:

# @deprecated Please use {#useful} instead

Lastly, if you adhere to tomdoc, make your comment look like this:

# Deprecated: Please use `useful` instead

Deprecated: Indicates that the method is deprecated and will be removed in a future version. You SHOULD use this to document methods that were Public but will be removed at the next major version.


Also, don't forget to remove the deprecated method in some future (and properly semver'd) release. Don't make the same mistakes that the Java libraries did.

You do have libdeprecated-ruby (2010-2012, not available anymore on rubygem in 2015)

A small library intended to aid developers working with deprecated code.
The idea comes from the 'D' programming language, where developers can mark certain code as deprecated, and then allow/disallow the ability to execute deprecated code.

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

We can use internal macros methods. Example:

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) 

end end

deprecate :a, :get_a deprecate :b, :get_b deprecate :c, :get_c end

o = Foo.new p o.a

Related