-
Notifications
You must be signed in to change notification settings - Fork 3.2k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Deprecator improvements #2997
Deprecator improvements #2997
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,17 +1,70 @@ | ||
# frozen_string_literal: true | ||
|
||
# Based on Rails ActiveSupport Deprecator | ||
# https://github.com/rails/rails/blob/6f0d1ad14b92b9f5906e44740fce8b4f1c7075dc/activesupport/lib/active_support/deprecation/constant_accessor.rb | ||
# https://github.com/rails/rails/blob/main/activesupport/lib/active_support/deprecation/constant_accessor.rb | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The changes here are mostly documentation and identation. |
||
|
||
# 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 <tt>Faker::NewGenerator</tt>: | ||
# | ||
# 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 <tt>Deprecator</tt> 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 <tt>Faker::Deprecator</tt> still work, they | ||
# evaluate to <tt>Faker::NewGenerator</tt> 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 <tt>assert_deprecated</tt> | ||
# and <tt>assert_not_deprecated</tt> matchers. | ||
# | ||
# There's also a <tt>Faker::Deprecator.skip_warning</tt> 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? | ||
$stdout.puts("DEPRECATION WARNING: #{name}::#{replacement[:old_generator]} is deprecated. Use #{replacement[:new_constant]} instead.") | ||
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] | ||
|
@@ -22,13 +75,25 @@ def const_missing(missing_const_name) | |
|
||
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 } | ||
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 | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
# frozen_string_literal: true | ||
|
||
require_relative '../test_helper' | ||
|
||
class TestFakerDeprecation < Test::Unit::TestCase | ||
def test_using_a_deprecated_generator_returns_a_warning_message | ||
assert_deprecated do | ||
Faker::Dogs.say | ||
end | ||
|
||
assert_equal 'meow', Faker::Dogs.say | ||
end | ||
|
||
def test_using_a_non_deprecated_generator_does_not_return_a_warning_message | ||
assert_not_deprecated do | ||
Faker::Cats.say | ||
end | ||
assert_equal 'meow', Faker::Cats.say | ||
end | ||
|
||
def test_testing_a_deprecated_generator_with_skip_warning_does_not_return_a_warning_message | ||
actual_stdout, actual_stderr = capture_output do | ||
Faker::Deprecator.skip_warning do | ||
Faker::Dogs.say | ||
end | ||
end | ||
|
||
assert_empty(actual_stdout) | ||
assert_empty(actual_stderr) | ||
assert_equal 'meow', Faker::Dogs.say | ||
end | ||
|
||
def test_deprecated_with_skip_warning_does_not_generate_message | ||
Faker::Deprecator.skip_warning do | ||
assert_not_deprecated do | ||
Faker::Dogs.say | ||
end | ||
end | ||
|
||
assert_equal 'meow', Faker::Dogs.say | ||
end | ||
end | ||
|
||
module Faker | ||
class Cats < Base | ||
def self.say | ||
'meow' | ||
end | ||
end | ||
|
||
include Faker::Deprecator | ||
deprecate_generator('Dogs', Cats) | ||
end |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
# frozen_string_literal: true | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Moved this file from test/faker/ to test/faker/support. |
||
|
||
# Based on Rails Testing Deprecator | ||
# https://github.com/rails/rails/blob/main/activesupport/lib/active_support/testing/deprecation.rb | ||
|
||
# Asserts that a matching deprecation warning was emitted during the execution of the yielded block. | ||
# | ||
# assert_deprecated do | ||
# DeprecatedGenerator.generate | ||
# end | ||
# | ||
def assert_deprecated(&block) | ||
warning = with_captured_stdout(&block) | ||
result = yield block | ||
|
||
refute_predicate warning, :empty?, 'Expected a deprecation warning within the block but received none' | ||
|
||
result | ||
end | ||
|
||
# Asserts that no deprecation warnings are emitted during the execution of the yielded block. | ||
# | ||
# assert_not_deprecated do | ||
# Faker::Internet.email | ||
# end | ||
def assert_not_deprecated(&block) | ||
warning = with_captured_stdout(&block) | ||
result = yield block | ||
|
||
assert_predicate warning, :empty?, "Expected no deprecation warning within the block but received a deprecation: #{warning}" | ||
result | ||
end | ||
|
||
def with_captured_stdout(&block) | ||
original_stdout = $stdout | ||
$stdout = StringIO.new | ||
yield block | ||
$stdout.string | ||
ensure | ||
$stdout = original_stdout | ||
end |
This file was deleted.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ruby head was not happy with the old version. This new version works for all Ruby versions in CI.