Skip to content
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

Merged
merged 2 commits into from
Sep 12, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ source 'https://rubygems.org'
gemspec

gem 'benchmark'
gem 'minitest', '5.25.0'
gem 'minitest', '5.25.1'
Copy link
Contributor Author

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.

gem 'pry', '0.14.2'
gem 'rake', '13.2.1'
gem 'rubocop', '1.65.1'
Expand Down
4 changes: 2 additions & 2 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ GEM
json (2.7.2)
language_server-protocol (3.17.0.3)
method_source (1.0.0)
minitest (5.25.0)
minitest (5.25.1)
parallel (1.25.1)
parser (3.3.4.0)
ast (~> 2.4.1)
Expand Down Expand Up @@ -71,7 +71,7 @@ PLATFORMS
DEPENDENCIES
benchmark
faker!
minitest (= 5.25.0)
minitest (= 5.25.1)
pry (= 0.14.2)
rake (= 13.2.1)
rubocop (= 1.65.1)
Expand Down
71 changes: 68 additions & 3 deletions lib/helpers/deprecator.rb
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
Copy link
Contributor Author

Choose a reason for hiding this comment

The 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]
Expand All @@ -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
Expand Down
53 changes: 53 additions & 0 deletions test/helpers/test_faker_deprecator.rb
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
41 changes: 41 additions & 0 deletions test/support/deprecation.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# frozen_string_literal: true
Copy link
Contributor Author

Choose a reason for hiding this comment

The 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
23 changes: 0 additions & 23 deletions test/test_faker_deprecator.rb

This file was deleted.

1 change: 1 addition & 0 deletions test/test_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

require_relative 'support/assert_not_english'
require_relative 'support/assert_email_regex'
require_relative 'support/deprecation'
require 'minitest/autorun'
require 'test/unit'
require 'rubygems'
Expand Down
Loading