Commit Graph

9793 Commits

Author SHA1 Message Date
Kelly Wolf Stannard
ed5d646127 Optimize HashWithIndifferentAccess#to_hash
Creating a copy by starting from an empty hash and inserting
keys one by one is inneficient because unless the hash is
very small, Ruby will have to reallocate the hash multiple
times until it reaches the same saize as the original.

And every time it happens, keys will have to be re-hashes.

While we're at it, instead of using the generic `convert_value`
we define a dedicated method which saves on needless checks.

Co-Authored-By: Jean Boussier <jean.boussier@gmail.com>

```ruby

require "bundler/inline"

gemfile(true) do
  source "https://rubygems.org"

  gem "activesupport", path: '.'
  gem 'benchmark-ips'
  gem 'benchmark-memory'
end

require "active_support"
require "active_support/core_ext/hash/indifferent_access"
require 'benchmark/ips'

module ActiveSupport
  class KwstannardHWIA < HashWithIndifferentAccess
    def to_hash
      Hash[self]
        .transform_values! { |v| convert_value(v, conversion: :to_hash) }
        .tap { |h| set_defaults(h) }
    end
  end

  class ByrootHWIA < HashWithIndifferentAccess
    def to_hash
      copy = Hash[self]
      copy.transform_values! { |v| convert_value_to_hash(v) }
      set_defaults(copy)
      copy
    end

    private

    def convert_value_to_hash(value)
      if value.is_a? Hash
        value.to_hash
      elsif value.is_a?(Array)
        value.map { |e| convert_value_to_hash(e) }
      else
        value
      end
    end
  end
end

flat = Hash[(1..9).to_a.product([1])]
flat_baseline = ActiveSupport::HashWithIndifferentAccess.new(flat)
flat_k = ActiveSupport::KwstannardHWIA.new(flat)
flat_b = ActiveSupport::ByrootHWIA.new(flat)

Benchmark.ips do |x|
  x.report("original") { flat_baseline.to_hash }
  x.report("kwstannard") { flat_k.to_hash }
  x.report("byroot") { flat_b.to_hash }
  x.compare!(order: :baseline)
end

long_flat = Hash[(1..100).to_a.product([1])]
long_flat_baseline = ActiveSupport::HashWithIndifferentAccess.new(long_flat)
long_flat_k = ActiveSupport::KwstannardHWIA.new(long_flat)
long_flat_b = ActiveSupport::ByrootHWIA.new(long_flat)

Benchmark.ips do |x|
  x.report("original") { long_flat_baseline.to_hash }
  x.report("kwstannard") { long_flat_k.to_hash }
  x.report("byroot") { long_flat_b.to_hash }
  x.compare!(order: :baseline)
end

deep_baseline = ActiveSupport::HashWithIndifferentAccess.new(flat.dup)
3.times.reduce(deep_baseline) { |deep, _| deep[:deep] = ActiveSupport::HashWithIndifferentAccess.new(flat.dup) }

deep_k = ActiveSupport::KwstannardHWIA.new(flat.dup)
3.times.reduce(deep_k) { |deep, _| deep[:deep] = ActiveSupport::KwstannardHWIA.new(flat.dup) }

deep_b = ActiveSupport::ByrootHWIA.new(flat.dup)
3.times.reduce(deep_b) { |deep, _| deep[:deep] = ActiveSupport::ByrootHWIA.new(flat.dup) }

Benchmark.ips do |x|
  x.report("original") { deep_baseline.to_hash }
  x.report("kwstannard") { deep_k.to_hash }
  x.report("byroot") { deep_b.to_hash }
  x.compare!(order: :baseline)
end

```

