Commit Graph

9180 Commits

Author SHA1 Message Date
Jonathan Hefner ff38e2effc Add Deprecators#disallowed_warnings=
Although disallowed warnings are likely to be deprecator-specific, it
can be useful to set this value once and have it applied to any
deprecators that are added later.  For example, setting the value in an
initializer via `config.active_support.disallowed_deprecation_warnings`
and applying it to any third-party deprecators that are added later in
the boot process.  Also, when using `:all`, it is more convenient to
write `deprecators.disallowed_warnings = :all` instead of
`deprecators.each { |deprecator| deprecator.disallowed_warnings = :all }`.
2022-11-25 12:30:08 -06:00
Takashi Kokubun d6c42b3fba Override ERB::Util#html_escape with Module#prepend
With Ruby 3.2 or the upcoming release of erb.gem, ERB::Util#html_escape
will be faster than CGI.escapeHTML in the case that it escapes nothing
because ERB::Util#html_escape will not duplicate the argument, unlike
CGI.escapeHTML. https://bugs.ruby-lang.org/issues/19102

Calling the original ERB::Util#html_escape with `super` is preferable
not only for the above performance reason but also for making it more
permissive about other monkey patches using Module#prepend. I tried to
use Module#prepend there myself, but I gave it up because it wasn't
compatible with the monkey patch of Rails not using Module#prepend.
2022-11-25 00:20:03 -08:00
Jonathan Hefner e5693c56c6 Add AS::ParameterFilter.precompile_filters
`ActiveSupport::ParameterFilter.precompile_filters` precompiles filters
that otherwise would be passed directly to `ParameterFilter.new`.
Depending on the quantity and types of filters, precompilation can
improve filtering performance, especially in the case where the
`ParameterFilter` instance cannot be retained, such as with per-request
instances in `ActionDispatch::Http::FilterParameters`.

**Benchmark script**

  ```ruby
  # frozen_string_literal: true
  require "benchmark/ips"
  require "benchmark/memory"
  require "active_support"
  require "active_support/parameter_filter"

  ootb = [:passw, :secret, :token, :_key, :crypt, :salt, :certificate, :otp, :ssn]
  mixed = [:passw, "secret", /token/, :crypt, "salt", /certificate/, "user.otp", /user\.ssn/, proc {}]
  precompiled_ootb = ActiveSupport::ParameterFilter.precompile_filters(ootb)
  precompiled_mixed = ActiveSupport::ParameterFilter.precompile_filters(mixed)

  params = {
    "user" => {
      "name" => :name,
      "email" => :email,
      "password" => :password,
      "ssn" => :ssn,
      "locations" => [
        { "city" => :city, "country" => :country },
        { "city" => :city, "country" => :country },
      ],
    }
  }

  Benchmark.ips do |x|
    x.report("ootb") do
      ActiveSupport::ParameterFilter.new(ootb).filter(params)
    end
    x.report("precompiled ootb") do
      ActiveSupport::ParameterFilter.new(precompiled_ootb).filter(params)
    end
    x.compare!
  end

  Benchmark.ips do |x|
    x.report("mixed") do
      ActiveSupport::ParameterFilter.new(mixed).filter(params)
    end
    x.report("precompiled mixed") do
      ActiveSupport::ParameterFilter.new(precompiled_mixed).filter(params)
    end
    x.compare!
  end

  Benchmark.memory do |x|
    x.report("ootb") do
      ActiveSupport::ParameterFilter.new(ootb).filter(params)
    end
    x.report("precompiled ootb") do
      ActiveSupport::ParameterFilter.new(precompiled_ootb).filter(params)
    end
  end

  Benchmark.memory do |x|
    x.report("mixed") do
      ActiveSupport::ParameterFilter.new(mixed).filter(params)
    end
    x.report("precompiled mixed") do
      ActiveSupport::ParameterFilter.new(precompiled_mixed).filter(params)
    end
  end
  ```

