# frozen_string_literal: true
# Based on Rails ActiveSupport Deprecator
# https://github.com/rails/rails/blob/main/activesupport/lib/active_support/deprecation/constant_accessor.rb
# rubocop:disable Style/ClassVars
module Faker
# Provides a way to rename generators, including their namespaces, with a deprecation cycle in which
# both the old and new names work, but using the old one prints a deprecation message.
#
# Deprecator provides a deprecate_generator method to be used when
# renaming a generator. For example, let's say we want to change the following Generator's
# name to Faker::NewGenerator:
#
# module Faker
# class Generator
# def self.generate
# "be kind"
# end
# end
# end
#
# To rename it, you need to do the update the name and declare the deprecation by
# including the Deprecator module and using the deprecate_generator method:
#
# module Faker
# class NewGenerator
# def self.generate
# "be kind"
# end
# end
#
# include Deprecator
# deprecate_generator('DeprecatedGenerator', NewGenerator)
# end
#
# The first argument is a constant name (no colons) as a string. It is the name of
# the constant you want to deprecate.
#
# The second argument is the constant path of the replacement (no colons) as a constant.
#
# For this to work, a +const_missing+ hook is installed. When users
# reference the deprecated constant, the callback prints the
# message and constantizes the replacement.
#
# With that in place, references to Faker::Deprecator still work, they
# evaluate to Faker::NewGenerator now, and trigger a deprecation warning:
#
# Faker::Generator.generate
# # DEPRECATION WARNING: Faker::Generator is deprecated. Use Faker::NewGenerator instead
# # "be kind"
#
# For testing the deprecations, we provide assert_deprecated
# and assert_not_deprecated matchers.
#
# There's also a Faker::Deprecator.skip_warning helper to silence
# the deprecation messages in the *test* output. Use it for generators that have lots of tests
# to avoid too many noise when running the tests.
module Deprecator
def self.included(base)
extension = Module.new do
def const_missing(missing_const_name)
if class_variable_defined?(:@@_deprecated_constants) && (replacement = class_variable_get(:@@_deprecated_constants)[missing_const_name.to_s])
unless Faker::Deprecator.skip_warning?
deprecated_message = "#{name}::#{replacement[:old_generator]} is deprecated."
replacement_message = "Use #{replacement[:new_constant]} instead."
$stdout.puts("DEPRECATION WARNING: #{deprecated_message} #{replacement_message}")
end
return replacement[:new_constant]
end
super
end
def deprecate_generator(old_generator_name, new_generator_constant)
class_variable_set(:@@_deprecated_constants, {}) unless class_variable_defined?(:@@_deprecated_constants)
class_variable_get(:@@_deprecated_constants)[old_generator_name] = {
new_constant: new_generator_constant,
old_generator: old_generator_name
}
end
end
base.singleton_class.prepend extension
end
# Silence deprecation warnings within the block.
#
# Faker::Generator.generate
# # => DEPRECATION WARNING: Faker::Generator is deprecated. Use Faker::NewGenerator instead.
#
# Faker::Deprecator.skip_warning do
# Faker::Generator.generate
# end
# # => nil
def self.skip_warning
original = Faker::Deprecator.skip
Faker::Deprecator.skip = true
yield
ensure
Faker::Deprecator.skip = original
end
def self.skip_warning?
skip == true
end
def self.skip
@skip ||= false
end
def self.skip=(value)
@skip = value
end
end
end
# rubocop:enable Style/ClassVars