```
$ ruby /tmp/to_hash.rb
Fetching gem metadata from https://rubygems.org/..........
Resolving dependencies...
ruby 3.3.1 (2024-04-23 revision c56cd86388) [arm64-darwin23]
Warming up --------------------------------------
            original    92.830k i/100ms
          kwstannard   125.443k i/100ms
              byroot   139.810k i/100ms
Calculating -------------------------------------
            original    968.200k (± 2.9%) i/s -      4.920M in   5.086600s
          kwstannard      1.268M (± 2.9%) i/s -      6.398M in   5.049545s
              byroot      1.397M (± 2.9%) i/s -      6.990M in   5.008404s

Comparison:
            original:   968200.3 i/s
              byroot:  1397069.4 i/s - 1.44x  faster
          kwstannard:  1268207.5 i/s - 1.31x  faster

ruby 3.3.1 (2024-04-23 revision c56cd86388) [arm64-darwin23]
Warming up --------------------------------------
            original    11.051k i/100ms
          kwstannard    15.865k i/100ms
              byroot    17.778k i/100ms
Calculating -------------------------------------
            original    109.059k (± 5.1%) i/s -    552.550k in   5.082820s
          kwstannard    157.499k (± 7.4%) i/s -    793.250k in   5.072103s
              byroot    177.066k (± 7.2%) i/s -    888.900k in   5.052601s

Comparison:
            original:   109059.1 i/s
              byroot:   177065.9 i/s - 1.62x  faster
          kwstannard:   157499.0 i/s - 1.44x  faster

ruby 3.3.1 (2024-04-23 revision c56cd86388) [arm64-darwin23]
Warming up --------------------------------------
            original    22.249k i/100ms
          kwstannard    30.132k i/100ms
              byroot    34.116k i/100ms
Calculating -------------------------------------
            original    224.127k (± 1.7%) i/s -      1.135M in   5.064253s
          kwstannard    295.912k (± 5.9%) i/s -      1.476M in   5.007324s
              byroot    343.225k (± 1.7%) i/s -      1.740M in   5.070715s

Comparison:
            original:   224127.0 i/s
              byroot:   343224.6 i/s - 1.53x  faster
          kwstannard:   295912.4 i/s - 1.32x  faster
```
2024-06-30 09:33:55 +02:00
Hartley McGuire
564e427c05
Remove obsolete Logger severity predicates
The Logger severity predicates have existed since the [introduction of
Logger][1]. However, these methods only looked at the `level` instance
variable, so they did not work with the [thread safe implementation][2]
of temporary log levels in Rails.

Since then, the Logger severity predicates were [updated][3] to use the
`level` method instead of the instance variable, making Rails' severity
predicate overrides obsolete.

This commit removes Rails' custom severity predicates in favor of
Logger's implementation, since the new implementation was released in
Logger 1.4.2 and came bundled with Ruby 2.7.0.

[1]: ruby/logger@525b58d97e
[2]: rails/rails@629efb6057
[3]: ruby/logger@7365c995bf
2024-06-26 21:19:12 +00:00
Rafael Mendonça França
716e4a7d32
Merge pull request #52091 from jasonkim/to-time-use-timezone
Add a config for preserving timezone information when calling `to_time` on TimeWithZone object
2024-06-26 16:16:05 -04:00
Rafael Mendonça França
f46d06b3b5
Merge pull request #52031 from matthewd/quieter-to_time
Don't emit to_time deprecations in known-safe contexts
2024-06-26 16:09:59 -04:00
Jean Boussier
cac62630a3 Lazily generate assertion failure messages
Some of them can be a bit costly to generate, particularly
when inspecting very large objects or when accessing the AST
of procs.

Minitest supports passing the message as a callable, which allow
us to defer all these computations.
2024-06-19 20:06:42 +02:00
Jean Boussier
869c7bf094 Improve BacktraceCleaner code example [ci-skip]
With newer rubies, removing a prefix is much simpler.
2024-06-19 09:16:30 +02:00
Jason Kim
9dcf17ec4c Add a config for preserving timezone information
when calling `to_time` on TimeWithZone object

Co-authored-by: jhawthorn <jhawthorn@github.com>
2024-06-13 14:56:40 -07:00
John Hawthorn
2627c953cb
Avoid using to_time in TimeWithZone#-
We're more likely to already have utc and can avoid constructing the
extra time object, and this will avoid deprecations on unconfigured
to_time_preserves_timezone.
2024-06-13 19:37:54 +00:00
Jean Boussier
514d474836 Fix a performance regression in attribute methods
Fix: #52111
Fix: 5dbc7b4

The above commit caused the size of the `CodeGenerator` method cache
to explode, because the dynamic namespace is way too granular.

But there is actually a much better fix for that, since `alias_attribute`
is now generating exactly the same code as the attribute it's aliasing,
we can generated it as the canonical method in the cache, and then just
define it in the model as the aliased name.

