Commit Graph

8594 Commits

Author SHA1 Message Date
Asherah Connor
2e14c53fc6
Add Enumerable#sole (#40914)
* Add `Enumerable#sole`, from `ActiveRecord::FinderMethods#sole`

* distinguish single-item Enumerable and two-item with nil last

Add a test for same.

* add symmetry, against rubocop's wishes
2021-04-19 11:26:34 +02:00
Zachary Scott
43e29f0f5d
Merge pull request #41945 from jbampton/fix-grammar
chore: fix grammar, spelling and minor whitespace fix
2021-04-14 09:19:15 +09:00
Rafael Mendonça França
94b954576a
Autocorrect Rubocop roles 2021-04-13 18:32:25 +00:00
Andrew White
b259fbcf09
Merge pull request #41957 from rails/simplify-find-timezone
Simplify Time.find_timezone! logic
2021-04-13 19:13:31 +01:00
Jean Boussier
c1501e04d0 Add a test case for race_condition_ttl with local_cache enabled 2021-04-13 18:07:12 +02:00
Jean byroot Boussier
62eb0b9c57
Revert "Refactor LocalCache to avoid calling Marshal.dump as much" 2021-04-13 18:03:51 +02:00
Andrew White
f6893cd242
Simplify Time.find_timezone! logic
By pushing the checks for TZInfo::Timezone and ActiveSupport::TimeZone
down into the case statement inside the `[]` method we can radically
simplify the logic inside of the `find_timezone!` method.

There's an edge case where passing an invalid argument to `[]` via the
`find_timezone!` method generates a slightly different message for the
`ArgumentError` exception and this is maintained in the unlikely case
someone was relying on the difference.
2021-04-13 16:25:58 +01:00
Ryuta Kamizono
a295612ebf
Merge pull request #41942 from caffkane/as-twz-dep-warn-correction
Correct misspelling in as-twz-deprecation message
2021-04-13 22:26:09 +09:00
John Bampton
54e526e473 chore: fix grammar, spelling and minor whitespace fix 2021-04-13 21:35:50 +10:00
Jean Boussier
8d34f769ce Revert "Merge pull request #41931 from MarcelEeken/deep-merge-changing-original-hash"
This reverts commit 483d36ae0903b8b2c989e6b28c6ae4e83f82985a, reversing
changes made to b171b842da8a4221d327ba94a187d8914f661bd4.
2021-04-13 12:12:03 +02:00
Andrew White
06b294a24c
Freeze ActiveSupport::Duration#parts hash
Durations are meant to be value objects and should not be mutated.
2021-04-13 09:22:42 +01:00
Andrew White
697edcb30f
Fix ActiveSupport::TimeZone#utc_to_local
When utc_to_local_returns_utc_offset_times is false and the time
instance had fractional seconds the new UTC time instance was out
by a factor of 1,000,000 as the Time.utc constructor takes a usec
value and not a fractional second value.
2021-04-13 08:58:35 +01:00
Logan Kane
1b01e47e0d Correct misspelling in as-twz-deprecation message 2021-04-12 21:08:02 -07:00
Jean Boussier
93e5388653 Restore the Entry#bytesize comments removed in #41882 2021-04-12 23:15:02 +02:00
Rafael França
8210d0a9d8
Merge pull request #41938 from Shopify/as-twz-name-deprecation
Allow to opt-in to the new TimeWithZone.name and fix XmlMini serialization
2021-04-12 16:26:39 -04:00
Jean Boussier
3457a4676d Allow to opt-in to the new TimeWithZone.name and fix XmlMini serialization 2021-04-12 22:03:31 +02:00
Rafael França
483d36ae09
Merge pull request #41931 from MarcelEeken/deep-merge-changing-original-hash
Deep duplicate in `deep_merge` so no references remain to the original hash in the result
2021-04-12 15:53:35 -04:00
Rafael Mendonça França
4354e3ae49
Don't define methods using the method modifier in the same line as the method
Our style guide use block method modifiers, not inline method modifiers.
2021-04-12 18:49:54 +00:00
Marcel Eeken
71ab41a099
Deep duplicate in deep_merge so no references remain to the original hash in the result
When deep merging a Hash, first a duplicate is created. The duplicate only
does a shallow copy, so deeper level structures are not duplicated but
remain references.