**Results**

  ```
  Warming up --------------------------------------
                  ootb     2.151k i/100ms
      precompiled ootb     4.251k i/100ms
  Calculating -------------------------------------
                  ootb     21.567k (± 1.1%) i/s -    109.701k in   5.086983s
      precompiled ootb     42.840k (± 0.8%) i/s -    216.801k in   5.061022s

  Comparison:
      precompiled ootb:    42840.4 i/s
                  ootb:    21567.5 i/s - 1.99x  (± 0.00) slower
  ```

  ```
  Warming up --------------------------------------
                 mixed     1.622k i/100ms
     precompiled mixed     2.455k i/100ms
  Calculating -------------------------------------
                 mixed     16.085k (± 1.3%) i/s -     81.100k in   5.042764s
     precompiled mixed     24.640k (± 1.0%) i/s -    125.205k in   5.081988s

  Comparison:
     precompiled mixed:    24639.6 i/s
                 mixed:    16085.0 i/s - 1.53x  (± 0.00) slower
  ```

  ```
  Calculating -------------------------------------
                  ootb     2.684k memsize (     0.000  retained)
                          30.000  objects (     0.000  retained)
                          10.000  strings (     0.000  retained)
      precompiled ootb     1.104k memsize (     0.000  retained)
                           9.000  objects (     0.000  retained)
                           1.000  strings (     0.000  retained)
  ```

  ```
  Calculating -------------------------------------
                 mixed     3.541k memsize (     0.000  retained)
                          46.000  objects (     0.000  retained)
                          20.000  strings (     0.000  retained)
     precompiled mixed     1.856k memsize (     0.000  retained)
                          29.000  objects (     0.000  retained)
                          13.000  strings (     0.000  retained)
  ```

This commit also adds `config.precompile_filter_parameters`, which
enables precompilation of `config.filter_parameters`.  It defaults to
`true` for `config.load_defaults 7.1` and above.
2022-11-24 10:26:54 -06:00
Jean Boussier 2e90215500 LoggerThreadSafeLevel only impact the receiving logger
Fix: https://github.com/rails/rails/issues/46559

That's how it initially worked, but this was broken in
https://github.com/rails/rails/pull/34055

That PR replaced an instance variable by a class variable, causing
the level to be per thread, but to apply to all logger instances.
2022-11-24 12:39:52 +01:00
Jean Boussier 1a2ca1920c AbstractAdapter: only synchronize when necessary
Ref: https://github.com/rails/rails/pull/28083

Right now all database operations are synchronized with a monitor even though
it's useless in the vast majority of cases.

The synchronization is only useful when transactional fixtures are enabled.

In production, connections are never shared across threads, as such this extra
synchronization is wasteful.
2022-11-22 15:33:40 +01:00
Maciej Mensfeld e57826234e
Remove concurrent map require 2022-11-21 18:55:27 +01:00
Maciej Mensfeld aff51e8f90
Replace concurrent map with a regular hash
No need for concurrent structure in a non-concurrent execution location.
2022-11-21 18:50:58 +01:00
Maciej Mensfeld 2039754e14
Make testing stubs fully thread-safe
This change makes the initialization of the hash upon missing key fully thread-safe. Before this change, initialization that would occur in two threads could overwrite each other, as illustrated here:

https://github.com/ruby-concurrency/concurrent-ruby/issues/970
2022-11-20 20:09:05 +01:00
Rafael Mendonça França 994bce4e32
Merge PR #45698 2022-11-17 22:54:30 +00:00
Petrik 3d26ef23a1 Use 2 spaces for identation in ActiveSupport code examples [ci-skip]
For consistency use 2 spaces for indentation (+ 1 default space after `#`)
Some of these were formatted incorrectly in the API docs.
2022-11-16 22:44:22 +01:00
Jonathan Hefner e6ab2888c8
Merge pull request #46456 from jonathanhefner/follow-up-46330-and-46337
Add missing `assert_not_deprecated` deprecator args
2022-11-10 16:29:48 -06:00
Jonathan Hefner fbad90fdd0
Merge pull request #46451 from jonathanhefner/parameter_filter-reintegrate-compiled_filter
Reintegrate `AS::ParameterFilter::CompiledFilter`
2022-11-10 16:27:59 -06:00
Jonathan Hefner 8a7aba0c76 Add missing assert_not_deprecated deprecator args
Follow-up to #46330 and #46337.

