Skip to content

Commit b09aa0d

Browse files
Merge pull request #2997 from faker-ruby/sb-deprecator-improvements
Deprecator improvements
2 parents caa5507 + d8b2327 commit b09aa0d

File tree

7 files changed

+166
-29
lines changed

7 files changed

+166
-29
lines changed

Gemfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ source 'https://rubygems.org'
66
gemspec
77

88
gem 'benchmark'
9-
gem 'minitest', '5.25.0'
9+
gem 'minitest', '5.25.1'
1010
gem 'pry', '0.14.2'
1111
gem 'rake', '13.2.1'
1212
gem 'rubocop', '1.65.1'

Gemfile.lock

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ GEM
1717
json (2.7.2)
1818
language_server-protocol (3.17.0.3)
1919
method_source (1.0.0)
20-
minitest (5.25.0)
20+
minitest (5.25.1)
2121
parallel (1.25.1)
2222
parser (3.3.4.0)
2323
ast (~> 2.4.1)
@@ -71,7 +71,7 @@ PLATFORMS
7171
DEPENDENCIES
7272
benchmark
7373
faker!
74-
minitest (= 5.25.0)
74+
minitest (= 5.25.1)
7575
pry (= 0.14.2)
7676
rake (= 13.2.1)
7777
rubocop (= 1.65.1)

lib/helpers/deprecator.rb

Lines changed: 68 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,70 @@
11
# frozen_string_literal: true
22

33
# Based on Rails ActiveSupport Deprecator
4-
# https://github.com/rails/rails/blob/6f0d1ad14b92b9f5906e44740fce8b4f1c7075dc/activesupport/lib/active_support/deprecation/constant_accessor.rb
4+
# https://github.com/rails/rails/blob/main/activesupport/lib/active_support/deprecation/constant_accessor.rb
55

66
# rubocop:disable Style/ClassVars
77
module Faker
8+
# Provides a way to rename generators, including their namespaces, with a deprecation cycle in which
9+
# both the old and new names work, but using the old one prints a deprecation message.
10+
#
11+
# Deprecator provides a deprecate_generator method to be used when
12+
# renaming a generator. For example, let's say we want to change the following Generator's
13+
# name to <tt>Faker::NewGenerator</tt>:
14+
#
15+
# module Faker
16+
# class Generator
17+
# def self.generate
18+
# "be kind"
19+
# end
20+
# end
21+
# end
22+
#
23+
# To rename it, you need to do the update the name and declare the deprecation by
24+
# including the <tt>Deprecator</tt> module and using the deprecate_generator method:
25+
#
26+
# module Faker
27+
# class NewGenerator
28+
# def self.generate
29+
# "be kind"
30+
# end
31+
# end
32+
#
33+
# include Deprecator
34+
# deprecate_generator('DeprecatedGenerator', NewGenerator)
35+
# end
36+
#
37+
# The first argument is a constant name (no colons) as a string. It is the name of
38+
# the constant you want to deprecate.
39+
#
40+
# The second argument is the constant path of the replacement (no colons) as a constant.
41+
#
42+
# For this to work, a +const_missing+ hook is installed. When users
43+
# reference the deprecated constant, the callback prints the
44+
# message and constantizes the replacement.
45+
#
46+
# With that in place, references to <tt>Faker::Deprecator</tt> still work, they
47+
# evaluate to <tt>Faker::NewGenerator</tt> now, and trigger a deprecation warning:
48+
#
49+
# Faker::Generator.generate
50+
# # DEPRECATION WARNING: Faker::Generator is deprecated. Use Faker::NewGenerator instead
51+
# # "be kind"
52+
#
53+
# For testing the deprecations, we provide <tt>assert_deprecated</tt>
54+
# and <tt>assert_not_deprecated</tt> matchers.
55+
#
56+
# There's also a <tt>Faker::Deprecator.skip_warning</tt> helper to silence
57+
# the deprecation messages in the *test* output. Use it for generators that have lots of tests
58+
# to avoid too many noise when running the tests.
859
module Deprecator
960
def self.included(base)
1061
extension = Module.new do
1162
def const_missing(missing_const_name)
1263
if class_variable_defined?(:@@_deprecated_constants) && (replacement = class_variable_get(:@@_deprecated_constants)[missing_const_name.to_s])
1364
unless Faker::Deprecator.skip_warning?
14-
$stdout.puts("DEPRECATION WARNING: #{name}::#{replacement[:old_generator]} is deprecated. Use #{replacement[:new_constant]} instead.")
65+
deprecated_message = "#{name}::#{replacement[:old_generator]} is deprecated."
66+
replacement_message = "Use #{replacement[:new_constant]} instead."
67+
$stdout.puts("DEPRECATION WARNING: #{deprecated_message} #{replacement_message}")
1568
end
1669