This can lead to unexpected modifications of the original hash when a deeply
nested hash is merged with another hash, and the newly returned hash gets modified.
```
  x = { a: { b: "foo" } }
  y = { d: { e: "bar" } }

  z = x.deep_merge(y)
  # z => { a: { b: "foo" }, d: { e: "bar" } }

  z[:a][:b] = "baz"
  # z => { a: { b: "baz" }, d: { e: "bar" } }
  # x => { a: { b: "baz" } }
```
2021-04-12 15:03:32 +02:00
John Bampton
13b1d9dc35 chore: fix grammar and spelling 2021-04-12 05:30:44 +10:00
Jean Boussier
3f59640016 Stop checking if ruby2_keywords is defined 2021-04-11 13:42:02 +02:00
Jean Boussier
466a54f766
Merge pull request #41882 from Shopify/local-store-dup-value
Refactor LocalCache to avoid calling Marshal.dump as much
2021-04-10 20:33:07 +02:00
Jean Boussier
084ba0ead0 Refactor LocalCache to avoid calling Marshal.dump as much 2021-04-08 18:06:24 +02:00
Jean Boussier
bade613012 Make sure Inflector.underscore returns a String
If you were to pass it an underscore symbol, it
would be immediately returned without modification.
2021-04-08 16:26:45 +02:00
Andrew White
3dd0af563b
Merge pull request #41873 from rails/prevent-deprecation-warning-with-yaml-twz
Use YAML.load_tags/dump_tags to prevent deprecation warnings
2021-04-08 12:04:26 +01:00
Jean Boussier
7057ccf656 Directly delegate constantize to Object.const_get
All the complexity of that method was to work around various
problems caused by Ruby's constant lookup semantic as well
as the classic autoloader shortcommings.

Now that Rails require Ruby 2.7 I don't think we need anything
more than just `Object.const_get`.

```ruby
require 'benchmark/ips'
require 'active_support/all'

module Foo
  module Bar
    module Baz
    end
  end
end

def patched_constantize(name)
  Object.const_get(name)
end

Benchmark.ips do |x|
  x.report('orig') { ActiveSupport::Inflector.constantize("Foo::Bar::Baz") }
  x.report('patched') { patched_constantize("Foo::Bar::Baz") }
  x.compare!
end
```

```
Warming up --------------------------------------
                orig    69.668k i/100ms
             patched   391.385k i/100ms
Calculating -------------------------------------
                orig    705.027k (± 1.9%) i/s -      3.553M in   5.041486s
             patched      3.935M (± 1.1%) i/s -     19.961M in   5.072912s

Comparison:
             patched:  3935235.5 i/s
                orig:   705027.2 i/s - 5.58x  (± 0.00) slower
```
2021-04-08 09:58:52 +02:00
Andrew White
db9ba18659
Use YAML.load_tags/dump_tags to prevent deprecation warnings
The default behavior of the Psych gem for Ruby classes is to call the
`name` method to generate a tag for encoding. However this causes a
stream of deprecation warnings whenever ActiveSupport::TimeWithZone
instances are encoded into YAML. By utilising the load_tags/dump_tags
configuration we can prevent Psych from calling the `name` method and
thereby prevent the triggering of the deprecation warnings.
2021-04-07 23:31:09 +01:00
Jean Boussier
fe8f47b425
Merge pull request #41831 from Shopify/as-cache-clock-gettime
Allow to set cache expiry as an absolute timestamp
2021-04-07 09:10:02 +02:00
Xavier Noria
27624077e6 Delete orphan autoloading fixtures
Rails now delegates autoloading to Zeitwerk, and therefore does not need to test
autoloading itself. Zeitwerk has test coverage, in Rails we only need to test
the integration.

We are gradually trimming AS::Dependencies, and the AS test suite. With the
removal of DependenciesTestHelpers and client code in af27a25, these fixtures
became orphan.