This adds a deprecator arg to some `assert_not_deprecated` calls that
were missed in #46330 and #46337.
2022-11-09 12:07:29 -06:00
Jean Boussier e5f3d69203
Merge pull request #46448 from fatkodima/fix-many-additional-arguments 2022-11-09 01:26:14 +01:00
Jonathan Hefner fd8b751066 Reintegrate AS::ParameterFilter::CompiledFilter
`ActiveSupport::ParameterFilter::CompiledFilter` was originally
extracted in 79e91cc0ec as a performance
optimization.  Its purpose was to avoid redundantly checking
`@filters.empty?`.  However, redundant checks can be avoided by using
separate `ParameterFilter` methods, rather than allocating a separate
`CompiledFilter` object.  Therefore, this commit reintegrates
`CompiledFilter` back into `ParameterFilter`.

Additionally, lazy compilation of filters predates the extraction of
`ParameterFilter` from `ActionDispatch::Http::FilterParameters` in
e466354edb.  However, since
`ActionDispatch::Http::FilterParameters` lazily allocates a
`ParameterFilter` instance, there is no benefit to `ParameterFilter`
also lazily compiling filters.  Therefore, this commit switches from
lazy compilation to eager compilation.

Together, these changes yield a small performance increase:

**Benchmark script**

  ```ruby
  # frozen_string_literal: true
  require "benchmark/ips"
  require "benchmark/memory"
  require "active_support"
  require "active_support/parameter_filter"

  ootb = [:passw, :secret, :token, :_key, :crypt, :salt, :certificate, :otp, :ssn]
  mixed = [:passw, "secret", /token/, :crypt, "salt", /certificate/, "user.otp", /user\.ssn/, proc {}]

  params = {
    "user" => {
      "name" => :name,
      "email" => :email,
      "password" => :password,
      "ssn" => :ssn,
      "locations" => [
        { "city" => :city, "country" => :country },
        { "city" => :city, "country" => :country },
      ],
    }
  }

  Benchmark.ips do |x|
    x.report("ootb") do
      ActiveSupport::ParameterFilter.new(ootb).filter(params)
    end

    x.report("mixed") do
      ActiveSupport::ParameterFilter.new(mixed).filter(params)
    end
  end
  ```

**Before**

  ```
  Warming up --------------------------------------
                  ootb     2.032k i/100ms
                 mixed     1.521k i/100ms
  Calculating -------------------------------------
                  ootb     20.315k (± 1.3%) i/s -    101.600k in   5.001939s
                 mixed     15.142k (± 1.2%) i/s -     76.050k in   5.023077s
  ```

**After**

  ```
  Warming up --------------------------------------
                  ootb     2.163k i/100ms
                 mixed     1.604k i/100ms
  Calculating -------------------------------------
                  ootb     21.478k (± 1.2%) i/s -    108.150k in   5.036188s
                 mixed     16.052k (± 0.8%) i/s -     81.804k in   5.096656s
  ```
2022-11-08 16:58:43 -06:00
Jonathan Hefner c9beaf1c97 Track parent key as string in ParameterFilter
This avoids allocating an array each time `ParameterFilter#filter` is
called, and avoids a few redundant operations when building up the
full key.  This yields a small but reproducible performance increase:

**Benchmark script**

  ```ruby
  # frozen_string_literal: true
  require "benchmark/ips"
  require "benchmark/memory"
  require "active_support"
  require "active_support/parameter_filter"

  ootb = [:passw, :secret, :token, :_key, :crypt, :salt, :certificate, :otp, :ssn]
  mixed = [:passw, "secret", /token/, :crypt, "salt", /certificate/, "user.otp", /user\.ssn/, proc {}]

  params = {
    "user" => {
      "name" => :name,
      "email" => :email,
      "password" => :password,
      "ssn" => :ssn,
      "locations" => [
        { "city" => :city, "country" => :country },
        { "city" => :city, "country" => :country },
      ],
    }
  }

  Benchmark.ips do |x|
    x.report("ootb") do
      ActiveSupport::ParameterFilter.new(ootb).filter(params)
    end

    x.report("mixed") do
      ActiveSupport::ParameterFilter.new(mixed).filter(params)
    end
  end
  ```

