9

In Ruby (and even more so: Rails) it is easy to mark methods as deprecated.

But how can I mark an entire class as deprecated? I want to raise a warning whenever a class is used:

class BillingMethod
end

BillingMethod.new #=> DEPRECATION WARNING: the class BillingMethod is deprecated. Use PaymentMethod instead.

Or when it gets used in inheritance:

class Sofort < BillingMethod
end

Sofort.new #=> DEPRECATION WARNING: the class BillingMethod is deprecated. Use PaymentMethod instead. 

Or, when used in nested classes:

class BillingMethod::Sofort < BillingMethod
end

BillingMethod::Sofort.new #=> DEPRECATION WARNING: the class BillingMethod is deprecated. Use PaymentMethod instead. 

I would think that a class_eval-block would be the place where to stick such a warning. Is that the correct place? Or are there better methods?

Community
  • 1
  • 1
berkes
  • 26,996
  • 27
  • 115
  • 206

3 Answers3

11

You may want to have a look at Deprecate which is part of Ruby's Standard Library:

require 'rubygems'

class BillingMethod
  extend Gem::Deprecate

  class << self
    deprecate :new, "PaymentMethod.new", 2016, 4
  end

  # Will be removed April 2016, use `PaymentMethod.new` instead
  def initialize 
    #...
  end
end

Using the deprecated method would result in a warning like this:

BillingMethod.new
# => NOTE: BillingMethod#new is deprecated; use PaymentMethod.new instead. It will be removed on or after 2016-04-01.
# => BillingMethod#new called from file_name.rb:32.
3limin4t0r
  • 19,353
  • 2
  • 31
  • 52
spickermann
  • 100,941
  • 9
  • 101
  • 131
  • 1
    That will only raise warnings when an object gets initialized. Not when a class is used as parent or used in a nested class tree. Or am I missing an important detail? – berkes Apr 17 '15 at 11:07
  • @berkes You can use the above to deprecate the `inherited` hook (class method), thereby deprecating inheritance: `class BillingMethod; class << self; deprecate :inherited, :none, 2016, 4; end; end`. Inheriting from BillingMethod should now issue the deprecation warning. – Petr Skocik Apr 17 '15 at 11:21
  • The code in the example is wrong. Because `:new` is a class-method, you need to wrap the `extend...deprecate` lines in a `class << self` block. – berkes Apr 17 '15 at 11:54
  • @berkes, I fixed my example. – spickermann Apr 17 '15 at 13:25
5

You can use const_missing to deprecate constants, and, by extension, classes.

const_missing is being invoked when an undefined constant is referenced.

module MyModule

  class PaymentMethod
    # ...
  end

  def self.const_missing(const_name)
    super unless const_name == :BillingMethod
    warn "DEPRECATION WARNING: the class MyModule::BillingMethod is deprecated. Use MyModule::PaymentMethod instead."
    PaymentMethod
  end
end

This allows existing code that references MyModule::BillingMethod to continue to work, and warns the user about their use of the deprecated class.

It's the best I've seen so far for the deprecating class purpose.

Andrey Deineko
  • 51,333
  • 10
  • 112
  • 145
  • In your example, how would `const_missing` be fired, when you've defined it just above? – berkes Apr 17 '15 at 10:38
  • @berkes the first part should not be there, typo – Andrey Deineko Apr 17 '15 at 10:41
  • In the `const_missing` method, what is the `PaymentMethod\n end` exactly achieving there? – berkes Apr 17 '15 at 10:44
  • 1
    `const_missing` is being invoked when a reference is made to an undefined constant in module. It returns a value (`PaymentMethod` in this case) to be used for that constant. – Andrey Deineko Apr 17 '15 at 10:53
  • It seems to me, that the last `end` just before closing the `const_missing` -method is superflous and incorrect. In Ruby 2.1.x it gives a syntax error. – berkes Apr 17 '15 at 10:58
-2

Why not do it this way:

def initialize(*args)
  warn "DEPRECATION WARNING: ..."
  super
end
Gena Shumilkin
  • 713
  • 4
  • 16
  • Author wants to show warning on all class usages (e.g. inheritance), not only new objects creating. – hedgesky Apr 17 '15 at 10:31