Three of them are left. They are to be autoloaded with Module#autoload because
they raise errors when the file is evaluated. Their current use cases are
already committed.
2021-04-06 20:14:10 +02:00
Jean Boussier
9de17ac4a4 Allow to set cache expiry as an absolute timestamp
Sometime it can be useful to set a cache entry expiry
not relative to current time, but as an absolute timestamps,
e.g.:

  - If you want to cache an API token that was provided to
    you with a precise expiry time.
  - If you want to cache something until a precise cutoff
    time, e.g. `expires_at: Time.now.at_end_of_hour`

This leaves the `@created_at` variable in a weird state,
but this is to avoid breaking the binary format.
2021-04-06 10:49:05 +02:00
Andrew White
3f4b41a6f5
Deprecate ActiveSupport::TimeWithZone.name
In c00f2d2 the `name` method was overridden to return 'Time' instead of
the real class name 'ActiveSupport::TimeWithZone'. The reasoning for
this is unclear and it can cause confusion for developers assuming that
name is returning the real class name. Since we don't know why this
was added, we're deprecating the method first to give developers a
chance to provide us with feedback and look to fix any issues that arise.
2021-04-04 16:57:51 +01:00
Xavier Noria
af27a25f19 Remove DependenciesTestHelpers 2021-04-03 19:24:12 +02:00
Xavier Noria
5f70349b05 Remove with_autoloading_fixtures from the AS::Testing::ConstantLookup test suite
The rewritten test is not super clean with the manual cleanup etc.. If this is a
one-off it's not a big deal. However, if in subsequent rewrites I spot more
occurrences of this pattern, then I'll refactor.
2021-04-03 19:24:12 +02:00
Tietew
92b8cda4c9
secure_compare: Check byte size instead of length
Match fixed_length_secure_compare's guard clause.

References #39142.
2021-04-02 12:45:29 -04:00
Lee Quarella
65f350166a Remove overwriting test_order
Reverts a change from
2327ebfdc6
which can overwrite `test_order` that may have been manually set in
config. This can cause a situation where the user is depending on a
particular `test_order` but is unknowingly forced into another.
2021-03-31 11:50:08 -04:00
Jean Boussier
d612542336
Merge pull request #41801 from Shopify/optimize-numeric-to-s
Optimize ActiveSupport::NumericWithFormat#to_s
2021-03-31 09:22:43 +02:00
Jean Boussier
31c20e248a Optimize ActiveSupport::NumericWithFormat#to_s
`case format when nil` is very efficient because it end up calling `NilClass === nil`
which pretty much translates to `nil.is_a?(NilClass)`.

On the other hand `format.nil?` benefit from a dedicated op code, so it's quite faster.

In this case `Integer#to_s` is much more often called without any arguments,
so it's worth optimizing for the most common case.

```ruby
class Integer
  alias_method :faster_to_s, :to_s
end
require 'active_support/all'
require 'benchmark/ips'

module FasterNumericWithFormat
  def faster_to_s(format = nil, options = nil)
    if format.nil?
      return super()
    end

    case format
    when Integer, String
      super(format)
    when :phone
      ActiveSupport::NumberHelper.number_to_phone(self, options || {})
    when :currency
      ActiveSupport::NumberHelper.number_to_currency(self, options || {})
    when :percentage
      ActiveSupport::NumberHelper.number_to_percentage(self, options || {})
    when :delimited
      ActiveSupport::NumberHelper.number_to_delimited(self, options || {})
    when :rounded
      ActiveSupport::NumberHelper.number_to_rounded(self, options || {})
    when :human
      ActiveSupport::NumberHelper.number_to_human(self, options || {})
    when :human_size
      ActiveSupport::NumberHelper.number_to_human_size(self, options || {})
    when Symbol
      super()
    else
      super(format)
    end
  end
end

Integer.prepend(FasterNumericWithFormat)

Benchmark.ips do |x|
  x.report('orig no-arg') { 42.to_s }
  x.report('fast no-arg') { 42.faster_to_s }
  x.compare!
end

Benchmark.ips do |x|
  x.report('orig :human') { 42.to_s(:human) }
  x.report('fast :human') { 42.faster_to_s(:human) }
  x.compare!
end
```