**Before**

  ```
  Warming up --------------------------------------
                  ootb     2.003k i/100ms
                 mixed     1.362k i/100ms
  Calculating -------------------------------------
                  ootb     19.975k (± 0.9%) i/s -    100.150k in   5.014277s
                 mixed     13.627k (± 0.9%) i/s -     69.462k in   5.097741s
  ```

**After**

  ```
  Warming up --------------------------------------
                  ootb     2.032k i/100ms
                 mixed     1.521k i/100ms
  Calculating -------------------------------------
                  ootb     20.315k (± 1.3%) i/s -    101.600k in   5.001939s
                 mixed     15.142k (± 1.2%) i/s -     76.050k in   5.023077s
  ```
2022-11-08 16:32:41 -06:00
fatkodima d862dffadd Fix `Enumerable#many?` to handle previous enumerator methods parameters 2022-11-08 20:53:55 +02:00
Sam Bostock 1bd522037e
Ensure pipe is closed after test run
`Forking.run_in_isolation` opens two ends of a pipe. The fork process closes
the read end, writes to it, and then terminates (which presumably closes the
file descriptors on its end). The parent process closes the write end, reads
from it, and returns, never closing the read end.

This results in an accumulation of open file descriptors, which can cause
errors if the limit is reached.

One approach to fixing this would be to simply close the read end of the pipe
in the parent process. However, it is more idiomatic to open the pipe given a
block, which automatically closes the pipe after the block exits.
2022-11-04 16:49:36 -04:00
Jean Boussier dac247a6cd
Merge pull request #46333 from radar/timezone-canberra
Point 'Canberra' time zone mapping to Australia/Canberra'
2022-11-01 22:24:59 +01:00
Jonathan Hefner 587c3406af Add ActiveSupport.deprecator
This commit adds `ActiveSupport.deprecator` and replaces all usages of
`ActiveSupport::Deprecation.warn` in `activesupport/lib` with
`ActiveSupport.deprecator`.

Additionally, this commit adds `ActiveSupport.deprecator` to
`Rails.application.deprecators` so that it can be configured using e.g.
`config.active_support.report_deprecations`.
2022-10-25 15:06:39 -05:00
Ryan Bigg 46065ddb5d Point 'Canberra' time zone mapping to Australia/Canberra' 2022-10-25 14:11:47 +11:00
Jonathan Hefner 09e6442c20 Add deprecator-only overload for assert_deprecated
This commits adds a deprecator-only overload for `assert_deprecated`.
For example, `assert_deprecated(/./, deprecator)` can now be written as
`assert_deprecated(deprecator)`.

This is part of an initiative to move away from the top-level
`ActiveSupport::Deprecation` API, towards per-library deprecator
instances.  See also #46000 and its follow-ups.
2022-10-24 16:24:25 -05:00
Jonathan Hefner 8bdea353eb
Merge pull request #46328 from jonathanhefner/rails_application_deprecators-config
Apply config to `Rails.application.deprecators`
2022-10-24 16:23:55 -05:00
Jonathan Hefner 3a3276c93c
Merge pull request #46251 from jonathanhefner/fix-time-change-and-advance-around-end-of-dst
Fix `Time#change` and `#advance` around the end of DST
2022-10-24 16:07:47 -05:00
Jonathan Hefner a23c9e38d3 Apply config to Rails.application.deprecators
This applies the following configs to `Rails.application.deprecators`,
which then applies them to `ActiveSupport::Deprecation.instance`:

* `config.active_support.report_deprecations`
* `config.active_support.deprecation`
* `config.active_support.disallowed_deprecation`
* `config.active_support.disallowed_deprecation_warnings`
2022-10-24 15:40:13 -05:00
Hartley McGuire ae529784b8
Fix test where broadcaster doesn't define #silence
This test was added in 308e84e to ensure that calling #silence on a
broadcasted logger works if the broadcastee implements #silence but the
broadcaster does not.