This prevent the cache from growing a lot, and even reduce memory
usage further as the original attribute and its alias now share
the same method cache.
2024-06-13 17:50:11 +02:00
Igor Depolli
4813a0f036
[ActiveSupport] Add option filter on in_order_of (#52072)
* [ActiveSupport] Add option 'filter' on 'in_order_of'

* Update activesupport/lib/active_support/core_ext/enumerable.rb

Co-authored-by: Willian Gustavo Veiga <willianveiga@users.noreply.github.com>

---------

Co-authored-by: Willian Gustavo Veiga <willianveiga@users.noreply.github.com>
Co-authored-by: Rafael Mendonça França <rafael@rubyonrails.org>
2024-06-12 15:13:50 -07:00
Rafael Mendonça França
68b6a1cc57
Merge pull request #52064 from feliperaul/improve_message_verifier_and_signed_id_docs
[ci skip] Improve ActiveSupport::MessageVerifier and ActiveRecord::SignedId docs
2024-06-12 18:00:28 -04:00
Felipe
ad20d9e7ec
Improve ActiveSupport::MessageVerifier and ActiveRecord::SignedId docs
The documentation on ActiveSupport::MessageVerifier used the “sensitive data” string as an example; that wording might induce the developer to think we’re dealing with encryption, while the payload is actually only Base64 encoded and is not protected at all.

We also improve the documentation on ActiveRecord::SignedId, which uses MessageVerifier and thereby will also expose the ID as encoded cleartext, making explicit that it’s not encryption, only signing.

Lastly, we refer the developer to MessageEncryptor if the payload needs to be encrypted.
2024-06-12 20:46:27 +00:00
Justin Ko
07325dc26f Do not use SyntaxError#path
Fixes #52089
2024-06-11 20:26:18 -06:00
Matthew Draper
d47c37183a Don't emit to_time deprecations in known-safe contexts
If the value is already a local time, there's no difference, so no need
to warn.

Correspondingly, avoid calling to_time in the handful of places we were
using it internally: it's easy to do, and we know we don't care about
the zone.
2024-06-11 15:51:46 -07:00
Richard Böhme
38e9695c10 Improve error message when passing a proc to assert_difference
Previously if `assert_difference` called with a proc fails, the inspect
output of the proc object was shown. This is not helpful to identify
what went wrong.

With this commit we leverage the experimental
`RubyVM::AbstractSyntaxTree` api of MRI to print the source code of the
proc that was passed to `assert_difference`. On all other platforms the
behavior stays the same.

The same applies to `assert_changes`.
2024-06-09 10:46:27 +02:00
John Hawthorn
a472403d55
Merge pull request #52034 from jhawthorn/ruby_time_zone_object_support
Improve support for using ActiveSupport::TimeZone as a ::Time object's timezone
2024-06-08 15:40:46 -07:00
John Hawthorn
a376cc2e49 Mark TimeZone TZInfo quacking methods as :nodoc: 2024-06-07 20:24:12 -07:00
John Hawthorn
edc7018742 Add ActiveSupport::TimeZone#dst?
Like abbr, this is used by Ruby when specifying creating a ::Time with a
zone object.
2024-06-06 10:51:18 -07:00
John Hawthorn
262713413c Add ActiveSupport::TimeZone#abbr
As of Ruby 2.6, ::Time supports rich timezone objects and expects them
to follow a similar API to tzinfo. Mostly we already do this with
ActiveSupport::TimeZone, delegating to the underlying tzinfo object,
except we were missing the API to display the timezone's name.

Calling strftime with "%Z" will try the following on the timezone:
* zone.abbr(time)
* zone.strftime("%Z", time)
* zone.name

Because we only implemented name, a ::Time created with an
ActiveSupport::TimeZone would "abbreviate" awkwardly to the full tz
identifier (like "12:34:00 America/Vancouver" instead of "12:34:00
PDT"). This commit implements abbr to make these Times format the same
way as TimeWithZone.

Co-authored-by: Jason Kim <jasonkim@github.com>
2024-06-06 10:43:34 -07:00
Carlos Antonio da Silva
fd5542ee1c Remove changelog, change backported to 7-2-stable
[ci skip]
2024-06-05 11:03:18 -03:00
Earlopain
d9adf17fbe
Add an explicit dependency on the logger gem
This is getting the same treatment as `base64`, `mutex_m`, etc.
In Ruby 3.4 it will start to warn: d7e558e3c4

Remoce require from two files that don't seem to need it
2024-06-05 13:53:33 +02:00
Rafael Mendonça França
f4c39b5e2d
Merge pull request #51994 from matthewd/preserves-timezone-very-deprecated
Re-roll deprecation of to_time_preserves_timezone
2024-06-04 11:02:11 -04:00
Matthew Draper
595c3ccc47 Re-roll deprecation of to_time_preserves_timezone
We realised the previous deprecation hadn't been warning for all users.
2024-06-03 00:57:09 +09:30
Matthew Draper
43fcdfa4d0 Revert "Remove deprecated support for the pre-Ruby 2.4 behavior of to_time"
This reverts commit b1b2c6d59c3e82ff8eed95f5556a902a4c03abd9.
2024-06-02 23:52:59 +09:30
Petrik
4735418d0d Use :nodoc: for alias_method instead of :stopdoc: [ci-skip]
RDoc 6.7 now hides `alias_method`s marked with `:nodoc:`.
2024-06-01 11:49:38 +02:00
Rafael Mendonça França
157f1df8fb
Require action_view/helpers instead of rails-html-sanitizer
This will avoid a warning about circular dependencies.

/circular require considered harmful.*rails-html-sanitizer/

This happens because `rails-html-sanitizer` requires `action_view/helpers`
that requires `action_view/helpers/sanitize_helper` that requires
`rails-html-sanitizer`.

I'll properly fix this in rails-html-sanitizer later removing the code
that needs to be added to ActionView::Helpers in that gem.
2024-05-31 20:25:06 +00:00
Rafael Mendonça França
91a441b650
Merge pull request #51939 from ElMassimo/fix-broadcast-logger-compatibility
Improve compatibility for `ActiveSupport::BroadcastLogger`
2024-05-30 14:32:40 -04:00
Maximo Mussini
944bc895ca Improve compatibility between Logger and ActiveSupport::BroadcastLogger
The usage of `dispatch` in all logging methods causes common usages such
as `logger.info` to return an array of loggers, making it unsafe for an
application to upgrade to Rails 7.1.

Returning `nil` is more efficient, and is the default behavior when
using `Logger`.
2024-05-30 13:07:05 -03:00
Maximo Mussini
a054307bbc
Improve compatibility between Logger and ActiveSupport::BroadcastLogger
The usage of `dispatch` in all logging methods causes common usages such
as `logger.info` to return an array of loggers, making it unsafe for an
application to upgrade to Rails 7.1.

Returning `nil` is more efficient, and is the default behavior when
using `Logger`.
2024-05-29 22:18:37 +00:00
Jean Boussier
f719787c58 Restore automatic detection of processor count in default puma config
It has to be reverted because the previous implementation wasn't
cgroup aware so it would often start way too many processes on various
shared hosting platforms.

Thanks to https://github.com/ruby-concurrency/concurrent-ruby/pull/1038
concurrent-ruby 1.3 now offer a cgroups aware method to detect how
many processors we can actually use.
2024-05-29 16:46:51 +02:00
Xavier Noria
a7d7e3d884 Define Digest::UUID.nil_uuid 2024-05-29 14:41:30 +02:00
David Heinemeier Hansson
1b3fc3c82e
Change asset pipeline default to Propshaft in Rails 8 (#51799)
* Change asset pipeline default to Propshaft

* Use :all for stylesheets when propshaft is active

* Switch to using propshaft as the default (still need to find a way to tests against sprockets too)

* Fix tests that rely on sprockets being used

* Fix Propshaft tests (#51913)

* Update railties/test/generators/shared_generator_tests.rb

Co-authored-by: Lázaro Nixon <lazaronixon@hotmail.com>

---------

Co-authored-by: Lázaro Nixon <lazaronixon@hotmail.com>
2024-05-25 20:48:35 -07:00
Rafael Mendonça França
ad41f711ce
Merge pull request #51846 from simi/base64-standard-error
Catch StandardError during Base64 decoding in message encryptor.
2024-05-24 16:00:43 -04:00
Rafael Mendonça França
7ee34d9efb
Enable Rails minitest plugin in our rake tasks 2024-05-23 16:16:37 +00:00
Rafael Mendonça França
c0a2b28038
Revert "Merge pull request #50489 from maniSHarma7575/50481-fix-activesupport-json-encode"
This reverts commit 7b9e9ee244350eeb89cd4bb4ac1ff817d82f3669, reversing
changes made to 590a675c4ecfaa9b7b06787a30adeb0136524879.

Reason: https://github.com/rails/rails/pull/50489#issuecomment-2123881327
2024-05-22 18:13:23 +00:00
Yasuo Honda
692f25a925
Merge pull request #51856 from yahonda/restore_warning_condition_for_ruby34
Restore unused block warnings condition for Ruby 3.4
2024-05-21 08:46:51 +09:00
nikhilbhatt
575c6413bb Fix exception raised from template should not show compiled code 2024-05-20 17:07:19 +09:00
Yasuo Honda
cba2b2f588 Restore unused block warnings condition for Ruby 3.4
https://github.com/ruby/ruby/pull/10403 raised many "the block passed to" warnings.
then idnored these warnings because some of them might have contain false positives.

Now we can restore the warning condition
because these false positives should have been addressed by these changes:

https://github.com/ruby/ruby/pull/10559
https://github.com/rails/rails/pull/51597
https://github.com/rails/rails/pull/51583
2024-05-18 08:57:11 +09:00
Josef Šimánek
a27a038dc3 Catch StandardError during Base64 decoding in message encryptor. 2024-05-16 03:24:52 +02:00
zzak
f12bbb61d1
Revert "Pin minitest version to 5.21" 2024-05-15 18:05:43 -04:00
Graham Cooper
b09ae673ab
Pass options to write_entry in handle_expired_entry method 2024-05-14 22:56:50 +00:00
Rafael Mendonça França
bf59d363fb
Clean CHANGELOG for 8.0 2024-05-13 16:55:52 +00:00
Rafael Mendonça França
37fd0e7fe4
Development of Rails 8.0 starts now
🎉
2024-05-13 16:45:20 +00:00
Carlos Antonio da Silva
a6e2bb04dd
Merge pull request #51651 from heka1024/support-duration-in-xml
Support duration in `ActiveSupport::XmlMini`
2024-05-13 13:34:50 -03:00
Jean Boussier
06d3b358df Replace allocations count by GC time in request logs
Allocations count is often an interesting proxy for performance,
but not necessarily the most relevant thing to include in request
logs, given they aren't a per thread metric, so the reporting
is widely innacurate in multi-threaded environments.

Since Ruby 3.1 there is now `GC.total_time` which is a monotonically
increasing counter of time spent in GC. It still isn't really a per
thread metric, but is is more interesting because it uses the same
unit as the response time, allowing to better see when you have a GC
pause performance issue.
2024-05-08 23:02:35 +02:00
heka1024
b681bb6df2 Support duration in ActiveSupport::XmlMini 2024-05-04 21:37:45 +09:00
Rafael Mendonça França
2dc20197da
Remove unnecessary deprecation silencing in cache_store_compression_behavior.rb 2024-05-01 18:45:47 +00:00
Rafael Mendonça França
c48aab17ce
Remove deprecated ActiveSupport::Notifications::Event#children and ActiveSupport::Notifications::Event#parent_of? 2024-05-01 18:45:46 +00:00
Rafael Mendonça França
fc2dc7c8d3
Remove deprecated support to call the following methods without passing a deprecator
- `deprecate`
  - `deprecate_constant`
  - `ActiveSupport::Deprecation::DeprecatedObjectProxy.new`
  - `ActiveSupport::Deprecation::DeprecatedInstanceVariableProxy.new`
  - `ActiveSupport::Deprecation::DeprecatedConstantProxy.new`
  - `assert_deprecated`
  - `assert_not_deprecated`
  - `collect_deprecations`
2024-05-01 18:45:45 +00:00
Rafael Mendonça França
c682bf2641
Remove deprecated ActiveSupport::Deprecation delegation to instance 2024-05-01 18:45:44 +00:00