Ruby 2.7.2
```
Warming up --------------------------------------
         orig no-arg   567.569k i/100ms
         fast no-arg   692.636k i/100ms
Calculating -------------------------------------
         orig no-arg      5.709M (± 1.3%) i/s -     28.946M in   5.070660s
         fast no-arg      6.892M (± 0.7%) i/s -     34.632M in   5.024961s

Comparison:
         fast no-arg:  6892287.7 i/s
         orig no-arg:  5709450.0 i/s - 1.21x  (± 0.00) slower

Warming up --------------------------------------
         orig :human   575.000  i/100ms
         fast :human   619.000  i/100ms
Calculating -------------------------------------
         orig :human      6.176k (± 1.6%) i/s -     31.050k in   5.028656s
         fast :human      6.179k (± 1.8%) i/s -     30.950k in   5.010372s

Comparison:
         fast :human:     6179.1 i/s
         orig :human:     6176.3 i/s - same-ish: difference falls within error

```
2021-03-30 15:41:20 +02:00
John Hawthorn
3a770b2197 Fix LogSubscriber for buffered event w/ nil logger
LogSubscriber overrides start/finish to avoid instrumenting when its
logger is nil. In order to support buffered notification events, as used
by async queries, we need to apply a similar override to
LogSubscriber#publish_event.
2021-03-29 17:31:07 -07:00
Steve Laing
d4186a76c8 Raise ArgumentError from TimeZone.iso8601 when invalid value can be parsed by Date._iso8601
Date._iso8601 will return a hash for some values eg. '12936' but this will not contain the expected :mon and :mday keys.
Check for these keys and raise an ArgumentError if they aren't present as this is consistent with other invalid input behaviour.
2021-03-26 09:10:45 +00:00
Eileen M. Uchitelle
ad9e52066c
Merge pull request #41684 from ricardotk002/disable-parallel-testing
Disable parallel testing when running individual files
2021-03-23 09:06:57 -04:00
Jean Boussier
a40fca290d Use triple-dot delegation in ForkTracker 2021-03-23 08:52:29 +01:00
Ryuta Kamizono
19fd39b672 to_yaml requires require "yaml"
https://buildkite.com/rails/rails/builds/75966#6b542bd0-82ce-4463-badf-7a68af7d3208/1055-1977
2021-03-23 08:51:39 +09:00
Ryuta Kamizono
3e71243b10 Parsing type="yaml" node requires require "yaml" 2021-03-23 08:45:46 +09:00
Ryuta Kamizono
d7f5f4f97f Fix test_from_trusted_xml_allows_symbol_and_yaml_types failure
Caused by #41712.

https://buildkite.com/rails/rails/builds/75962#984c08aa-f57f-4f1c-ab31-7674fac12bbe/975-1397
2021-03-23 08:29:09 +09:00
Rafael Mendonça França
741099e995
Really make OrderedHash private to the framework
Related to 0dd76540327be58999b0cb7584277724e60486d3.
2021-03-22 22:13:23 +00:00
Ryuta Kamizono
1ef30c19b5
Merge pull request #41712 from okuramasafumi/remove-ordered-hash
Remove requires and references to OrderedHash
2021-03-22 22:01:26 +09:00
OKURA Masafumi
0dd7654032 Remove some references to OrderedHash
OrderedHash is deprecated but there are some requires and references
to OrderedHash, which might be confusing.
As described in
https://github.com/rails/rails/issues/22681#issuecomment-166059717
OrderedHash is internal only so references in the docs should be
removed.
2021-03-22 21:14:32 +09:00
Ryuta Kamizono
8c7883d3fc ✂️ [ci skip] 2021-03-22 04:46:11 +09:00
Ryuta Kamizono
1dcad65f80
Merge pull request #41707 from okuramasafumi/add-missing-require-to-hash_with_indifferent_access
Add missing require to hash_with_indifferent_access
2021-03-21 15:19:44 +09:00
OKURA Masafumi
8a56380c53
Add documentation to HashWithIndifferentAccess#except
https://api.rubyonrails.org/classes/ActiveSupport/HashWithIndifferentAccess.html#method-i-except
Currently HashWithIndifferentAccess#except has no documentation.
Since it's behavior is different from Hash#except, so it deserves
its own documentation.
2021-03-20 10:37:13 -04:00