diff --git a/CHANGELOG.md b/CHANGELOG.md index 4e51794..0dcacf1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ ## main (unreleased) +* [#86](https://github.com/Shopify/deprecation_toolkit/pull/86): Preserve and utilize `Warning` categories + ## 2.0.3 (2023-02-10) * [#80](https://github.com/Shopify/deprecation_toolkit/pull/80): Filter out stack trace from Gem::Deprecate deprecation messages diff --git a/README.md b/README.md index f902d85..dbf786e 100644 --- a/README.md +++ b/README.md @@ -117,6 +117,18 @@ This setting accepts an array of regular expressions. To match on all warnings, DeprecationToolkit::Configuration.warnings_treated_as_deprecation = [//] ``` +### 🔨 `#DeprecationToolkit::Configuration#warning_deprecated_category` + +[Ruby silences its deprecation warnings by setting the `Warning[:deprecated]` category to `false` +unless otherwise specified.](https://bugs.ruby-lang.org/projects/ruby-master/repository/git/revisions/a84ad24386d27269b90794146c2a351c1d79471b) +This configuration option enables that category by default. + +| Value of `DeprecationToolkit::Configuration#warning_deprecated_category` | Value of `Warning[:deprecated]` | +|--------------------------------------------------------------------------|---------------------------------| +| `true` (default) | `true` | +| `false` | `false` | +| `nil` | Unchanged | + ## RSpec By default Deprecation Toolkit uses Minitest as its test runner. To use Deprecation Toolkit with RSpec you'll have to configure it. diff --git a/lib/deprecation_toolkit/configuration.rb b/lib/deprecation_toolkit/configuration.rb index 3814905..9f97050 100644 --- a/lib/deprecation_toolkit/configuration.rb +++ b/lib/deprecation_toolkit/configuration.rb @@ -6,11 +6,26 @@ module DeprecationToolkit class Configuration include ActiveSupport::Configurable + PREVIOUS_WARNING_DEPRECATED_CATEGORY = ::Warning[:deprecated] + config_accessor(:allowed_deprecations) { [] } config_accessor(:attach_to) { [:rails] } config_accessor(:behavior) { Behaviors::Raise } config_accessor(:deprecation_path) { "test/deprecations" } config_accessor(:test_runner) { :minitest } config_accessor(:warnings_treated_as_deprecation) { [] } + config_accessor(:warning_deprecated_category) + + def self.warning_deprecated_category=(value) + ::Warning[:deprecated] = + if value.nil? + PREVIOUS_WARNING_DEPRECATED_CATEGORY + else + value + end + config.warning_deprecated_category = value + end + + self.warning_deprecated_category = true end end diff --git a/lib/deprecation_toolkit/warning.rb b/lib/deprecation_toolkit/warning.rb index 12ea47b..6defdf4 100644 --- a/lib/deprecation_toolkit/warning.rb +++ b/lib/deprecation_toolkit/warning.rb @@ -37,19 +37,20 @@ def handle_multipart(str) str end - def deprecation_triggered?(str) - DeprecationToolkit::Configuration.warnings_treated_as_deprecation.any? { |warning| warning =~ str } + def deprecation_triggered?(str, category: nil) + (category == :deprecated && ::Warning[:deprecated]) || + DeprecationToolkit::Configuration.warnings_treated_as_deprecation.any? { |warning| warning =~ str } end end end module DeprecationToolkit module WarningPatch - def warn(str) + def warn(str, category: nil) str = DeprecationToolkit::Warning.handle_multipart(str) return unless str - if DeprecationToolkit::Warning.deprecation_triggered?(str) + if DeprecationToolkit::Warning.deprecation_triggered?(str, category: category) ActiveSupport::Deprecation.warn(str) else super diff --git a/test/deprecation_toolkit/configuration_test.rb b/test/deprecation_toolkit/configuration_test.rb index 2e015e8..edc793e 100644 --- a/test/deprecation_toolkit/configuration_test.rb +++ b/test/deprecation_toolkit/configuration_test.rb @@ -4,6 +4,16 @@ module DeprecationToolkit class ConfigurationTest < ActiveSupport::TestCase + setup do + @previous_warning_deprecated = ::Warning[:deprecated] + @previous_warning_deprecated_category = Configuration.warning_deprecated_category + end + + teardown do + Configuration.warning_deprecated_category = @previous_warning_deprecated_category + ::Warning[:deprecated] = @previous_warning_deprecated + end + test ".behavior is by default set to Raise" do assert_equal Behaviors::Raise, Configuration.behavior end @@ -23,5 +33,68 @@ class ConfigurationTest < ActiveSupport::TestCase test ".test_runner is by default set to `minitest`" do assert_equal :minitest, Configuration.test_runner end + + test ".warning_deprecated_category is by default set to `true`" do + with_each_warning_deprecated_value do + assert_equal true, Configuration.warning_deprecated_category + end + end + + test ".warning_deprecated_category= sets `Warning[:deprecated]` when passed boolean" do + with_each_warning_deprecated_value do + Configuration.warning_deprecated_category = true + assert_equal true, ::Warning[:deprecated] + + Configuration.warning_deprecated_category = false + assert_equal false, ::Warning[:deprecated] + end + end + + test ".warning_deprecated_category= leaves `Warning[:deprecated]` unchanged when passed nil" do + with_warning_deprecated false do + Configuration.warning_deprecated_category = nil + assert_equal false, ::Warning[:deprecated] + + Configuration.warning_deprecated_category = true + assert_equal true, ::Warning[:deprecated] + + Configuration.warning_deprecated_category = nil + assert_equal false, ::Warning[:deprecated] + end + + with_warning_deprecated true do + Configuration.warning_deprecated_category = nil + assert_equal true, ::Warning[:deprecated] + + Configuration.warning_deprecated_category = false + assert_equal false, ::Warning[:deprecated] + + Configuration.warning_deprecated_category = nil + assert_equal true, ::Warning[:deprecated] + end + end + + private + + def with_warning_deprecated(value) + previous_value = ::Warning[:deprecated] + + ::Warning[:deprecated] = value + + Configuration.send(:remove_const, :PREVIOUS_WARNING_DEPRECATED_CATEGORY) + Configuration.const_set(:PREVIOUS_WARNING_DEPRECATED_CATEGORY, ::Warning[:deprecated]) + + yield + ensure + ::Warning[:deprecated] = previous_value + + Configuration.send(:remove_const, :PREVIOUS_WARNING_DEPRECATED_CATEGORY) + Configuration.const_set(:PREVIOUS_WARNING_DEPRECATED_CATEGORY, ::Warning[:deprecated]) + end + + def with_each_warning_deprecated_value(&block) + with_warning_deprecated(false, &block) + with_warning_deprecated(true, &block) + end end end diff --git a/test/deprecation_toolkit/warning_test.rb b/test/deprecation_toolkit/warning_test.rb index e6bdcf1..75ab44a 100644 --- a/test/deprecation_toolkit/warning_test.rb +++ b/test/deprecation_toolkit/warning_test.rb @@ -6,9 +6,13 @@ module DeprecationToolkit class WarningTest < ActiveSupport::TestCase setup do @previous_warnings_treated_as_deprecation = Configuration.warnings_treated_as_deprecation + @previous_warnings_deprecated_category = Configuration.warning_deprecated_category + @previous_warning_experimental = ::Warning[:experimental] end teardown do + ::Warning[:experimental] = @previous_warning_experimental + Configuration.warning_deprecated_category = @previous_warnings_deprecated_category Configuration.warnings_treated_as_deprecation = @previous_warnings_treated_as_deprecation end @@ -78,5 +82,37 @@ class WarningTest < ActiveSupport::TestCase assert_match(/Using the last argument as keyword parameters/, error.message) assert_match(/The called method/, error.message) end + + test "warn preserves category" do + ::Warning[:experimental] = true + assert_output(nil, /#example is experimental/) do + warn "#example is experimental", category: :experimental + + trigger_deprecation_toolkit_behavior + end + + ::Warning[:experimental] = false + assert_silent do + warn "#example is experimental", category: :experimental + + trigger_deprecation_toolkit_behavior + end + end + + test "treats `category: :deprecated` as deprecations, if flag is set" do + Configuration.warning_deprecated_category = true + assert_raises Behaviors::DeprecationIntroduced do + warn "#example is deprecated", category: :deprecated + + trigger_deprecation_toolkit_behavior + end + + Configuration.warning_deprecated_category = false + assert_nothing_raised do + warn "#example is deprecated", category: :deprecated + + trigger_deprecation_toolkit_behavior + end + end end end