1770
return replacement[:new_constant]
@@ -22,13 +75,25 @@ def const_missing(missing_const_name)
2275

2376
def deprecate_generator(old_generator_name, new_generator_constant)
2477
class_variable_set(:@@_deprecated_constants, {}) unless class_variable_defined?(:@@_deprecated_constants)
25-
class_variable_get(:@@_deprecated_constants)[old_generator_name] = { new_constant: new_generator_constant, old_generator: old_generator_name }
78+
class_variable_get(:@@_deprecated_constants)[old_generator_name] = {
79+
new_constant: new_generator_constant,
80+
old_generator: old_generator_name
81+
}
2682
end
2783
end
2884

2985
base.singleton_class.prepend extension
3086
end
3187

88+
# Silence deprecation warnings within the block.
89+
#
90+
# Faker::Generator.generate
91+
# # => DEPRECATION WARNING: Faker::Generator is deprecated. Use Faker::NewGenerator instead.
92+
#
93+
# Faker::Deprecator.skip_warning do
94+
# Faker::Generator.generate
95+
# end
96+
# # => nil
3297
def self.skip_warning
3398
original = Faker::Deprecator.skip
3499
Faker::Deprecator.skip = true

test/helpers/test_faker_deprecator.rb

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
# frozen_string_literal: true
2+
3+
require_relative '../test_helper'
4+
5+
class TestFakerDeprecation < Test::Unit::TestCase
6+
def test_using_a_deprecated_generator_returns_a_warning_message
7+
assert_deprecated do
8+
Faker::Dogs.say
9+
end
10+
11+
assert_equal 'meow', Faker::Dogs.say
12+
end
13+
14+
def test_using_a_non_deprecated_generator_does_not_return_a_warning_message
15+
assert_not_deprecated do
16+
Faker::Cats.say
17+
end
18+
assert_equal 'meow', Faker::Cats.say
19+
end
20+
21+
def test_testing_a_deprecated_generator_with_skip_warning_does_not_return_a_warning_message
22+
actual_stdout, actual_stderr = capture_output do
23+
Faker::Deprecator.skip_warning do
24+
Faker::Dogs.say
25+
end
26+
end
27+
28+
assert_empty(actual_stdout)
29+
assert_empty(actual_stderr)
30+
assert_equal 'meow', Faker::Dogs.say
31+
end
32+
33+
def test_deprecated_with_skip_warning_does_not_generate_message
34+
Faker::Deprecator.skip_warning do
35+
assert_not_deprecated do
36+
Faker::Dogs.say
37+
end
38+
end
39+
40+
assert_equal 'meow', Faker::Dogs.say
41+
end
42+
end
43+
44+
module Faker
45+
class Cats < Base
46+
def self.say
47+
'meow'
48+
end
49+
end
50+
51+
include Faker::Deprecator
52+
deprecate_generator('Dogs', Cats)
53+
end

test/support/deprecation.rb

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
# frozen_string_literal: true
2+
3+
# Based on Rails Testing Deprecator
4+
# https://github.com/rails/rails/blob/main/activesupport/lib/active_support/testing/deprecation.rb
5+
6+
# Asserts that a matching deprecation warning was emitted during the execution of the yielded block.
7+
#
8+
# assert_deprecated do
9+
# DeprecatedGenerator.generate
10+
# end
11+
#
12+
def assert_deprecated(&block)
13+
warning = with_captured_stdout(&block)
14+
result = yield block
15+
16+
refute_predicate warning, :empty?, 'Expected a deprecation warning within the block but received none'
17+
18+
result
19+
end
20+
21+
# Asserts that no deprecation warnings are emitted during the execution of the yielded block.
22+
#
23+
# assert_not_deprecated do
24+
# Faker::Internet.email
25+
# end
26+
def assert_not_deprecated(&block)
27+
warning = with_captured_stdout(&block)
28+
result = yield block
29+
30+
assert_predicate warning, :empty?, "Expected no deprecation warning within the block but received a deprecation: #{warning}"
31+
result
32+
end
33+
34+
def with_captured_stdout(&block)
35+
original_stdout = $stdout
36+
$stdout = StringIO.new
37+
yield block
38+
$stdout.string
39+
ensure
40+
$stdout = original_stdout
41+
end

test/test_faker_deprecator.rb

Lines changed: 0 additions & 23 deletions
This file was deleted.

test/test_helper.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111

1212
require_relative 'support/assert_not_english'
1313
require_relative 'support/assert_email_regex'
14+
require_relative 'support/deprecation'
1415
require 'minitest/autorun'
1516
require 'test/unit'
1617
require 'rubygems'

0 commit comments

Comments
 (0)