Class: Dont

Inherits:
Module
  • Object
show all
Defined in:
lib/dont.rb,
lib/dont/version.rb

Overview

Defines a ‘dont_use` method which can be used to deprecate methods. Whenever the deprecated method is used the specified handler will get triggered.

Examples:


# Register a deprecation handler.
# Anything that responds to `.call(deprecation)` will work.
LOGGER = Logger.new
Dont.register_handler(:logger, ->(deprecation) { LOGGER.warn(deprecation.message) })
class Shouter
  include Dont.new(:logger)

  def shout(msg)
    msg.upcase
  end

  def scream(msg)
    shout(msg)
  end
  dont_use :scream, use: :shout
end

# Logs "DEPRECATED: Don't use Shouter#scream. It's deprecated in favor of
# shout.", before executing the method.
Shouter.new.scream("hello")

# The :exception deprecation handler is provided by default.
# It raises an exception whenever the method is called, which is handy in
# test or development mode.
class Person
  include Dont.new(:exception)

  attr_accessor :firstname
  attr_accessor :first_name

  dont_use :firstname, use: :first_name
end
Person.new.firstname # => fails with Dont::DeprecationError

Defined Under Namespace

Classes: Deprecation

Constant Summary collapse

Error =
Class.new(StandardError)
DeprecationError =
Class.new(Error)
MissingHandlerError =
Class.new(Error)
WithException =
new(:exception)
WithWarn =
new(:warn)
VERSION =
"0.2.2".freeze

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(key) ⇒ Dont

Returns a new instance of Dont.



49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
# File 'lib/dont.rb', line 49

def initialize(key)
  handler = Dont.fetch_handler(key)
  @implementation = ->(old_method, use: nil) {
    # The moment `dont_use` is called in ActiveRecord is before AR defines
    # the attributes in the model. So you get an error when calling
    # instance_method with the regular implementation.
    #
    # This hack determines if it's an ActiveRecord attribute or not, and
    # adapts the code.
    is_ar_attribute = defined?(ActiveRecord::Base) &&
      ancestors.include?(ActiveRecord::Base) &&
      !method_defined?(old_method)

    original = instance_method(old_method) unless is_ar_attribute
    define_method(old_method) do |*args|
      deprecation = Deprecation.new(
        subject: self,
        new_method: use,
        old_method: old_method,
      )
      handler.call(deprecation)
      if is_ar_attribute
        if old_method =~ /=\z/
          attr = old_method.to_s.sub(/=\z/, '')
          public_send(:[]=, attr, *args)
        else
          self[old_method.to_s.sub(/\?\z/, '')]
        end
      else
        original.bind(self).call(*args)
      end
    end
  }
end

Class Method Details

.fetch_handler(key) ⇒ Object



95
96
97
98
99
# File 'lib/dont.rb', line 95

def fetch_handler(key)
  handlers.resolve(key)
rescue Dry::Container::Error => e
  fail MissingHandlerError, e.message
end

.register_handler(key, callable) ⇒ Object



91
92
93
# File 'lib/dont.rb', line 91

def register_handler(key, callable)
  handlers.register(key, callable)
end

Instance Method Details

#included(base) ⇒ Object



84
85
86
87
88
# File 'lib/dont.rb', line 84

def included(base)
  base.instance_exec(@implementation) do |impl|
    define_singleton_method(:dont_use, &impl)
  end
end