However, `include ActiveSupport::LoggerSilence` was moved from the
`FakeLogger` to the `CustomLogger` in 05ad44e. This resulted in both
loggers in the above test implementing silence, so it no longer tested
the behavior expected (that only one of them implements #silence).

The inclusion of `LoggerSilence` was moved back to `FakeLogger` so that
`CustomLogger` does not implement silence, and assertions were added so
that this does not regress. In addition, methods transitively included
by `LoggerSilence` are overriden so that they continue to behave like
`CustomLogger`.
2022-10-23 01:46:40 -04:00
Jonathan Hefner b191a65850 Fix Time#change and #advance around the end of DST
Prior to this commit, when `Time#change` or `Time#advance` constructed a
time inside the final stretch of Daylight Saving Time (DST), the non-DST
offset would always be chosen for local times:

  ```ruby
  # DST ended just before 2021-11-07 2:00:00 AM in US/Eastern.
  ENV["TZ"] = "US/Eastern"

  time = Time.local(2021, 11, 07, 00, 59, 59) + 1
  # => 2021-11-07 01:00:00 -0400
  time.change(day: 07)
  # => 2021-11-07 01:00:00 -0500
  time.advance(seconds: 0)
  # => 2021-11-07 01:00:00 -0500

  time = Time.local(2021, 11, 06, 01, 00, 00)
  # => 2021-11-06 01:00:00 -0400
  time.change(day: 07)
  # => 2021-11-07 01:00:00 -0500
  time.advance(days: 1)
  # => 2021-11-07 01:00:00 -0500
  ```

And the DST offset would always be chosen for times with a `TimeZone`
object:

  ```ruby
  Time.zone = "US/Eastern"

  time = Time.new(2021, 11, 07, 02, 00, 00, Time.zone) - 3600
  # => 2021-11-07 01:00:00 -0500
  time.change(day: 07)
  # => 2021-11-07 01:00:00 -0400
  time.advance(seconds: 0)
  # => 2021-11-07 01:00:00 -0400

  time = Time.new(2021, 11, 8, 01, 00, 00, Time.zone)
  # => 2021-11-08 01:00:00 -0500
  time.change(day: 07)
  # => 2021-11-07 01:00:00 -0400
  time.advance(days: -1)
  # => 2021-11-07 01:00:00 -0400
  ```

This commit fixes `Time#change` and `Time#advance` to choose the offset
that matches the original time's offset when possible:

  ```ruby
  ENV["TZ"] = "US/Eastern"

  time = Time.local(2021, 11, 07, 00, 59, 59) + 1
  # => 2021-11-07 01:00:00 -0400
  time.change(day: 07)
  # => 2021-11-07 01:00:00 -0400
  time.advance(seconds: 0)
  # => 2021-11-07 01:00:00 -0400

  time = Time.local(2021, 11, 06, 01, 00, 00)
  # => 2021-11-06 01:00:00 -0400
  time.change(day: 07)
  # => 2021-11-07 01:00:00 -0400
  time.advance(days: 1)
  # => 2021-11-07 01:00:00 -0400

  Time.zone = "US/Eastern"

  time = Time.new(2021, 11, 07, 02, 00, 00, Time.zone) - 3600
  # => 2021-11-07 01:00:00 -0500
  time.change(day: 07)
  # => 2021-11-07 01:00:00 -0500
  time.advance(seconds: 0)
  # => 2021-11-07 01:00:00 -0500

  time = Time.new(2021, 11, 8, 01, 00, 00, Time.zone)
  # => 2021-11-08 01:00:00 -0500
  time.change(day: 07)
  # => 2021-11-07 01:00:00 -0500
  time.advance(days: -1)
  # => 2021-11-07 01:00:00 -0500
  ```

It's worth noting that there is a somewhat dubious case when calling
`advance` with a mix of calendar and clock units (e.g. months + hours).
`advance` adds calendar units first, then adds clock units.  So a
non-DST time may first be advanced to a date within DST before any clock
units are applied.  For example:

  ```ruby
  # DST began on 2021-03-14 in US/Eastern.
  Time.zone = "US/Eastern"

  non_dst = Time.new(2021, 03, 07, 00, 00, 00, Time.zone)
  # => 2021-03-07 00:00:00 -0500

  non_dst.advance(months: 8, hours: 1)
  # => 2021-11-07 01:00:00 -0400
  ```

One could argue that the expected result is `2021-11-07 01:00:00 -0500`.
However, the difference between that and the result for `hours: 0` is
greater than 1 hour:

  ```ruby
  adjusted_result = non_dst.advance(months: 8, hours: 1) + 3600
  # => 2021-11-07 01:00:00 -0500

  adjusted_result - non_dst.advance(months: 8, hours: 0)
  # => 7200.0
  ```

Which might also be unexpected.

Furthermore, it may be difficult (or expensive) to apply such an
adjustment in a consistent way.  For example, the result for `hours: 2`
does have the expected `-0500` offset, so it might seem no adjustment is
necessary, but if we didn't adjust it too, it would conflict with the
adjusted `hours: 1` result:

  ```ruby
  non_dst.advance(months: 8, hours: 2)
  # => 2021-11-07 01:00:00 -0500
  ```

Therefore, the approach in this commit (which produces a `-0400` offset
for `hours: 1`) seems like a reasonable compromise.

Fixes #45055.
Closes #45556.
Closes #46248.

Co-authored-by: Kevin Hall <bigtoe416@yahoo.com>
Co-authored-by: Takayoshi Nishida <takayoshi.nishida@gmail.com>
2022-10-22 14:58:03 -05:00
Jean Boussier 4af6d50d44 MemoryStore: preserve entry ttl when incrementing
Fix: https://github.com/rails/rails/issues/46301

When incrementing in Memcached or Redis, we use `raw` values, so
only the backing store TTL counts, and is preserved.

So for consistency we need to emulate this in MemoryStore by
re-using the existing entry's `expires_at`.
2022-10-22 12:33:41 +02:00
Martin Spickermann 1a9b887c0c Allow ErrorReporter to handle several error classes
`Rails.error.handle` and `Rails.error.record` are able to filter by list of serveral error classes now, for example like this:

```ruby
Rails.error.handle(ArgumentError, TypeError) do
  [1, 2, 3].first(x) # where `x` might be `-4` or `'4'`
end
```
2022-10-21 13:21:36 +02:00
Aaron Patterson 2f36f0a2bb
Merge pull request #46171 from rails/refactor-errors
Add column information inside ERB templates
2022-10-11 15:10:40 -07:00
Jean Boussier d917896f45 Enable verbose mode in test and report warnings as errors
We recently let a few very easy to avoid warnings get merged.
The root cause is that locally the test suite doesn't run in
verbose mode unless you explictly pass `-w`.

On CI warnings are enabled, but there is no reason to look at the
build output unless something is failing. And even if one wanted
to do that, that would be particularly work intensive since warnings
may be specific to a Ruby version etc.

Because of this I believe we should:

  - Always run the test suite with warnings enabled.
  - Raise an error if a warning is unexpected.

We've been using this pattern for a long time at Shopify both in private
and public repositories.
2022-10-11 09:25:18 +02:00
Aaron Patterson abc6b5a382
rubocop 😩 2022-10-09 16:34:44 -07:00
Aaron Patterson 9f5dee3a91
move ERB monkey patches to their own file 2022-10-09 16:12:37 -07:00
Aaron Patterson a7238cbfa4
rubocop 2022-10-09 15:54:42 -07:00
Aaron Patterson 1d39573a9f
Move ERB parsing to core_ext 2022-10-09 14:52:17 -07:00
Aaron Patterson f6e20abd27
rubocop 2022-10-09 14:52:17 -07:00
Aaron Patterson 650e99ac5b
Map column information in to ERB templates
This commit maps the column information returned from ErrorHighlight in
to column information within the source ERB template.  ErrorHighlight
only understands the compiled Ruby code, so this commit adds a small
translation layer that converts the values from ErrorHighlight in to the
right values for the ERB source template
2022-10-09 14:52:17 -07:00
Aaron Patterson e85edcc45d
Ask backtrace locations for their spot information
This way we can do special stuff when the exceptions come from special
locations
2022-10-09 14:52:17 -07:00
Aaron Patterson 343dba47e0
Only deal with backtrace locations in ExceptionWrapper
We should get out of the business of parsing backtraces and only use
backtrace locations.  Backtrace locations have the file and line number
information baked in, so we don't need to parse things anymore
2022-10-09 14:52:17 -07:00
Aaron Patterson 80a698d15c
Use a SyntaxError proxy object when displaying syntax error info
This commit adds a SyntaxErrorProxy object to active support and wraps
syntax error exceptions with that proxy object.  We want to enhance
syntax errors with information about the source location where they
actually happened (normally the backtrace doesn't contain such info).
Rather than mutating the original exception's backtrace, this wraps it
with a proxy object.

Eventually we will implement backtrace_locations on the proxy object so
that the exception handling middleware can be updated to _only_ deal
with backtrace_locations and never deal with raw `backtrace`
2022-10-09 14:52:17 -07:00
hsachdeva01 c8d8f09f56
remove redis reconnect attempts 2022-10-06 12:37:06 -07:00
Jonathan Hefner d240e8a986 Add Rails.application.deprecators
This adds a `Rails.application.deprecators` method that returns a
managed collection of deprecators.

Individual deprecators can be added and retrieved from the collection:

  ```ruby
  Rails.application.deprecators[:my_gem] = ActiveSupport::Deprecation.new("2.0", "MyGem")
  Rails.application.deprecators[:other_gem] = ActiveSupport::Deprecation.new("3.0", "OtherGem")
  ```

And the collection's configuration methods affect all deprecators in the
collection:

  ```ruby
  Rails.application.deprecators.debug = true

  Rails.application.deprecators[:my_gem].debug
  # => true
  Rails.application.deprecators[:other_gem].debug
  # => true
  ```

Additionally, all deprecators in the collection can be silenced for the
duration of a given block:

  ```ruby
  Rails.application.deprecators.silence do
    Rails.application.deprecators[:my_gem].warn    # => silenced (no warning)
    Rails.application.deprecators[:other_gem].warn # => silenced (no warning)
  end
  ```
2022-10-05 14:37:27 -05:00
Alex Ghiculescu be155f135a Support using a method name to define the `ActiveSupport::CurrentAttributes.resets` callback
Previously you could only use a block, which was inconsistent with other callback APIs in Rails. Now, you can use a block or a method name. The block API is still recommended in the docs.

```ruby
class Current < ActiveSupport::CurrentAttributes
  resets { Time.zone = nil }
  resets :clear_time_zone
end
```

This also works for `before_reset`.

```ruby
class Current < ActiveSupport::CurrentAttributes
  before_reset { Time.zone = nil }
  before_reset :clear_time_zone
end
```
2022-10-05 11:05:58 -05:00
Jean Boussier 05bcb1555b Namespace keys in EncodedKeyCacheBehavior test
It's a bit of a stab in the dark but I'm hoping it may fix
the flaky failures such as:

```ruby
Failure:
OptimizedMemCacheStoreTest#test_iso_8859_6_encoded_values [/rails/activesupport/test/cache/behaviors/encoded_key_cache_behavior.rb:10]:
Expected false to be truthy.
```
2022-10-04 09:31:13 +02:00
Jean Boussier b205dc4b36 DescendantsTracker: fix a method redefinition warning 2022-10-03 21:37:33 +02:00
Jean Boussier 837f20e430 Fix an uninitialized variable warning in RotationCoordinator 2022-10-03 21:31:45 +02:00
Jean Boussier 890015ae46 Avoid uninitialized variable warnings on Ruby 2.7
Since the variable is either set to true, or not present at all
we can check wether it's defined instead.
2022-10-03 21:29:19 +02:00
Yoshiki Takagi 2c35dce71c Remove duplicate frozen_string_literal comment 2022-10-04 00:16:25 +09:00
Jonathan Hefner c267be43d3 Move CHANGELOG entry for #44179 to railties [ci-skip]
The CHANGELOG entry for #44179 originally focused on
`ActiveSupport::MessageVerifiers` and `ActiveSupport::MessageEncryptors`,
and made sense in `activesupport/CHANGELOG.md`.  However, prior to
merge, the focus changed to `Rails.application.message_verifiers`.
Therefore, the CHANGELOG entry should be in `railties/CHANGELOG.md`.
2022-09-29 12:08:14 -05:00
Jean Boussier 1aa24639f7 Filter reloaded classes in Class#subclasses and Class#descendants core exts
When calling `#descendants` on a non-reloadable class with reloadable
descendants, it can return classes that were unloaded but not yet
garbage collected.

`DescendantsTracker` have been dealing with this for a long time
but the core_ext versions of these methods were never made reloader
aware.

This also refactor `DescendantsTracker` to not be so different when
there is no native `#subclasses` method.
2022-09-28 12:08:58 +02:00