diff options
Diffstat (limited to 'activesupport')
448 files changed, 4476 insertions, 975 deletions
diff --git a/activesupport/CHANGELOG.md b/activesupport/CHANGELOG.md index ab5237488a..3f77b191f9 100644 --- a/activesupport/CHANGELOG.md +++ b/activesupport/CHANGELOG.md @@ -1,3 +1,389 @@ +* `assert_changes` will always assert that the expression changes, + regardless of `from:` and `to:` argument combinations. + + *Daniel Ma* + +* Allow the hash function used to generate non-sensitive digests, such as the + ETag header, to be specified with `config.active_support.hash_digest_class`. + + The object provided must respond to `#hexdigest`, e.g. `Digest::SHA1`. + + *Dmitri Dolguikh* + + +## Rails 5.2.0.beta2 (November 28, 2017) ## + +* No changes. + + +## Rails 5.2.0.beta1 (November 27, 2017) ## + +* Changed default behaviour of `ActiveSupport::SecurityUtils.secure_compare`, + to make it not leak length information even for variable length string. + + Renamed old `ActiveSupport::SecurityUtils.secure_compare` to `fixed_length_secure_compare`, + and started raising `ArgumentError` in case of length mismatch of passed strings. + + *Vipul A M* + +* Make `ActiveSupport::TimeZone.all` return only time zones that are in + `ActiveSupport::TimeZone::MAPPING`. + + Fixes #7245. + + *Chris LaRose* + +* MemCacheStore: Support expiring counters. + + Pass `expires_in: [seconds]` to `#increment` and `#decrement` options + to set the Memcached TTL (time-to-live) if the counter doesn't exist. + If the counter exists, Memcached doesn't extend its expiry when it's + incremented or decremented. + + ``` + Rails.cache.increment("my_counter", 1, expires_in: 2.minutes) + ``` + + *Takumasa Ochi* + +* Handle `TZInfo::AmbiguousTime` errors + + Make `ActiveSupport::TimeWithZone` match Ruby's handling of ambiguous + times by choosing the later period, e.g. + + Ruby: + ``` + ENV["TZ"] = "Europe/Moscow" + Time.local(2014, 10, 26, 1, 0, 0) # => 2014-10-26 01:00:00 +0300 + ``` + + Before: + ``` + >> "2014-10-26 01:00:00".in_time_zone("Moscow") + TZInfo::AmbiguousTime: 26/10/2014 01:00 is an ambiguous local time. + ``` + + After: + ``` + >> "2014-10-26 01:00:00".in_time_zone("Moscow") + => Sun, 26 Oct 2014 01:00:00 MSK +03:00 + ``` + + Fixes #17395. + + *Andrew White* + +* Redis cache store. + + ``` + # Defaults to `redis://localhost:6379/0`. Only use for dev/test. + config.cache_store = :redis_cache_store + + # Supports all common cache store options (:namespace, :compress, + # :compress_threshold, :expires_in, :race_condition_ttl) and all + # Redis options. + cache_password = Rails.application.secrets.redis_cache_password + config.cache_store = :redis_cache_store, driver: :hiredis, + namespace: 'myapp-cache', compress: true, timeout: 1, + url: "redis://:#{cache_password}@myapp-cache-1:6379/0" + + # Supports Redis::Distributed with multiple hosts + config.cache_store = :redis_cache_store, driver: :hiredis + namespace: 'myapp-cache', compress: true, + url: %w[ + redis://myapp-cache-1:6379/0 + redis://myapp-cache-1:6380/0 + redis://myapp-cache-2:6379/0 + redis://myapp-cache-2:6380/0 + redis://myapp-cache-3:6379/0 + redis://myapp-cache-3:6380/0 + ] + + # Or pass a builder block + config.cache_store = :redis_cache_store, + namespace: 'myapp-cache', compress: true, + redis: -> { Redis.new … } + ``` + + Deployment note: Take care to use a *dedicated Redis cache* rather + than pointing this at your existing Redis server. It won't cope well + with mixed usage patterns and it won't expire cache entries by default. + + Redis cache server setup guide: https://redis.io/topics/lru-cache + + *Jeremy Daer* + +* Cache: Enable compression by default for values > 1kB. + + Compression has long been available, but opt-in and at a 16kB threshold. + It wasn't enabled by default due to CPU cost. Today it's cheap and typical + cache data is eminently compressible, such as HTML or JSON fragments. + Compression dramatically reduces Memcached/Redis mem usage, which means + the same cache servers can store more data, which means higher hit rates. + + To disable compression, pass `compress: false` to the initializer. + + *Jeremy Daer* + +* Allow `Range#include?` on TWZ ranges + + In #11474 we prevented TWZ ranges being iterated over which matched + Ruby's handling of Time ranges and as a consequence `include?` + stopped working with both Time ranges and TWZ ranges. However in + ruby/ruby@b061634 support was added for `include?` to use `cover?` + for 'linear' objects. Since we have no way of making Ruby consider + TWZ instances as 'linear' we have to override `Range#include?`. + + Fixes #30799. + + *Andrew White* + +* Fix acronym support in `humanize` + + Acronym inflections are stored with lowercase keys in the hash but + the match wasn't being lowercased before being looked up in the hash. + This shouldn't have any performance impact because before it would + fail to find the acronym and perform the `downcase` operation anyway. + + Fixes #31052. + + *Andrew White* + +* Add same method signature for `Time#prev_year` and `Time#next_year` + in accordance with `Date#prev_year`, `Date#next_year`. + + Allows pass argument for `Time#prev_year` and `Time#next_year`. + + Before: + ``` + Time.new(2017, 9, 16, 17, 0).prev_year # => 2016-09-16 17:00:00 +0300 + Time.new(2017, 9, 16, 17, 0).prev_year(1) + # => ArgumentError: wrong number of arguments (given 1, expected 0) + + Time.new(2017, 9, 16, 17, 0).next_year # => 2018-09-16 17:00:00 +0300 + Time.new(2017, 9, 16, 17, 0).next_year(1) + # => ArgumentError: wrong number of arguments (given 1, expected 0) + ``` + + After: + ``` + Time.new(2017, 9, 16, 17, 0).prev_year # => 2016-09-16 17:00:00 +0300 + Time.new(2017, 9, 16, 17, 0).prev_year(1) # => 2016-09-16 17:00:00 +0300 + + Time.new(2017, 9, 16, 17, 0).next_year # => 2018-09-16 17:00:00 +0300 + Time.new(2017, 9, 16, 17, 0).next_year(1) # => 2018-09-16 17:00:00 +0300 + ``` + + *bogdanvlviv* + +* Add same method signature for `Time#prev_month` and `Time#next_month` + in accordance with `Date#prev_month`, `Date#next_month`. + + Allows pass argument for `Time#prev_month` and `Time#next_month`. + + Before: + ``` + Time.new(2017, 9, 16, 17, 0).prev_month # => 2017-08-16 17:00:00 +0300 + Time.new(2017, 9, 16, 17, 0).prev_month(1) + # => ArgumentError: wrong number of arguments (given 1, expected 0) + + Time.new(2017, 9, 16, 17, 0).next_month # => 2017-10-16 17:00:00 +0300 + Time.new(2017, 9, 16, 17, 0).next_month(1) + # => ArgumentError: wrong number of arguments (given 1, expected 0) + ``` + + After: + ``` + Time.new(2017, 9, 16, 17, 0).prev_month # => 2017-08-16 17:00:00 +0300 + Time.new(2017, 9, 16, 17, 0).prev_month(1) # => 2017-08-16 17:00:00 +0300 + + Time.new(2017, 9, 16, 17, 0).next_month # => 2017-10-16 17:00:00 +0300 + Time.new(2017, 9, 16, 17, 0).next_month(1) # => 2017-10-16 17:00:00 +0300 + ``` + + *bogdanvlviv* + +* Add same method signature for `Time#prev_day` and `Time#next_day` + in accordance with `Date#prev_day`, `Date#next_day`. + + Allows pass argument for `Time#prev_day` and `Time#next_day`. + + Before: + ``` + Time.new(2017, 9, 16, 17, 0).prev_day # => 2017-09-15 17:00:00 +0300 + Time.new(2017, 9, 16, 17, 0).prev_day(1) + # => ArgumentError: wrong number of arguments (given 1, expected 0) + + Time.new(2017, 9, 16, 17, 0).next_day # => 2017-09-17 17:00:00 +0300 + Time.new(2017, 9, 16, 17, 0).next_day(1) + # => ArgumentError: wrong number of arguments (given 1, expected 0) + ``` + + After: + ``` + Time.new(2017, 9, 16, 17, 0).prev_day # => 2017-09-15 17:00:00 +0300 + Time.new(2017, 9, 16, 17, 0).prev_day(1) # => 2017-09-15 17:00:00 +0300 + + Time.new(2017, 9, 16, 17, 0).next_day # => 2017-09-17 17:00:00 +0300 + Time.new(2017, 9, 16, 17, 0).next_day(1) # => 2017-09-17 17:00:00 +0300 + ``` + + *bogdanvlviv* + +* `IO#to_json` now returns the `to_s` representation, rather than + attempting to convert to an array. This fixes a bug where `IO#to_json` + would raise an `IOError` when called on an unreadable object. + + Fixes #26132. + + *Paul Kuruvilla* + +* Remove deprecated `halt_callback_chains_on_return_false` option. + + *Rafael Mendonça França* + +* Remove deprecated `:if` and `:unless` string filter for callbacks. + + *Rafael Mendonça França* + +* `Hash#slice` now falls back to Ruby 2.5+'s built-in definition if defined. + + *Akira Matsuda* + +* Deprecate `secrets.secret_token`. + + The architecture for secrets had a big upgrade between Rails 3 and Rails 4, + when the default changed from using `secret_token` to `secret_key_base`. + + `secret_token` has been soft deprecated in documentation for four years + but is still in place to support apps created before Rails 4. + Deprecation warnings have been added to help developers upgrade their + applications to `secret_key_base`. + + *claudiob*, *Kasper Timm Hansen* + +* Return an instance of `HashWithIndifferentAccess` from `HashWithIndifferentAccess#transform_keys`. + + *Yuji Yaginuma* + +* Add key rotation support to `MessageEncryptor` and `MessageVerifier` + + This change introduces a `rotate` method to both the `MessageEncryptor` and + `MessageVerifier` classes. This method accepts the same arguments and + options as the given classes' constructor. The `encrypt_and_verify` method + for `MessageEncryptor` and the `verified` method for `MessageVerifier` also + accept an optional keyword argument `:on_rotation` block which is called + when a rotated instance is used to decrypt or verify the message. + + *Michael J Coyne* + +* Deprecate `Module#reachable?` method. + + *bogdanvlviv* + +* Add `config/credentials.yml.enc` to store production app secrets. + + Allows saving any authentication credentials for third party services + directly in repo encrypted with `config/master.key` or `ENV["RAILS_MASTER_KEY"]`. + + This will eventually replace `Rails.application.secrets` and the encrypted + secrets introduced in Rails 5.1. + + *DHH*, *Kasper Timm Hansen* + +* Add `ActiveSupport::EncryptedFile` and `ActiveSupport::EncryptedConfiguration`. + + Allows for stashing encrypted files or configuration directly in repo by + encrypting it with a key. + + Backs the new credentials setup above, but can also be used independently. + + *DHH*, *Kasper Timm Hansen* + +* `Module#delegate_missing_to` now raises `DelegationError` if target is nil, + similar to `Module#delegate`. + + *Anton Khamets* + +* Update `String#camelize` to provide feedback when wrong option is passed + + `String#camelize` was returning nil without any feedback when an + invalid option was passed as a parameter. + + Previously: + + 'one_two'.camelize(true) + # => nil + + Now: + + 'one_two'.camelize(true) + # => ArgumentError: Invalid option, use either :upper or :lower. + + *Ricardo DÃaz* + +* Fix modulo operations involving durations + + Rails 5.1 introduced `ActiveSupport::Duration::Scalar` as a wrapper + around numeric values as a way of ensuring a duration was the outcome of + an expression. However, the implementation was missing support for modulo + operations. This support has now been added and should result in a duration + being returned from expressions involving modulo operations. + + Prior to Rails 5.1: + + 5.minutes % 2.minutes + # => 60 + + Now: + + 5.minutes % 2.minutes + # => 1 minute + + Fixes #29603 and #29743. + + *Sayan Chakraborty*, *Andrew White* + +* Fix division where a duration is the denominator + + PR #29163 introduced a change in behavior when a duration was the denominator + in a calculation - this was incorrect as dividing by a duration should always + return a `Numeric`. The behavior of previous versions of Rails has been restored. + + Fixes #29592. + + *Andrew White* + +* Add purpose and expiry support to `ActiveSupport::MessageVerifier` & + `ActiveSupport::MessageEncryptor`. + + For instance, to ensure a message is only usable for one intended purpose: + + token = @verifier.generate("x", purpose: :shipping) + + @verifier.verified(token, purpose: :shipping) # => "x" + @verifier.verified(token) # => nil + + Or make it expire after a set time: + + @verifier.generate("x", expires_in: 1.month) + @verifier.generate("y", expires_at: Time.now.end_of_year) + + Showcased with `ActiveSupport::MessageVerifier`, but works the same for + `ActiveSupport::MessageEncryptor`'s `encrypt_and_sign` and `decrypt_and_verify`. + + Pull requests: #29599, #29854 + + *Assain Jaleel* + +* Make the order of `Hash#reverse_merge!` consistent with `HashWithIndifferentAccess`. + + *Erol Fornoles* + +* Add `freeze_time` helper which freezes time to `Time.now` in tests. + + *Prathamesh Sonpatki* + * Default `ActiveSupport::MessageEncryptor` to use AES 256 GCM encryption. On for new Rails 5.2 apps. Upgrading apps can find the config as a new @@ -56,15 +442,15 @@ * Fix implicit coercion calculations with scalars and durations - Previously calculations where the scalar is first would be converted to a duration - of seconds but this causes issues with dates being converted to times, e.g: + Previously, calculations where the scalar is first would be converted to a duration + of seconds, but this causes issues with dates being converted to times, e.g: Time.zone = "Beijing" # => Asia/Shanghai date = Date.civil(2017, 5, 20) # => Mon, 20 May 2017 2 * 1.day # => 172800 seconds date + 2 * 1.day # => Mon, 22 May 2017 00:00:00 CST +08:00 - Now the `ActiveSupport::Duration::Scalar` calculation methods will try to maintain + Now, the `ActiveSupport::Duration::Scalar` calculation methods will try to maintain the part structure of the duration where possible, e.g: Time.zone = "Beijing" # => Asia/Shanghai diff --git a/activesupport/MIT-LICENSE b/activesupport/MIT-LICENSE index 6b3cead1a7..8f769c0767 100644 --- a/activesupport/MIT-LICENSE +++ b/activesupport/MIT-LICENSE @@ -1,4 +1,4 @@ -Copyright (c) 2005-2017 David Heinemeier Hansson +Copyright (c) 2005-2018 David Heinemeier Hansson Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the diff --git a/activesupport/README.rdoc b/activesupport/README.rdoc index 14ce204303..c770324be8 100644 --- a/activesupport/README.rdoc +++ b/activesupport/README.rdoc @@ -21,7 +21,7 @@ Source code can be downloaded as part of the Rails project on GitHub: Active Support is released under the MIT license: -* http://www.opensource.org/licenses/MIT +* https://opensource.org/licenses/MIT == Support @@ -30,7 +30,7 @@ API documentation is at: * http://api.rubyonrails.org -Bug reports can be filed for the Ruby on Rails project here: +Bug reports for the Ruby on Rails project can be filed here: * https://github.com/rails/rails/issues diff --git a/activesupport/Rakefile b/activesupport/Rakefile index 2e1c50cc3d..8672ab1542 100644 --- a/activesupport/Rakefile +++ b/activesupport/Rakefile @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "rake/testtask" task default: :test diff --git a/activesupport/activesupport.gemspec b/activesupport/activesupport.gemspec index 16e912694c..db801d2da2 100644 --- a/activesupport/activesupport.gemspec +++ b/activesupport/activesupport.gemspec @@ -1,3 +1,5 @@ +# frozen_string_literal: true + version = File.read(File.expand_path("../RAILS_VERSION", __dir__)).strip Gem::Specification.new do |s| diff --git a/activesupport/bin/generate_tables b/activesupport/bin/generate_tables index 6f62593f14..18199b2171 100755 --- a/activesupport/bin/generate_tables +++ b/activesupport/bin/generate_tables @@ -1,4 +1,5 @@ #!/usr/bin/env ruby +# frozen_string_literal: true begin $:.unshift(File.expand_path("../lib", __dir__)) diff --git a/activesupport/bin/test b/activesupport/bin/test index 470ce93f10..c53377cc97 100755 --- a/activesupport/bin/test +++ b/activesupport/bin/test @@ -1,4 +1,5 @@ #!/usr/bin/env ruby +# frozen_string_literal: true COMPONENT_ROOT = File.expand_path("..", __dir__) require_relative "../../tools/test" diff --git a/activesupport/lib/active_support.rb b/activesupport/lib/active_support.rb index 7302841075..a4fb697669 100644 --- a/activesupport/lib/active_support.rb +++ b/activesupport/lib/active_support.rb @@ -1,5 +1,7 @@ +# frozen_string_literal: true + #-- -# Copyright (c) 2005-2017 David Heinemeier Hansson +# Copyright (c) 2005-2018 David Heinemeier Hansson # # Permission is hereby granted, free of charge, to any person obtaining # a copy of this software and associated documentation files (the @@ -22,11 +24,11 @@ #++ require "securerandom" -require_relative "active_support/dependencies/autoload" -require_relative "active_support/version" -require_relative "active_support/logger" -require_relative "active_support/lazy_load_hooks" -require_relative "active_support/core_ext/date_and_time/compatibility" +require "active_support/dependencies/autoload" +require "active_support/version" +require "active_support/logger" +require "active_support/lazy_load_hooks" +require "active_support/core_ext/date_and_time/compatibility" module ActiveSupport extend ActiveSupport::Autoload @@ -51,6 +53,7 @@ module ActiveSupport autoload :Callbacks autoload :Configurable autoload :Deprecation + autoload :Digest autoload :Gzip autoload :Inflector autoload :JSON @@ -80,18 +83,6 @@ module ActiveSupport cattr_accessor :test_order # :nodoc: - def self.halt_callback_chains_on_return_false - ActiveSupport::Deprecation.warn(<<-MSG.squish) - ActiveSupport.halt_callback_chains_on_return_false is deprecated and will be removed in Rails 5.2. - MSG - end - - def self.halt_callback_chains_on_return_false=(value) - ActiveSupport::Deprecation.warn(<<-MSG.squish) - ActiveSupport.halt_callback_chains_on_return_false= is deprecated and will be removed in Rails 5.2. - MSG - end - def self.to_time_preserves_timezone DateAndTime::Compatibility.preserve_timezone end diff --git a/activesupport/lib/active_support/all.rb b/activesupport/lib/active_support/all.rb index 413314167d..4adf446af8 100644 --- a/activesupport/lib/active_support/all.rb +++ b/activesupport/lib/active_support/all.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "active_support" -require_relative "time" -require_relative "core_ext" +require "active_support/time" +require "active_support/core_ext" diff --git a/activesupport/lib/active_support/array_inquirer.rb b/activesupport/lib/active_support/array_inquirer.rb index befa1746c6..b2b9e9c0b7 100644 --- a/activesupport/lib/active_support/array_inquirer.rb +++ b/activesupport/lib/active_support/array_inquirer.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module ActiveSupport # Wrapping an array in an +ArrayInquirer+ gives a friendlier way to check # its string-like contents: diff --git a/activesupport/lib/active_support/backtrace_cleaner.rb b/activesupport/lib/active_support/backtrace_cleaner.rb index e47c90597f..16dd733ddb 100644 --- a/activesupport/lib/active_support/backtrace_cleaner.rb +++ b/activesupport/lib/active_support/backtrace_cleaner.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module ActiveSupport # Backtraces often include many lines that are not relevant for the context # under review. This makes it hard to find the signal amongst the backtrace diff --git a/activesupport/lib/active_support/benchmarkable.rb b/activesupport/lib/active_support/benchmarkable.rb index 74e39c74e1..f481d68198 100644 --- a/activesupport/lib/active_support/benchmarkable.rb +++ b/activesupport/lib/active_support/benchmarkable.rb @@ -1,5 +1,7 @@ -require_relative "core_ext/benchmark" -require_relative "core_ext/hash/keys" +# frozen_string_literal: true + +require "active_support/core_ext/benchmark" +require "active_support/core_ext/hash/keys" module ActiveSupport module Benchmarkable diff --git a/activesupport/lib/active_support/builder.rb b/activesupport/lib/active_support/builder.rb index 0f010c5d96..3fa7e6b26d 100644 --- a/activesupport/lib/active_support/builder.rb +++ b/activesupport/lib/active_support/builder.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + begin require "builder" rescue LoadError => e diff --git a/activesupport/lib/active_support/cache.rb b/activesupport/lib/active_support/cache.rb index f706f8ecf7..8301b8c7cb 100644 --- a/activesupport/lib/active_support/cache.rb +++ b/activesupport/lib/active_support/cache.rb @@ -1,19 +1,22 @@ +# frozen_string_literal: true + require "zlib" -require_relative "core_ext/array/extract_options" -require_relative "core_ext/array/wrap" -require_relative "core_ext/module/attribute_accessors" -require_relative "core_ext/numeric/bytes" -require_relative "core_ext/numeric/time" -require_relative "core_ext/object/to_param" -require_relative "core_ext/string/inflections" +require "active_support/core_ext/array/extract_options" +require "active_support/core_ext/array/wrap" +require "active_support/core_ext/module/attribute_accessors" +require "active_support/core_ext/numeric/bytes" +require "active_support/core_ext/numeric/time" +require "active_support/core_ext/object/to_param" +require "active_support/core_ext/string/inflections" module ActiveSupport # See ActiveSupport::Cache::Store for documentation. module Cache - autoload :FileStore, "active_support/cache/file_store" - autoload :MemoryStore, "active_support/cache/memory_store" - autoload :MemCacheStore, "active_support/cache/mem_cache_store" - autoload :NullStore, "active_support/cache/null_store" + autoload :FileStore, "active_support/cache/file_store" + autoload :MemoryStore, "active_support/cache/memory_store" + autoload :MemCacheStore, "active_support/cache/mem_cache_store" + autoload :NullStore, "active_support/cache/null_store" + autoload :RedisCacheStore, "active_support/cache/redis_cache_store" # These options mean something to all cache implementations. Individual cache # implementations may support additional options. @@ -99,7 +102,9 @@ module ActiveSupport # Obtains the specified cache store class, given the name of the +store+. # Raises an error when the store class cannot be found. def retrieve_store_class(store) - require_relative "cache/#{store}" + # require_relative cannot be used here because the class might be + # provided by another gem, like redis-activesupport for example. + require "active_support/cache/#{store}" rescue LoadError => e raise "Could not find cache store adapter for #{store} (#{e})" else @@ -144,12 +149,11 @@ module ActiveSupport # cache.namespace = -> { @last_mod_time } # Set the namespace to a variable # @last_mod_time = Time.now # Invalidate the entire cache by changing namespace # - # Caches can also store values in a compressed format to save space and - # reduce time spent sending data. Since there is overhead, values must be - # large enough to warrant compression. To turn on compression either pass - # <tt>compress: true</tt> in the initializer or as an option to +fetch+ - # or +write+. To specify the threshold at which to compress values, set the - # <tt>:compress_threshold</tt> option. The default threshold is 16K. + # Cached data larger than 1kB are compressed by default. To turn off + # compression, pass <tt>compress: false</tt> to the initializer or to + # individual +fetch+ or +write+ method calls. The 1kB compression + # threshold is configurable with the <tt>:compress_threshold</tt> option, + # specified in bytes. class Store cattr_accessor :logger, instance_writer: true @@ -208,8 +212,7 @@ module ActiveSupport # ask whether you should force a cache write. Otherwise, it's clearer to # just call <tt>Cache#write</tt>. # - # Setting <tt>:compress</tt> will store a large cache entry set by the call - # in a compressed format. + # Setting <tt>compress: false</tt> disables compression of the cache entry. # # Setting <tt>:expires_in</tt> will set an expiration time on the cache. # All caches support auto-expiring content after a specified number of @@ -558,14 +561,34 @@ module ActiveSupport end end - # Prefixes a key with the namespace. Namespace and key will be delimited - # with a colon. - def normalize_key(key, options) - key = expanded_key(key) - namespace = options[:namespace] if options - prefix = namespace.is_a?(Proc) ? namespace.call : namespace - key = "#{prefix}:#{key}" if prefix - key + # Expands and namespaces the cache key. May be overridden by + # cache stores to do additional normalization. + def normalize_key(key, options = nil) + namespace_key expanded_key(key), options + end + + # Prefix the key with a namespace string: + # + # namespace_key 'foo', namespace: 'cache' + # # => 'cache:foo' + # + # With a namespace block: + # + # namespace_key 'foo', namespace: -> { 'cache' } + # # => 'cache:foo' + def namespace_key(key, options = nil) + options = merged_options(options) + namespace = options[:namespace] + + if namespace.respond_to?(:call) + namespace = namespace.call + end + + if namespace + "#{namespace}:#{key}" + else + key + end end # Expands key to be a consistent string value. Invokes +cache_key+ if @@ -654,7 +677,7 @@ module ActiveSupport class Entry # :nodoc: attr_reader :version - DEFAULT_COMPRESS_LIMIT = 16.kilobytes + DEFAULT_COMPRESS_LIMIT = 1.kilobyte # Creates a new cache entry for the specified value. Options supported are # +:compress+, +:compress_threshold+, and +:expires_in+. @@ -729,8 +752,8 @@ module ActiveSupport private def should_compress?(value, options) - if value && options[:compress] - compress_threshold = options[:compress_threshold] || DEFAULT_COMPRESS_LIMIT + if value && options.fetch(:compress, true) + compress_threshold = options.fetch(:compress_threshold, DEFAULT_COMPRESS_LIMIT) serialized_value_size = (value.is_a?(String) ? value : Marshal.dump(value)).bytesize return true if serialized_value_size >= compress_threshold diff --git a/activesupport/lib/active_support/cache/file_store.rb b/activesupport/lib/active_support/cache/file_store.rb index bb65da2723..a0f44aac0f 100644 --- a/activesupport/lib/active_support/cache/file_store.rb +++ b/activesupport/lib/active_support/cache/file_store.rb @@ -1,6 +1,8 @@ -require_relative "../core_ext/marshal" -require_relative "../core_ext/file/atomic" -require_relative "../core_ext/string/conversions" +# frozen_string_literal: true + +require "active_support/core_ext/marshal" +require "active_support/core_ext/file/atomic" +require "active_support/core_ext/string/conversions" require "uri/common" module ActiveSupport @@ -37,9 +39,8 @@ module ActiveSupport def cleanup(options = nil) options = merged_options(options) search_dir(cache_path) do |fname| - key = file_path_key(fname) - entry = read_entry(key, options) - delete_entry(key, options) if entry && entry.expired? + entry = read_entry(fname, options) + delete_entry(fname, options) if entry && entry.expired? end end @@ -120,7 +121,7 @@ module ActiveSupport fname = URI.encode_www_form_component(key) if fname.size > FILEPATH_MAX_SIZE - fname = Digest::MD5.hexdigest(key) + fname = ActiveSupport::Digest.hexdigest(key) end hash = Zlib.adler32(fname) diff --git a/activesupport/lib/active_support/cache/mem_cache_store.rb b/activesupport/lib/active_support/cache/mem_cache_store.rb index 7efe6fe3bf..df8bc8e43e 100644 --- a/activesupport/lib/active_support/cache/mem_cache_store.rb +++ b/activesupport/lib/active_support/cache/mem_cache_store.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + begin require "dalli" rescue LoadError => e @@ -5,14 +7,13 @@ rescue LoadError => e raise e end -require "digest/md5" -require_relative "../core_ext/marshal" -require_relative "../core_ext/array/extract_options" +require "active_support/core_ext/marshal" +require "active_support/core_ext/array/extract_options" module ActiveSupport module Cache # A cache store implementation which stores data in Memcached: - # http://memcached.org/ + # https://memcached.org # # This is currently the most popular cache store for production websites. # @@ -120,7 +121,7 @@ module ActiveSupport options = merged_options(options) instrument(:increment, name, amount: amount) do rescue_error_with nil do - @data.incr(normalize_key(name, options), amount) + @data.incr(normalize_key(name, options), amount, options[:expires_in]) end end end @@ -133,7 +134,7 @@ module ActiveSupport options = merged_options(options) instrument(:decrement, name, amount: amount) do rescue_error_with nil do - @data.decr(normalize_key(name, options), amount) + @data.decr(normalize_key(name, options), amount, options[:expires_in]) end end end @@ -181,7 +182,7 @@ module ActiveSupport key = super.dup key = key.force_encoding(Encoding::ASCII_8BIT) key = key.gsub(ESCAPE_KEY_CHARS) { |match| "%#{match.getbyte(0).to_s(16).upcase}" } - key = "#{key[0, 213]}:md5:#{Digest::MD5.hexdigest(key)}" if key.size > 250 + key = "#{key[0, 213]}:md5:#{ActiveSupport::Digest.hexdigest(key)}" if key.size > 250 key end diff --git a/activesupport/lib/active_support/cache/memory_store.rb b/activesupport/lib/active_support/cache/memory_store.rb index 56fe1457d0..564ac17241 100644 --- a/activesupport/lib/active_support/cache/memory_store.rb +++ b/activesupport/lib/active_support/cache/memory_store.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "monitor" module ActiveSupport diff --git a/activesupport/lib/active_support/cache/null_store.rb b/activesupport/lib/active_support/cache/null_store.rb index 550659fc56..1a5983db43 100644 --- a/activesupport/lib/active_support/cache/null_store.rb +++ b/activesupport/lib/active_support/cache/null_store.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module ActiveSupport module Cache # A cache store implementation which doesn't actually store anything. Useful in diff --git a/activesupport/lib/active_support/cache/redis_cache_store.rb b/activesupport/lib/active_support/cache/redis_cache_store.rb new file mode 100644 index 0000000000..6cc45f5284 --- /dev/null +++ b/activesupport/lib/active_support/cache/redis_cache_store.rb @@ -0,0 +1,406 @@ +# frozen_string_literal: true + +begin + gem "redis", ">= 4.0.1" + require "redis" + require "redis/distributed" +rescue LoadError + warn "The Redis cache store requires the redis gem, version 4.0.1 or later. Please add it to your Gemfile: `gem \"redis\", \"~> 4.0\"`" + raise +end + +# Prefer the hiredis driver but don't require it. +begin + require "redis/connection/hiredis" +rescue LoadError +end + +require "digest/sha2" +require "active_support/core_ext/marshal" + +module ActiveSupport + module Cache + # Redis cache store. + # + # Deployment note: Take care to use a *dedicated Redis cache* rather + # than pointing this at your existing Redis server. It won't cope well + # with mixed usage patterns and it won't expire cache entries by default. + # + # Redis cache server setup guide: https://redis.io/topics/lru-cache + # + # * Supports vanilla Redis, hiredis, and Redis::Distributed. + # * Supports Memcached-like sharding across Redises with Redis::Distributed. + # * Fault tolerant. If the Redis server is unavailable, no exceptions are + # raised. Cache fetches are all misses and writes are dropped. + # * Local cache. Hot in-memory primary cache within block/middleware scope. + # * +read_multi+ and +write_multi+ support for Redis mget/mset. Use Redis::Distributed + # 4.0.1+ for distributed mget support. + # * +delete_matched+ support for Redis KEYS globs. + class RedisCacheStore < Store + # Keys are truncated with their own SHA2 digest if they exceed 1kB + MAX_KEY_BYTESIZE = 1024 + + DEFAULT_REDIS_OPTIONS = { + connect_timeout: 20, + read_timeout: 1, + write_timeout: 1, + reconnect_attempts: 0, + } + + DEFAULT_ERROR_HANDLER = -> (method:, returning:, exception:) do + if logger + logger.error { "RedisCacheStore: #{method} failed, returned #{returning.inspect}: #{exception.class}: #{exception.message}" } + end + end + + DELETE_GLOB_LUA = "for i, name in ipairs(redis.call('KEYS', ARGV[1])) do redis.call('DEL', name); end" + private_constant :DELETE_GLOB_LUA + + # Support raw values in the local cache strategy. + module LocalCacheWithRaw # :nodoc: + private + def read_entry(key, options) + entry = super + if options[:raw] && local_cache && entry + entry = deserialize_entry(entry.value) + end + entry + end + + def write_entry(key, entry, options) + if options[:raw] && local_cache + raw_entry = Entry.new(entry.value.to_s) + raw_entry.expires_at = entry.expires_at + super(key, raw_entry, options) + else + super + end + end + + def write_multi_entries(entries, options) + if options[:raw] && local_cache + raw_entries = entries.map do |key, entry| + raw_entry = Entry.new(entry.value.to_s) + raw_entry.expires_at = entry.expires_at + end.to_h + + super(raw_entries, options) + else + super + end + end + end + + prepend Strategy::LocalCache + prepend LocalCacheWithRaw + + class << self + # Factory method to create a new Redis instance. + # + # Handles four options: :redis block, :redis instance, single :url + # string, and multiple :url strings. + # + # Option Class Result + # :redis Proc -> options[:redis].call + # :redis Object -> options[:redis] + # :url String -> Redis.new(url: …) + # :url Array -> Redis::Distributed.new([{ url: … }, { url: … }, …]) + # + def build_redis(redis: nil, url: nil, **redis_options) #:nodoc: + urls = Array(url) + + if redis.respond_to?(:call) + redis.call + elsif redis + redis + elsif urls.size > 1 + build_redis_distributed_client urls: urls, **redis_options + else + build_redis_client url: urls.first, **redis_options + end + end + + private + def build_redis_distributed_client(urls:, **redis_options) + ::Redis::Distributed.new([], DEFAULT_REDIS_OPTIONS.merge(redis_options)).tap do |dist| + urls.each { |u| dist.add_node url: u } + end + end + + def build_redis_client(url:, **redis_options) + ::Redis.new DEFAULT_REDIS_OPTIONS.merge(redis_options.merge(url: url)) + end + end + + attr_reader :redis_options + attr_reader :max_key_bytesize + + # Creates a new Redis cache store. + # + # Handles three options: block provided to instantiate, single URL + # provided, and multiple URLs provided. + # + # :redis Proc -> options[:redis].call + # :url String -> Redis.new(url: …) + # :url Array -> Redis::Distributed.new([{ url: … }, { url: … }, …]) + # + # No namespace is set by default. Provide one if the Redis cache + # server is shared with other apps: <tt>namespace: 'myapp-cache'<tt>. + # + # Compression is enabled by default with a 1kB threshold, so cached + # values larger than 1kB are automatically compressed. Disable by + # passing <tt>cache: false</tt> or change the threshold by passing + # <tt>compress_threshold: 4.kilobytes</tt>. + # + # No expiry is set on cache entries by default. Redis is expected to + # be configured with an eviction policy that automatically deletes + # least-recently or -frequently used keys when it reaches max memory. + # See https://redis.io/topics/lru-cache for cache server setup. + # + # Race condition TTL is not set by default. This can be used to avoid + # "thundering herd" cache writes when hot cache entries are expired. + # See <tt>ActiveSupport::Cache::Store#fetch</tt> for more. + def initialize(namespace: nil, compress: true, compress_threshold: 1.kilobyte, expires_in: nil, race_condition_ttl: nil, error_handler: DEFAULT_ERROR_HANDLER, **redis_options) + @redis_options = redis_options + + @max_key_bytesize = MAX_KEY_BYTESIZE + @error_handler = error_handler + + super namespace: namespace, + compress: compress, compress_threshold: compress_threshold, + expires_in: expires_in, race_condition_ttl: race_condition_ttl + end + + def redis + @redis ||= self.class.build_redis(**redis_options) + end + + def inspect + instance = @redis || @redis_options + "<##{self.class} options=#{options.inspect} redis=#{instance.inspect}>" + end + + # Cache Store API implementation. + # + # Read multiple values at once. Returns a hash of requested keys -> + # fetched values. + def read_multi(*names) + if mget_capable? + read_multi_mget(*names) + else + super + end + end + + # Cache Store API implementation. + # + # Supports Redis KEYS glob patterns: + # + # h?llo matches hello, hallo and hxllo + # h*llo matches hllo and heeeello + # h[ae]llo matches hello and hallo, but not hillo + # h[^e]llo matches hallo, hbllo, ... but not hello + # h[a-b]llo matches hallo and hbllo + # + # Use \ to escape special characters if you want to match them verbatim. + # + # See https://redis.io/commands/KEYS for more. + # + # Failsafe: Raises errors. + def delete_matched(matcher, options = nil) + instrument :delete_matched, matcher do + case matcher + when String + redis.eval DELETE_GLOB_LUA, [], [namespace_key(matcher, options)] + else + raise ArgumentError, "Only Redis glob strings are supported: #{matcher.inspect}" + end + end + end + + # Cache Store API implementation. + # + # Increment a cached value. This method uses the Redis incr atomic + # operator and can only be used on values written with the :raw option. + # Calling it on a value not stored with :raw will initialize that value + # to zero. + # + # Failsafe: Raises errors. + def increment(name, amount = 1, options = nil) + instrument :increment, name, amount: amount do + redis.incrby normalize_key(name, options), amount + end + end + + # Cache Store API implementation. + # + # Decrement a cached value. This method uses the Redis decr atomic + # operator and can only be used on values written with the :raw option. + # Calling it on a value not stored with :raw will initialize that value + # to zero. + # + # Failsafe: Raises errors. + def decrement(name, amount = 1, options = nil) + instrument :decrement, name, amount: amount do + redis.decrby normalize_key(name, options), amount + end + end + + # Cache Store API implementation. + # + # Removes expired entries. Handled natively by Redis least-recently-/ + # least-frequently-used expiry, so manual cleanup is not supported. + def cleanup(options = nil) + super + end + + # Clear the entire cache on all Redis servers. Safe to use on + # shared servers if the cache is namespaced. + # + # Failsafe: Raises errors. + def clear(options = nil) + failsafe :clear do + if namespace = merged_options(options)[namespace] + delete_matched "*", namespace: namespace + else + redis.flushdb + end + end + end + + def mget_capable? #:nodoc: + set_redis_capabilities unless defined? @mget_capable + @mget_capable + end + + def mset_capable? #:nodoc: + set_redis_capabilities unless defined? @mset_capable + @mset_capable + end + + private + def set_redis_capabilities + case redis + when Redis::Distributed + @mget_capable = true + @mset_capable = false + else + @mget_capable = true + @mset_capable = true + end + end + + # Store provider interface: + # Read an entry from the cache. + def read_entry(key, options = nil) + failsafe :read_entry do + deserialize_entry redis.get(key) + end + end + + def read_multi_mget(*names) + options = names.extract_options! + options = merged_options(options) + + keys = names.map { |name| normalize_key(name, options) } + values = redis.mget(*keys) + + names.zip(values).each_with_object({}) do |(name, value), results| + if value + entry = deserialize_entry(value) + unless entry.nil? || entry.expired? || entry.mismatched?(normalize_version(name, options)) + results[name] = entry.value + end + end + end + end + + # Write an entry to the cache. + # + # Requires Redis 2.6.12+ for extended SET options. + def write_entry(key, entry, unless_exist: false, raw: false, expires_in: nil, race_condition_ttl: nil, **options) + value = raw ? entry.value.to_s : serialize_entry(entry) + + # If race condition TTL is in use, ensure that cache entries + # stick around a bit longer after they would have expired + # so we can purposefully serve stale entries. + if race_condition_ttl && expires_in && expires_in > 0 && !raw + expires_in += 5.minutes + end + + failsafe :write_entry do + if unless_exist || expires_in + modifiers = {} + modifiers[:nx] = unless_exist + modifiers[:px] = (1000 * expires_in.to_f).ceil if expires_in + + redis.set key, value, modifiers + else + redis.set key, value + end + end + end + + # Delete an entry from the cache. + def delete_entry(key, options) + failsafe :delete_entry, returning: false do + redis.del key + end + end + + # Nonstandard store provider API to write multiple values at once. + def write_multi_entries(entries, expires_in: nil, **options) + if entries.any? + if mset_capable? && expires_in.nil? + failsafe :write_multi_entries do + redis.mapped_mset(entries) + end + else + super + end + end + end + + # Truncate keys that exceed 1kB. + def normalize_key(key, options) + truncate_key super + end + + def truncate_key(key) + if key.bytesize > max_key_bytesize + suffix = ":sha2:#{Digest::SHA2.hexdigest(key)}" + truncate_at = max_key_bytesize - suffix.bytesize + "#{key.byteslice(0, truncate_at)}#{suffix}" + else + key + end + end + + def deserialize_entry(raw_value) + if raw_value + entry = Marshal.load(raw_value) rescue raw_value + entry.is_a?(Entry) ? entry : Entry.new(entry) + end + end + + def serialize_entry(entry) + Marshal.dump(entry) + end + + def failsafe(method, returning: nil) + yield + rescue ::Redis::BaseConnectionError => e + handle_exception exception: e, method: method, returning: returning + returning + end + + def handle_exception(exception:, method:, returning:) + if @error_handler + @error_handler.(method: method, exception: exception, returning: returning) + end + rescue => failsafe + warn "RedisCacheStore ignored exception in handle_exception: #{failsafe.class}: #{failsafe.message}\n #{failsafe.backtrace.join("\n ")}" + end + end + end +end diff --git a/activesupport/lib/active_support/cache/strategy/local_cache.rb b/activesupport/lib/active_support/cache/strategy/local_cache.rb index 2e7e5af0e3..aaa9638fa8 100644 --- a/activesupport/lib/active_support/cache/strategy/local_cache.rb +++ b/activesupport/lib/active_support/cache/strategy/local_cache.rb @@ -1,6 +1,8 @@ -require_relative "../../core_ext/object/duplicable" -require_relative "../../core_ext/string/inflections" -require_relative "../../per_thread_registry" +# frozen_string_literal: true + +require "active_support/core_ext/object/duplicable" +require "active_support/core_ext/string/inflections" +require "active_support/per_thread_registry" module ActiveSupport module Cache diff --git a/activesupport/lib/active_support/cache/strategy/local_cache_middleware.rb b/activesupport/lib/active_support/cache/strategy/local_cache_middleware.rb index 4c3679e4bf..62542bdb22 100644 --- a/activesupport/lib/active_support/cache/strategy/local_cache_middleware.rb +++ b/activesupport/lib/active_support/cache/strategy/local_cache_middleware.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "rack/body_proxy" require "rack/utils" diff --git a/activesupport/lib/active_support/callbacks.rb b/activesupport/lib/active_support/callbacks.rb index 34d62ec3a9..0ed4681b7d 100644 --- a/activesupport/lib/active_support/callbacks.rb +++ b/activesupport/lib/active_support/callbacks.rb @@ -1,11 +1,13 @@ -require_relative "concern" -require_relative "descendants_tracker" -require_relative "core_ext/array/extract_options" -require_relative "core_ext/class/attribute" -require_relative "core_ext/kernel/reporting" -require_relative "core_ext/kernel/singleton_class" -require_relative "core_ext/string/filters" -require_relative "deprecation" +# frozen_string_literal: true + +require "active_support/concern" +require "active_support/descendants_tracker" +require "active_support/core_ext/array/extract_options" +require "active_support/core_ext/class/attribute" +require "active_support/core_ext/kernel/reporting" +require "active_support/core_ext/kernel/singleton_class" +require "active_support/core_ext/string/filters" +require "active_support/deprecation" require "thread" module ActiveSupport @@ -296,8 +298,8 @@ module ActiveSupport @kind = kind @filter = filter @key = compute_identifier filter - @if = Array(options[:if]) - @unless = Array(options[:unless]) + @if = check_conditionals(Array(options[:if])) + @unless = check_conditionals(Array(options[:unless])) end def filter; @key; end @@ -321,7 +323,7 @@ module ActiveSupport def duplicates?(other) case @filter - when Symbol, String + when Symbol matches?(other.kind, other.filter) else false @@ -348,9 +350,21 @@ module ActiveSupport end private + def check_conditionals(conditionals) + if conditionals.any? { |c| c.is_a?(String) } + raise ArgumentError, <<-MSG.squish + Passing string to be evaluated in :if and :unless conditional + options is not supported. Pass a symbol for an instance method, + or a lambda, proc or block, instead. + MSG + end + + conditionals + end + def compute_identifier(filter) case filter - when String, ::Proc + when ::Proc filter.object_id else filter @@ -425,7 +439,6 @@ module ActiveSupport # Filters support: # # Symbols:: A method to call. - # Strings:: Some content to evaluate. # Procs:: A proc to call with the object. # Objects:: An object with a <tt>before_foo</tt> method on it to call. # @@ -435,8 +448,6 @@ module ActiveSupport case filter when Symbol new(nil, filter, [], nil) - when String - new(nil, :instance_exec, [:value], compile_lambda(filter)) when Conditionals::Value new(filter, :call, [:target, :value], nil) when ::Proc @@ -453,10 +464,6 @@ module ActiveSupport new(filter, method_to_call, [:target], nil) end end - - def self.compile_lambda(filter) - eval("lambda { |value| #{filter} }") - end end # Execute before and after filters in a sequence instead of @@ -649,26 +656,17 @@ module ActiveSupport # # ===== Options # - # * <tt>:if</tt> - A symbol, a string (deprecated) or an array of symbols, - # each naming an instance method or a proc; the callback will be called - # only when they all return a true value. - # * <tt>:unless</tt> - A symbol, a string (deprecated) or an array of symbols, - # each naming an instance method or a proc; the callback will be called - # only when they all return a false value. + # * <tt>:if</tt> - A symbol or an array of symbols, each naming an instance + # method or a proc; the callback will be called only when they all return + # a true value. + # * <tt>:unless</tt> - A symbol or an array of symbols, each naming an + # instance method or a proc; the callback will be called only when they + # all return a false value. # * <tt>:prepend</tt> - If +true+, the callback will be prepended to the # existing chain rather than appended. def set_callback(name, *filter_list, &block) type, filters, options = normalize_callback_params(filter_list, block) - if options[:if].is_a?(String) || options[:unless].is_a?(String) - ActiveSupport::Deprecation.warn(<<-MSG.squish) - Passing string to be evaluated in :if and :unless conditional - options is deprecated and will be removed in Rails 5.2 without - replacement. Pass a symbol for an instance method, or a lambda, - proc or block, instead. - MSG - end - self_chain = get_callbacks name mapped = filters.map do |filter| Callback.build(self_chain, filter, type, options) @@ -693,13 +691,6 @@ module ActiveSupport def skip_callback(name, *filter_list, &block) type, filters, options = normalize_callback_params(filter_list, block) - if options[:if].is_a?(String) || options[:unless].is_a?(String) - ActiveSupport::Deprecation.warn(<<-MSG.squish) - Passing string to :if and :unless conditional options is deprecated - and will be removed in Rails 5.2 without replacement. - MSG - end - options[:raise] = true unless options.key?(:raise) __update_callbacks(name) do |target, chain| diff --git a/activesupport/lib/active_support/concern.rb b/activesupport/lib/active_support/concern.rb index 0403eb70ca..b0a0d845e5 100644 --- a/activesupport/lib/active_support/concern.rb +++ b/activesupport/lib/active_support/concern.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module ActiveSupport # A typical module looks like this: # @@ -111,7 +113,7 @@ module ActiveSupport def append_features(base) if base.instance_variable_defined?(:@_dependencies) base.instance_variable_get(:@_dependencies) << self - return false + false else return false if base < self @_dependencies.each { |dep| base.include(dep) } diff --git a/activesupport/lib/active_support/concurrency/load_interlock_aware_monitor.rb b/activesupport/lib/active_support/concurrency/load_interlock_aware_monitor.rb new file mode 100644 index 0000000000..a8455c0048 --- /dev/null +++ b/activesupport/lib/active_support/concurrency/load_interlock_aware_monitor.rb @@ -0,0 +1,17 @@ +# frozen_string_literal: true + +require "monitor" + +module ActiveSupport + module Concurrency + # A monitor that will permit dependency loading while blocked waiting for + # the lock. + class LoadInterlockAwareMonitor < Monitor + # Enters an exclusive section, but allows dependency loading while blocked + def mon_enter + mon_try_enter || + ActiveSupport::Dependencies.interlock.permit_concurrent_loads { super } + end + end + end +end diff --git a/activesupport/lib/active_support/concurrency/share_lock.rb b/activesupport/lib/active_support/concurrency/share_lock.rb index 4318523b07..f18ccf1c88 100644 --- a/activesupport/lib/active_support/concurrency/share_lock.rb +++ b/activesupport/lib/active_support/concurrency/share_lock.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "thread" require "monitor" diff --git a/activesupport/lib/active_support/configurable.rb b/activesupport/lib/active_support/configurable.rb index ebe4055f91..4d6f7819bb 100644 --- a/activesupport/lib/active_support/configurable.rb +++ b/activesupport/lib/active_support/configurable.rb @@ -1,7 +1,9 @@ -require_relative "concern" -require_relative "ordered_options" -require_relative "core_ext/array/extract_options" -require_relative "core_ext/regexp" +# frozen_string_literal: true + +require "active_support/concern" +require "active_support/ordered_options" +require "active_support/core_ext/array/extract_options" +require "active_support/core_ext/regexp" module ActiveSupport # Configurable provides a <tt>config</tt> method to store and retrieve diff --git a/activesupport/lib/active_support/core_ext.rb b/activesupport/lib/active_support/core_ext.rb index 42e0acf66a..f590605d84 100644 --- a/activesupport/lib/active_support/core_ext.rb +++ b/activesupport/lib/active_support/core_ext.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + Dir.glob(File.expand_path("core_ext/*.rb", __dir__)).each do |path| require path end diff --git a/activesupport/lib/active_support/core_ext/array.rb b/activesupport/lib/active_support/core_ext/array.rb index 3536c7f2bf..6d83b76882 100644 --- a/activesupport/lib/active_support/core_ext/array.rb +++ b/activesupport/lib/active_support/core_ext/array.rb @@ -1,7 +1,9 @@ -require_relative "array/wrap" -require_relative "array/access" -require_relative "array/conversions" -require_relative "array/extract_options" -require_relative "array/grouping" -require_relative "array/prepend_and_append" -require_relative "array/inquiry" +# frozen_string_literal: true + +require "active_support/core_ext/array/wrap" +require "active_support/core_ext/array/access" +require "active_support/core_ext/array/conversions" +require "active_support/core_ext/array/extract_options" +require "active_support/core_ext/array/grouping" +require "active_support/core_ext/array/prepend_and_append" +require "active_support/core_ext/array/inquiry" diff --git a/activesupport/lib/active_support/core_ext/array/access.rb b/activesupport/lib/active_support/core_ext/array/access.rb index fca33c9d69..b7ff7a3907 100644 --- a/activesupport/lib/active_support/core_ext/array/access.rb +++ b/activesupport/lib/active_support/core_ext/array/access.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class Array # Returns the tail of the array from +position+. # @@ -33,8 +35,8 @@ class Array # people.without "Aaron", "Todd" # # => ["David", "Rafael"] # - # Note: This is an optimization of `Enumerable#without` that uses `Array#-` - # instead of `Array#reject` for performance reasons. + # Note: This is an optimization of <tt>Enumerable#without</tt> that uses <tt>Array#-</tt> + # instead of <tt>Array#reject</tt> for performance reasons. def without(*elements) self - elements end diff --git a/activesupport/lib/active_support/core_ext/array/conversions.rb b/activesupport/lib/active_support/core_ext/array/conversions.rb index 57ad32483a..ea688ed2ea 100644 --- a/activesupport/lib/active_support/core_ext/array/conversions.rb +++ b/activesupport/lib/active_support/core_ext/array/conversions.rb @@ -1,8 +1,10 @@ -require_relative "../../xml_mini" -require_relative "../hash/keys" -require_relative "../string/inflections" -require_relative "../object/to_param" -require_relative "../object/to_query" +# frozen_string_literal: true + +require "active_support/xml_mini" +require "active_support/core_ext/hash/keys" +require "active_support/core_ext/string/inflections" +require "active_support/core_ext/object/to_param" +require "active_support/core_ext/object/to_query" class Array # Converts the array to a comma-separated sentence where the last element is @@ -179,7 +181,7 @@ class Array # </messages> # def to_xml(options = {}) - require_relative "../../builder" unless defined?(Builder) + require "active_support/builder" unless defined?(Builder) options = options.dup options[:indent] ||= 2 diff --git a/activesupport/lib/active_support/core_ext/array/extract_options.rb b/activesupport/lib/active_support/core_ext/array/extract_options.rb index 9008a0df2a..8c7cb2e780 100644 --- a/activesupport/lib/active_support/core_ext/array/extract_options.rb +++ b/activesupport/lib/active_support/core_ext/array/extract_options.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class Hash # By default, only instances of Hash itself are extractable. # Subclasses of Hash may implement this method and return diff --git a/activesupport/lib/active_support/core_ext/array/grouping.rb b/activesupport/lib/active_support/core_ext/array/grouping.rb index 0d798e5c4e..67e760bc4b 100644 --- a/activesupport/lib/active_support/core_ext/array/grouping.rb +++ b/activesupport/lib/active_support/core_ext/array/grouping.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class Array # Splits or iterates over the array in groups of size +number+, # padding any remaining slots with +fill_with+ unless it is +false+. diff --git a/activesupport/lib/active_support/core_ext/array/inquiry.rb b/activesupport/lib/active_support/core_ext/array/inquiry.rb index c46b01baf0..92c61bf201 100644 --- a/activesupport/lib/active_support/core_ext/array/inquiry.rb +++ b/activesupport/lib/active_support/core_ext/array/inquiry.rb @@ -1,4 +1,6 @@ -require_relative "../../array_inquirer" +# frozen_string_literal: true + +require "active_support/array_inquirer" class Array # Wraps the array in an +ArrayInquirer+ object, which gives a friendlier way diff --git a/activesupport/lib/active_support/core_ext/array/prepend_and_append.rb b/activesupport/lib/active_support/core_ext/array/prepend_and_append.rb index 88a34128c9..661971d7cd 100644 --- a/activesupport/lib/active_support/core_ext/array/prepend_and_append.rb +++ b/activesupport/lib/active_support/core_ext/array/prepend_and_append.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class Array # The human way of thinking about adding stuff to the end of a list is with append. alias_method :append, :push unless [].respond_to?(:append) diff --git a/activesupport/lib/active_support/core_ext/array/wrap.rb b/activesupport/lib/active_support/core_ext/array/wrap.rb index b611d34c27..d62f97edbf 100644 --- a/activesupport/lib/active_support/core_ext/array/wrap.rb +++ b/activesupport/lib/active_support/core_ext/array/wrap.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class Array # Wraps its argument in an array unless it is already an array (or array-like). # diff --git a/activesupport/lib/active_support/core_ext/benchmark.rb b/activesupport/lib/active_support/core_ext/benchmark.rb index 2300953860..641b58c8b8 100644 --- a/activesupport/lib/active_support/core_ext/benchmark.rb +++ b/activesupport/lib/active_support/core_ext/benchmark.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "benchmark" class << Benchmark diff --git a/activesupport/lib/active_support/core_ext/big_decimal.rb b/activesupport/lib/active_support/core_ext/big_decimal.rb index 7e396cac3c..9e6a9d6331 100644 --- a/activesupport/lib/active_support/core_ext/big_decimal.rb +++ b/activesupport/lib/active_support/core_ext/big_decimal.rb @@ -1 +1,3 @@ -require_relative "big_decimal/conversions" +# frozen_string_literal: true + +require "active_support/core_ext/big_decimal/conversions" diff --git a/activesupport/lib/active_support/core_ext/big_decimal/conversions.rb b/activesupport/lib/active_support/core_ext/big_decimal/conversions.rb index decd4e1699..52bd229416 100644 --- a/activesupport/lib/active_support/core_ext/big_decimal/conversions.rb +++ b/activesupport/lib/active_support/core_ext/big_decimal/conversions.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "bigdecimal" require "bigdecimal/util" diff --git a/activesupport/lib/active_support/core_ext/class.rb b/activesupport/lib/active_support/core_ext/class.rb index 66dd1c939a..1c110fd07b 100644 --- a/activesupport/lib/active_support/core_ext/class.rb +++ b/activesupport/lib/active_support/core_ext/class.rb @@ -1,2 +1,4 @@ -require_relative "class/attribute" -require_relative "class/subclasses" +# frozen_string_literal: true + +require "active_support/core_ext/class/attribute" +require "active_support/core_ext/class/subclasses" diff --git a/activesupport/lib/active_support/core_ext/class/attribute.rb b/activesupport/lib/active_support/core_ext/class/attribute.rb index 26b826b39b..7928efb871 100644 --- a/activesupport/lib/active_support/core_ext/class/attribute.rb +++ b/activesupport/lib/active_support/core_ext/class/attribute.rb @@ -1,11 +1,23 @@ -require_relative "../kernel/singleton_class" -require_relative "../module/remove_method" -require_relative "../array/extract_options" +# frozen_string_literal: true + +require "active_support/core_ext/kernel/singleton_class" +require "active_support/core_ext/module/redefine_method" +require "active_support/core_ext/array/extract_options" class Class # Declare a class-level attribute whose value is inheritable by subclasses. # Subclasses can change their own value and it will not impact parent class. # + # ==== Options + # + # * <tt>:instance_reader</tt> - Sets the instance reader method (defaults to true). + # * <tt>:instance_writer</tt> - Sets the instance writer method (defaults to true). + # * <tt>:instance_accessor</tt> - Sets both instance methods (defaults to true). + # * <tt>:instance_predicate</tt> - Sets a predicate method (defaults to true). + # * <tt>:default</tt> - Sets a default value for the attribute (defaults to nil). + # + # ==== Examples + # # class Base # class_attribute :setting # end @@ -80,25 +92,23 @@ class Class default_value = options.fetch(:default, nil) attrs.each do |name| - remove_possible_singleton_method(name) + singleton_class.silence_redefinition_of_method(name) define_singleton_method(name) { nil } - remove_possible_singleton_method("#{name}?") + singleton_class.silence_redefinition_of_method("#{name}?") define_singleton_method("#{name}?") { !!public_send(name) } if instance_predicate ivar = "@#{name}" - remove_possible_singleton_method("#{name}=") + singleton_class.silence_redefinition_of_method("#{name}=") define_singleton_method("#{name}=") do |val| singleton_class.class_eval do - remove_possible_method(name) - define_method(name) { val } + redefine_method(name) { val } end if singleton_class? class_eval do - remove_possible_method(name) - define_method(name) do + redefine_method(name) do if instance_variable_defined? ivar instance_variable_get ivar else @@ -111,8 +121,7 @@ class Class end if instance_reader - remove_possible_method name - define_method(name) do + redefine_method(name) do if instance_variable_defined?(ivar) instance_variable_get ivar else @@ -120,13 +129,13 @@ class Class end end - remove_possible_method "#{name}?" - define_method("#{name}?") { !!public_send(name) } if instance_predicate + redefine_method("#{name}?") { !!public_send(name) } if instance_predicate end if instance_writer - remove_possible_method "#{name}=" - attr_writer name + redefine_method("#{name}=") do |val| + instance_variable_set ivar, val + end end unless default_value.nil? diff --git a/activesupport/lib/active_support/core_ext/class/attribute_accessors.rb b/activesupport/lib/active_support/core_ext/class/attribute_accessors.rb index eebf2e294a..a77354e153 100644 --- a/activesupport/lib/active_support/core_ext/class/attribute_accessors.rb +++ b/activesupport/lib/active_support/core_ext/class/attribute_accessors.rb @@ -1,4 +1,6 @@ +# frozen_string_literal: true + # cattr_* became mattr_* aliases in 7dfbd91b0780fbd6a1dd9bfbc176e10894871d2d, # but we keep this around for libraries that directly require it knowing they # want cattr_*. No need to deprecate. -require_relative "../module/attribute_accessors" +require "active_support/core_ext/module/attribute_accessors" diff --git a/activesupport/lib/active_support/core_ext/class/subclasses.rb b/activesupport/lib/active_support/core_ext/class/subclasses.rb index 545ad7fb3e..75e65337b7 100644 --- a/activesupport/lib/active_support/core_ext/class/subclasses.rb +++ b/activesupport/lib/active_support/core_ext/class/subclasses.rb @@ -1,5 +1,4 @@ -require_relative "../module/anonymous" -require_relative "../module/reachable" +# frozen_string_literal: true class Class begin diff --git a/activesupport/lib/active_support/core_ext/date.rb b/activesupport/lib/active_support/core_ext/date.rb index aba72c732f..cce73f2db2 100644 --- a/activesupport/lib/active_support/core_ext/date.rb +++ b/activesupport/lib/active_support/core_ext/date.rb @@ -1,5 +1,7 @@ -require_relative "date/acts_like" -require_relative "date/blank" -require_relative "date/calculations" -require_relative "date/conversions" -require_relative "date/zones" +# frozen_string_literal: true + +require "active_support/core_ext/date/acts_like" +require "active_support/core_ext/date/blank" +require "active_support/core_ext/date/calculations" +require "active_support/core_ext/date/conversions" +require "active_support/core_ext/date/zones" diff --git a/activesupport/lib/active_support/core_ext/date/acts_like.rb b/activesupport/lib/active_support/core_ext/date/acts_like.rb index dfea3e3f09..c8077f3774 100644 --- a/activesupport/lib/active_support/core_ext/date/acts_like.rb +++ b/activesupport/lib/active_support/core_ext/date/acts_like.rb @@ -1,4 +1,6 @@ -require_relative "../object/acts_like" +# frozen_string_literal: true + +require "active_support/core_ext/object/acts_like" class Date # Duck-types as a Date-like class. See Object#acts_like?. diff --git a/activesupport/lib/active_support/core_ext/date/blank.rb b/activesupport/lib/active_support/core_ext/date/blank.rb index edd2847126..e6271c79b3 100644 --- a/activesupport/lib/active_support/core_ext/date/blank.rb +++ b/activesupport/lib/active_support/core_ext/date/blank.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "date" class Date #:nodoc: diff --git a/activesupport/lib/active_support/core_ext/date/calculations.rb b/activesupport/lib/active_support/core_ext/date/calculations.rb index 24d3721d48..1cd7acb05d 100644 --- a/activesupport/lib/active_support/core_ext/date/calculations.rb +++ b/activesupport/lib/active_support/core_ext/date/calculations.rb @@ -1,9 +1,11 @@ +# frozen_string_literal: true + require "date" -require_relative "../../duration" -require_relative "../object/acts_like" -require_relative "zones" -require_relative "../time/zones" -require_relative "../date_and_time/calculations" +require "active_support/duration" +require "active_support/core_ext/object/acts_like" +require "active_support/core_ext/date/zones" +require "active_support/core_ext/time/zones" +require "active_support/core_ext/date_and_time/calculations" class Date include DateAndTime::Calculations diff --git a/activesupport/lib/active_support/core_ext/date/conversions.rb b/activesupport/lib/active_support/core_ext/date/conversions.rb index 7971d39fb7..870119dc7f 100644 --- a/activesupport/lib/active_support/core_ext/date/conversions.rb +++ b/activesupport/lib/active_support/core_ext/date/conversions.rb @@ -1,7 +1,9 @@ +# frozen_string_literal: true + require "date" -require_relative "../../inflector/methods" -require_relative "zones" -require_relative "../module/remove_method" +require "active_support/inflector/methods" +require "active_support/core_ext/date/zones" +require "active_support/core_ext/module/redefine_method" class Date DATE_FORMATS = { @@ -17,14 +19,6 @@ class Date iso8601: lambda { |date| date.iso8601 } } - # Ruby 1.9 has Date#to_time which converts to localtime only. - remove_method :to_time - - # Ruby 1.9 has Date#xmlschema which converts to a string without the time - # component. This removal may generate an issue on FreeBSD, that's why we - # need to use remove_possible_method here - remove_possible_method :xmlschema - # Convert to a formatted string. See DATE_FORMATS for predefined formats. # # This method is aliased to <tt>to_s</tt>. @@ -70,6 +64,8 @@ class Date alias_method :default_inspect, :inspect alias_method :inspect, :readable_inspect + silence_redefinition_of_method :to_time + # Converts a Date instance to a Time, where the time is set to the beginning of the day. # The timezone can be either :local or :utc (default :local). # @@ -87,6 +83,8 @@ class Date ::Time.send(form, year, month, day) end + silence_redefinition_of_method :xmlschema + # Returns a string which represents the time in used time zone as DateTime # defined by XML Schema: # diff --git a/activesupport/lib/active_support/core_ext/date/zones.rb b/activesupport/lib/active_support/core_ext/date/zones.rb index d94c7bcfc2..2dcf97cff8 100644 --- a/activesupport/lib/active_support/core_ext/date/zones.rb +++ b/activesupport/lib/active_support/core_ext/date/zones.rb @@ -1,5 +1,7 @@ +# frozen_string_literal: true + require "date" -require_relative "../date_and_time/zones" +require "active_support/core_ext/date_and_time/zones" class Date include DateAndTime::Zones diff --git a/activesupport/lib/active_support/core_ext/date_and_time/calculations.rb b/activesupport/lib/active_support/core_ext/date_and_time/calculations.rb index cf01a4542f..f6cb1a384c 100644 --- a/activesupport/lib/active_support/core_ext/date_and_time/calculations.rb +++ b/activesupport/lib/active_support/core_ext/date_and_time/calculations.rb @@ -1,4 +1,6 @@ -require_relative "../object/try" +# frozen_string_literal: true + +require "active_support/core_ext/object/try" module DateAndTime module Calculations @@ -18,9 +20,9 @@ module DateAndTime advance(days: -1) end - # Returns a new date/time representing the previous day. - def prev_day - advance(days: -1) + # Returns a new date/time the specified number of days ago. + def prev_day(days = 1) + advance(days: -days) end # Returns a new date/time representing tomorrow. @@ -28,9 +30,9 @@ module DateAndTime advance(days: 1) end - # Returns a new date/time representing the next day. - def next_day - advance(days: 1) + # Returns a new date/time the specified number of days in the future. + def next_day(days = 1) + advance(days: days) end # Returns true if the date/time is today. @@ -186,9 +188,9 @@ module DateAndTime end end - # Short-hand for months_since(1). - def next_month - months_since(1) + # Returns a new date/time the specified number of months in the future. + def next_month(months = 1) + advance(months: months) end # Short-hand for months_since(3) @@ -196,9 +198,9 @@ module DateAndTime months_since(3) end - # Short-hand for years_since(1). - def next_year - years_since(1) + # Returns a new date/time the specified number of years in the future. + def next_year(years = 1) + advance(years: years) end # Returns a new date/time representing the given day in the previous week. @@ -221,11 +223,15 @@ module DateAndTime end alias_method :last_weekday, :prev_weekday + # Returns a new date/time the specified number of months ago. + def prev_month(months = 1) + advance(months: -months) + end + # Short-hand for months_ago(1). - def prev_month + def last_month months_ago(1) end - alias_method :last_month, :prev_month # Short-hand for months_ago(3). def prev_quarter @@ -233,11 +239,15 @@ module DateAndTime end alias_method :last_quarter, :prev_quarter + # Returns a new date/time the specified number of years ago. + def prev_year(years = 1) + advance(years: -years) + end + # Short-hand for years_ago(1). - def prev_year + def last_year years_ago(1) end - alias_method :last_year, :prev_year # Returns the number of days to the start of the week on the given day. # Week is assumed to start on +start_day+, default is @@ -320,20 +330,28 @@ module DateAndTime beginning_of_year..end_of_year end - # Returns specific next occurring day of week + # Returns a new date/time representing the next occurrence of the specified day of week. + # + # today = Date.today # => Thu, 14 Dec 2017 + # today.next_occurring(:monday) # => Mon, 18 Dec 2017 + # today.next_occurring(:thursday) # => Thu, 21 Dec 2017 def next_occurring(day_of_week) current_day_number = wday != 0 ? wday - 1 : 6 from_now = DAYS_INTO_WEEK.fetch(day_of_week) - current_day_number from_now += 7 unless from_now > 0 - since(from_now.days) + advance(days: from_now) end - # Returns specific previous occurring day of week + # Returns a new date/time representing the previous occurrence of the specified day of week. + # + # today = Date.today # => Thu, 14 Dec 2017 + # today.prev_occurring(:monday) # => Mon, 11 Dec 2017 + # today.prev_occurring(:thursday) # => Thu, 07 Dec 2017 def prev_occurring(day_of_week) current_day_number = wday != 0 ? wday - 1 : 6 ago = current_day_number - DAYS_INTO_WEEK.fetch(day_of_week) ago += 7 unless ago > 0 - ago(ago.days) + advance(days: -ago) end private diff --git a/activesupport/lib/active_support/core_ext/date_and_time/compatibility.rb b/activesupport/lib/active_support/core_ext/date_and_time/compatibility.rb index bb9908df61..d33c36ef73 100644 --- a/activesupport/lib/active_support/core_ext/date_and_time/compatibility.rb +++ b/activesupport/lib/active_support/core_ext/date_and_time/compatibility.rb @@ -1,4 +1,6 @@ -require_relative "../module/attribute_accessors" +# frozen_string_literal: true + +require "active_support/core_ext/module/attribute_accessors" module DateAndTime module Compatibility diff --git a/activesupport/lib/active_support/core_ext/date_and_time/zones.rb b/activesupport/lib/active_support/core_ext/date_and_time/zones.rb index edd724f1d0..894fd9b76d 100644 --- a/activesupport/lib/active_support/core_ext/date_and_time/zones.rb +++ b/activesupport/lib/active_support/core_ext/date_and_time/zones.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module DateAndTime module Zones # Returns the simultaneous time in <tt>Time.zone</tt> if a zone is given or diff --git a/activesupport/lib/active_support/core_ext/date_time.rb b/activesupport/lib/active_support/core_ext/date_time.rb index ce35026a71..790dbeec1b 100644 --- a/activesupport/lib/active_support/core_ext/date_time.rb +++ b/activesupport/lib/active_support/core_ext/date_time.rb @@ -1,5 +1,7 @@ -require_relative "date_time/acts_like" -require_relative "date_time/blank" -require_relative "date_time/calculations" -require_relative "date_time/compatibility" -require_relative "date_time/conversions" +# frozen_string_literal: true + +require "active_support/core_ext/date_time/acts_like" +require "active_support/core_ext/date_time/blank" +require "active_support/core_ext/date_time/calculations" +require "active_support/core_ext/date_time/compatibility" +require "active_support/core_ext/date_time/conversions" diff --git a/activesupport/lib/active_support/core_ext/date_time/acts_like.rb b/activesupport/lib/active_support/core_ext/date_time/acts_like.rb index f0356ee6a0..5dccdfe219 100644 --- a/activesupport/lib/active_support/core_ext/date_time/acts_like.rb +++ b/activesupport/lib/active_support/core_ext/date_time/acts_like.rb @@ -1,5 +1,7 @@ +# frozen_string_literal: true + require "date" -require_relative "../object/acts_like" +require "active_support/core_ext/object/acts_like" class DateTime # Duck-types as a Date-like class. See Object#acts_like?. diff --git a/activesupport/lib/active_support/core_ext/date_time/blank.rb b/activesupport/lib/active_support/core_ext/date_time/blank.rb index b475fd926d..a52c8bc150 100644 --- a/activesupport/lib/active_support/core_ext/date_time/blank.rb +++ b/activesupport/lib/active_support/core_ext/date_time/blank.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "date" class DateTime #:nodoc: diff --git a/activesupport/lib/active_support/core_ext/date_time/calculations.rb b/activesupport/lib/active_support/core_ext/date_time/calculations.rb index 7a9eb8c266..e61b23f842 100644 --- a/activesupport/lib/active_support/core_ext/date_time/calculations.rb +++ b/activesupport/lib/active_support/core_ext/date_time/calculations.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "date" class DateTime diff --git a/activesupport/lib/active_support/core_ext/date_time/compatibility.rb b/activesupport/lib/active_support/core_ext/date_time/compatibility.rb index fe255c087f..2d6b49722d 100644 --- a/activesupport/lib/active_support/core_ext/date_time/compatibility.rb +++ b/activesupport/lib/active_support/core_ext/date_time/compatibility.rb @@ -1,13 +1,15 @@ -require_relative "../date_and_time/compatibility" -require_relative "../module/remove_method" +# frozen_string_literal: true + +require "active_support/core_ext/date_and_time/compatibility" +require "active_support/core_ext/module/redefine_method" class DateTime include DateAndTime::Compatibility - remove_possible_method :to_time + silence_redefinition_of_method :to_time - # Either return an instance of `Time` with the same UTC offset - # as +self+ or an instance of `Time` representing the same time + # Either return an instance of +Time+ with the same UTC offset + # as +self+ or an instance of +Time+ representing the same time # in the the local system timezone depending on the setting of # on the setting of +ActiveSupport.to_time_preserves_timezone+. def to_time diff --git a/activesupport/lib/active_support/core_ext/date_time/conversions.rb b/activesupport/lib/active_support/core_ext/date_time/conversions.rb index 36bfd28f31..29725c89f7 100644 --- a/activesupport/lib/active_support/core_ext/date_time/conversions.rb +++ b/activesupport/lib/active_support/core_ext/date_time/conversions.rb @@ -1,8 +1,10 @@ +# frozen_string_literal: true + require "date" -require_relative "../../inflector/methods" -require_relative "../time/conversions" -require_relative "calculations" -require_relative "../../values/time_zone" +require "active_support/inflector/methods" +require "active_support/core_ext/time/conversions" +require "active_support/core_ext/date_time/calculations" +require "active_support/values/time_zone" class DateTime # Convert to a formatted string. See Time::DATE_FORMATS for predefined formats. diff --git a/activesupport/lib/active_support/core_ext/digest/uuid.rb b/activesupport/lib/active_support/core_ext/digest/uuid.rb index e6d60e3267..6e949a2d72 100644 --- a/activesupport/lib/active_support/core_ext/digest/uuid.rb +++ b/activesupport/lib/active_support/core_ext/digest/uuid.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "securerandom" module Digest @@ -12,7 +14,7 @@ module Digest # Using Digest::MD5 generates version 3 UUIDs; Digest::SHA1 generates version 5 UUIDs. # uuid_from_hash always generates the same UUID for a given name and namespace combination. # - # See RFC 4122 for details of UUID at: http://www.ietf.org/rfc/rfc4122.txt + # See RFC 4122 for details of UUID at: https://www.ietf.org/rfc/rfc4122.txt def self.uuid_from_hash(hash_class, uuid_namespace, name) if hash_class == Digest::MD5 version = 3 diff --git a/activesupport/lib/active_support/core_ext/enumerable.rb b/activesupport/lib/active_support/core_ext/enumerable.rb index 3a4ae6cb8b..17733d955c 100644 --- a/activesupport/lib/active_support/core_ext/enumerable.rb +++ b/activesupport/lib/active_support/core_ext/enumerable.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Enumerable # Enumerable#sum was added in Ruby 2.4, but it only works with Numeric elements # when we omit an identity. diff --git a/activesupport/lib/active_support/core_ext/file.rb b/activesupport/lib/active_support/core_ext/file.rb index ea3267f5da..64553bfa4e 100644 --- a/activesupport/lib/active_support/core_ext/file.rb +++ b/activesupport/lib/active_support/core_ext/file.rb @@ -1 +1,3 @@ -require_relative "file/atomic" +# frozen_string_literal: true + +require "active_support/core_ext/file/atomic" diff --git a/activesupport/lib/active_support/core_ext/file/atomic.rb b/activesupport/lib/active_support/core_ext/file/atomic.rb index 8d6c0d3685..8e288833b6 100644 --- a/activesupport/lib/active_support/core_ext/file/atomic.rb +++ b/activesupport/lib/active_support/core_ext/file/atomic.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "fileutils" class File diff --git a/activesupport/lib/active_support/core_ext/hash.rb b/activesupport/lib/active_support/core_ext/hash.rb index 6122ac57ba..e19aeaa983 100644 --- a/activesupport/lib/active_support/core_ext/hash.rb +++ b/activesupport/lib/active_support/core_ext/hash.rb @@ -1,9 +1,11 @@ -require_relative "hash/compact" -require_relative "hash/conversions" -require_relative "hash/deep_merge" -require_relative "hash/except" -require_relative "hash/indifferent_access" -require_relative "hash/keys" -require_relative "hash/reverse_merge" -require_relative "hash/slice" -require_relative "hash/transform_values" +# frozen_string_literal: true + +require "active_support/core_ext/hash/compact" +require "active_support/core_ext/hash/conversions" +require "active_support/core_ext/hash/deep_merge" +require "active_support/core_ext/hash/except" +require "active_support/core_ext/hash/indifferent_access" +require "active_support/core_ext/hash/keys" +require "active_support/core_ext/hash/reverse_merge" +require "active_support/core_ext/hash/slice" +require "active_support/core_ext/hash/transform_values" diff --git a/activesupport/lib/active_support/core_ext/hash/compact.rb b/activesupport/lib/active_support/core_ext/hash/compact.rb index e357284be0..d6364dd9f3 100644 --- a/activesupport/lib/active_support/core_ext/hash/compact.rb +++ b/activesupport/lib/active_support/core_ext/hash/compact.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class Hash unless Hash.instance_methods(false).include?(:compact) # Returns a hash with non +nil+ values. diff --git a/activesupport/lib/active_support/core_ext/hash/conversions.rb b/activesupport/lib/active_support/core_ext/hash/conversions.rb index 713711e16a..11d28d12a1 100644 --- a/activesupport/lib/active_support/core_ext/hash/conversions.rb +++ b/activesupport/lib/active_support/core_ext/hash/conversions.rb @@ -1,11 +1,13 @@ -require_relative "../../xml_mini" -require_relative "../../time" -require_relative "../object/blank" -require_relative "../object/to_param" -require_relative "../object/to_query" -require_relative "../array/wrap" -require_relative "reverse_merge" -require_relative "../string/inflections" +# frozen_string_literal: true + +require "active_support/xml_mini" +require "active_support/time" +require "active_support/core_ext/object/blank" +require "active_support/core_ext/object/to_param" +require "active_support/core_ext/object/to_query" +require "active_support/core_ext/array/wrap" +require "active_support/core_ext/hash/reverse_merge" +require "active_support/core_ext/string/inflections" class Hash # Returns a string containing an XML representation of its receiver: @@ -71,7 +73,7 @@ class Hash # configure your own builder with the <tt>:builder</tt> option. The method also accepts # options like <tt>:dasherize</tt> and friends, they are forwarded to the builder. def to_xml(options = {}) - require_relative "../../builder" unless defined?(Builder) + require "active_support/builder" unless defined?(Builder) options = options.dup options[:indent] ||= 2 diff --git a/activesupport/lib/active_support/core_ext/hash/deep_merge.rb b/activesupport/lib/active_support/core_ext/hash/deep_merge.rb index 9c9faf67ea..9bc50b7bc6 100644 --- a/activesupport/lib/active_support/core_ext/hash/deep_merge.rb +++ b/activesupport/lib/active_support/core_ext/hash/deep_merge.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class Hash # Returns a new hash with +self+ and +other_hash+ merged recursively. # @@ -19,20 +21,14 @@ class Hash # Same as +deep_merge+, but modifies +self+. def deep_merge!(other_hash, &block) - other_hash.each_pair do |current_key, other_value| - this_value = self[current_key] - - self[current_key] = if this_value.is_a?(Hash) && other_value.is_a?(Hash) - this_value.deep_merge(other_value, &block) + merge!(other_hash) do |key, this_val, other_val| + if this_val.is_a?(Hash) && other_val.is_a?(Hash) + this_val.deep_merge(other_val, &block) + elsif block_given? + block.call(key, this_val, other_val) else - if block_given? && key?(current_key) - block.call(current_key, this_value, other_value) - else - other_value - end + other_val end end - - self end end diff --git a/activesupport/lib/active_support/core_ext/hash/except.rb b/activesupport/lib/active_support/core_ext/hash/except.rb index 2f6d38c1f6..6258610c98 100644 --- a/activesupport/lib/active_support/core_ext/hash/except.rb +++ b/activesupport/lib/active_support/core_ext/hash/except.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class Hash # Returns a hash that includes everything except given keys. # hash = { a: true, b: false, c: nil } diff --git a/activesupport/lib/active_support/core_ext/hash/indifferent_access.rb b/activesupport/lib/active_support/core_ext/hash/indifferent_access.rb index 4b7fe34cc9..a38f33f128 100644 --- a/activesupport/lib/active_support/core_ext/hash/indifferent_access.rb +++ b/activesupport/lib/active_support/core_ext/hash/indifferent_access.rb @@ -1,4 +1,6 @@ -require_relative "../../hash_with_indifferent_access" +# frozen_string_literal: true + +require "active_support/hash_with_indifferent_access" class Hash # Returns an <tt>ActiveSupport::HashWithIndifferentAccess</tt> out of its receiver: diff --git a/activesupport/lib/active_support/core_ext/hash/keys.rb b/activesupport/lib/active_support/core_ext/hash/keys.rb index b7089357a8..bdf196ec3d 100644 --- a/activesupport/lib/active_support/core_ext/hash/keys.rb +++ b/activesupport/lib/active_support/core_ext/hash/keys.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class Hash # Returns a new hash with all keys converted using the +block+ operation. # @@ -16,7 +18,7 @@ class Hash result[yield(key)] = self[key] end result - end + end unless method_defined? :transform_keys # Destructively converts all keys using the +block+ operations. # Same as +transform_keys+ but modifies +self+. @@ -26,7 +28,7 @@ class Hash self[yield(key)] = delete(key) end self - end + end unless method_defined? :transform_keys! # Returns a new hash with all keys converted to strings. # diff --git a/activesupport/lib/active_support/core_ext/hash/reverse_merge.rb b/activesupport/lib/active_support/core_ext/hash/reverse_merge.rb index 061c959442..ef8d592829 100644 --- a/activesupport/lib/active_support/core_ext/hash/reverse_merge.rb +++ b/activesupport/lib/active_support/core_ext/hash/reverse_merge.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class Hash # Merges the caller into +other_hash+. For example, # @@ -16,8 +18,7 @@ class Hash # Destructive +reverse_merge+. def reverse_merge!(other_hash) - # right wins if there is no left - merge!(other_hash) { |key, left, right| left } + replace(reverse_merge(other_hash)) end alias_method :reverse_update, :reverse_merge! alias_method :with_defaults!, :reverse_merge! diff --git a/activesupport/lib/active_support/core_ext/hash/slice.rb b/activesupport/lib/active_support/core_ext/hash/slice.rb index 161b00dfb3..2bd0a56ea4 100644 --- a/activesupport/lib/active_support/core_ext/hash/slice.rb +++ b/activesupport/lib/active_support/core_ext/hash/slice.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class Hash # Slices a hash to include only the given keys. Returns a hash containing # the given keys. @@ -19,9 +21,8 @@ class Hash # valid_keys = [:mass, :velocity, :time] # search(options.slice(*valid_keys)) def slice(*keys) - keys.map! { |key| convert_key(key) } if respond_to?(:convert_key, true) - keys.each_with_object(self.class.new) { |k, hash| hash[k] = self[k] if has_key?(k) } - end + keys.each_with_object(Hash.new) { |k, hash| hash[k] = self[k] if has_key?(k) } + end unless method_defined?(:slice) # Replaces the hash with only the given keys. # Returns a hash containing the removed key/value pairs. @@ -29,7 +30,6 @@ class Hash # { a: 1, b: 2, c: 3, d: 4 }.slice!(:a, :b) # # => {:c=>3, :d=>4} def slice!(*keys) - keys.map! { |key| convert_key(key) } if respond_to?(:convert_key, true) omit = slice(*self.keys - keys) hash = slice(*keys) hash.default = default diff --git a/activesupport/lib/active_support/core_ext/hash/transform_values.rb b/activesupport/lib/active_support/core_ext/hash/transform_values.rb index 2f693bff0c..4b19c9fc1f 100644 --- a/activesupport/lib/active_support/core_ext/hash/transform_values.rb +++ b/activesupport/lib/active_support/core_ext/hash/transform_values.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class Hash # Returns a new hash with the results of running +block+ once for every value. # The keys are unchanged. diff --git a/activesupport/lib/active_support/core_ext/integer.rb b/activesupport/lib/active_support/core_ext/integer.rb index e7c1aae980..d22701306a 100644 --- a/activesupport/lib/active_support/core_ext/integer.rb +++ b/activesupport/lib/active_support/core_ext/integer.rb @@ -1,3 +1,5 @@ -require_relative "integer/multiple" -require_relative "integer/inflections" -require_relative "integer/time" +# frozen_string_literal: true + +require "active_support/core_ext/integer/multiple" +require "active_support/core_ext/integer/inflections" +require "active_support/core_ext/integer/time" diff --git a/activesupport/lib/active_support/core_ext/integer/inflections.rb b/activesupport/lib/active_support/core_ext/integer/inflections.rb index 0b2ada8b22..aef3266f28 100644 --- a/activesupport/lib/active_support/core_ext/integer/inflections.rb +++ b/activesupport/lib/active_support/core_ext/integer/inflections.rb @@ -1,4 +1,6 @@ -require_relative "../../inflector" +# frozen_string_literal: true + +require "active_support/inflector" class Integer # Ordinalize turns a number into an ordinal string used to denote the diff --git a/activesupport/lib/active_support/core_ext/integer/multiple.rb b/activesupport/lib/active_support/core_ext/integer/multiple.rb index c668c7c2eb..e7606662d3 100644 --- a/activesupport/lib/active_support/core_ext/integer/multiple.rb +++ b/activesupport/lib/active_support/core_ext/integer/multiple.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class Integer # Check whether the integer is evenly divisible by the argument. # diff --git a/activesupport/lib/active_support/core_ext/integer/time.rb b/activesupport/lib/active_support/core_ext/integer/time.rb index d5625dfd1c..5efb89cf9f 100644 --- a/activesupport/lib/active_support/core_ext/integer/time.rb +++ b/activesupport/lib/active_support/core_ext/integer/time.rb @@ -1,27 +1,20 @@ -require_relative "../../duration" -require_relative "../numeric/time" +# frozen_string_literal: true + +require "active_support/duration" +require "active_support/core_ext/numeric/time" class Integer - # Enables the use of time calculations and declarations, like <tt>45.minutes + - # 2.hours + 4.years</tt>. - # - # These methods use Time#advance for precise date calculations when using - # <tt>from_now</tt>, +ago+, etc. as well as adding or subtracting their - # results from a Time object. - # - # # equivalent to Time.now.advance(months: 1) - # 1.month.from_now + # Returns a Duration instance matching the number of months provided. # - # # equivalent to Time.now.advance(years: 2) - # 2.years.from_now - # - # # equivalent to Time.now.advance(months: 4, years: 5) - # (4.months + 5.years).from_now + # 2.months # => 2 months def months ActiveSupport::Duration.months(self) end alias :month :months + # Returns a Duration instance matching the number of years provided. + # + # 2.years # => 2 years def years ActiveSupport::Duration.years(self) end diff --git a/activesupport/lib/active_support/core_ext/kernel.rb b/activesupport/lib/active_support/core_ext/kernel.rb index 26142b107b..0f4356fbdd 100644 --- a/activesupport/lib/active_support/core_ext/kernel.rb +++ b/activesupport/lib/active_support/core_ext/kernel.rb @@ -1,4 +1,6 @@ -require_relative "kernel/agnostics" -require_relative "kernel/concern" -require_relative "kernel/reporting" -require_relative "kernel/singleton_class" +# frozen_string_literal: true + +require "active_support/core_ext/kernel/agnostics" +require "active_support/core_ext/kernel/concern" +require "active_support/core_ext/kernel/reporting" +require "active_support/core_ext/kernel/singleton_class" diff --git a/activesupport/lib/active_support/core_ext/kernel/agnostics.rb b/activesupport/lib/active_support/core_ext/kernel/agnostics.rb index 64837d87aa..403b5f31f0 100644 --- a/activesupport/lib/active_support/core_ext/kernel/agnostics.rb +++ b/activesupport/lib/active_support/core_ext/kernel/agnostics.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class Object # Makes backticks behave (somewhat more) similarly on all platforms. # On win32 `nonexistent_command` raises Errno::ENOENT; on Unix, the diff --git a/activesupport/lib/active_support/core_ext/kernel/concern.rb b/activesupport/lib/active_support/core_ext/kernel/concern.rb index 535f0d21df..0b2baed780 100644 --- a/activesupport/lib/active_support/core_ext/kernel/concern.rb +++ b/activesupport/lib/active_support/core_ext/kernel/concern.rb @@ -1,4 +1,6 @@ -require_relative "../module/concerning" +# frozen_string_literal: true + +require "active_support/core_ext/module/concerning" module Kernel module_function diff --git a/activesupport/lib/active_support/core_ext/kernel/reporting.rb b/activesupport/lib/active_support/core_ext/kernel/reporting.rb index c02618d5f3..9155bd6c10 100644 --- a/activesupport/lib/active_support/core_ext/kernel/reporting.rb +++ b/activesupport/lib/active_support/core_ext/kernel/reporting.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Kernel module_function diff --git a/activesupport/lib/active_support/core_ext/kernel/singleton_class.rb b/activesupport/lib/active_support/core_ext/kernel/singleton_class.rb index 9bbf1bbd73..6715eba80a 100644 --- a/activesupport/lib/active_support/core_ext/kernel/singleton_class.rb +++ b/activesupport/lib/active_support/core_ext/kernel/singleton_class.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module Kernel # class_eval on an object acts like singleton_class.class_eval. def class_eval(*args, &block) diff --git a/activesupport/lib/active_support/core_ext/load_error.rb b/activesupport/lib/active_support/core_ext/load_error.rb index d273487010..750f858fcc 100644 --- a/activesupport/lib/active_support/core_ext/load_error.rb +++ b/activesupport/lib/active_support/core_ext/load_error.rb @@ -1,11 +1,6 @@ -class LoadError - REGEXPS = [ - /^no such file to load -- (.+)$/i, - /^Missing \w+ (?:file\s*)?([^\s]+.rb)$/i, - /^Missing API definition file in (.+)$/i, - /^cannot load such file -- (.+)$/i, - ] +# frozen_string_literal: true +class LoadError # Returns true if the given path name (except perhaps for the ".rb" # extension) is the missing file which caused the exception to be raised. def is_missing?(location) diff --git a/activesupport/lib/active_support/core_ext/marshal.rb b/activesupport/lib/active_support/core_ext/marshal.rb index bba2b3be2e..0c72cd7b47 100644 --- a/activesupport/lib/active_support/core_ext/marshal.rb +++ b/activesupport/lib/active_support/core_ext/marshal.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module ActiveSupport module MarshalWithAutoloading # :nodoc: def load(source, proc = nil) diff --git a/activesupport/lib/active_support/core_ext/module.rb b/activesupport/lib/active_support/core_ext/module.rb index 3ee394edd9..d91e3fba6a 100644 --- a/activesupport/lib/active_support/core_ext/module.rb +++ b/activesupport/lib/active_support/core_ext/module.rb @@ -1,11 +1,14 @@ -require_relative "module/aliasing" -require_relative "module/introspection" -require_relative "module/anonymous" -require_relative "module/reachable" -require_relative "module/attribute_accessors" -require_relative "module/attribute_accessors_per_thread" -require_relative "module/attr_internal" -require_relative "module/concerning" -require_relative "module/delegation" -require_relative "module/deprecation" -require_relative "module/remove_method" +# frozen_string_literal: true + +require "active_support/core_ext/module/aliasing" +require "active_support/core_ext/module/introspection" +require "active_support/core_ext/module/anonymous" +require "active_support/core_ext/module/reachable" +require "active_support/core_ext/module/attribute_accessors" +require "active_support/core_ext/module/attribute_accessors_per_thread" +require "active_support/core_ext/module/attr_internal" +require "active_support/core_ext/module/concerning" +require "active_support/core_ext/module/delegation" +require "active_support/core_ext/module/deprecation" +require "active_support/core_ext/module/redefine_method" +require "active_support/core_ext/module/remove_method" diff --git a/activesupport/lib/active_support/core_ext/module/aliasing.rb b/activesupport/lib/active_support/core_ext/module/aliasing.rb index c48bd3354a..6f64d11627 100644 --- a/activesupport/lib/active_support/core_ext/module/aliasing.rb +++ b/activesupport/lib/active_support/core_ext/module/aliasing.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class Module # Allows you to make aliases for attributes, which includes # getter, setter, and a predicate. diff --git a/activesupport/lib/active_support/core_ext/module/anonymous.rb b/activesupport/lib/active_support/core_ext/module/anonymous.rb index 510c9a5430..d1c86b8722 100644 --- a/activesupport/lib/active_support/core_ext/module/anonymous.rb +++ b/activesupport/lib/active_support/core_ext/module/anonymous.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class Module # A module may or may not have a name. # diff --git a/activesupport/lib/active_support/core_ext/module/attr_internal.rb b/activesupport/lib/active_support/core_ext/module/attr_internal.rb index 5081d5f7a3..7801f6d181 100644 --- a/activesupport/lib/active_support/core_ext/module/attr_internal.rb +++ b/activesupport/lib/active_support/core_ext/module/attr_internal.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class Module # Declares an attribute reader backed by an internally-named instance variable. def attr_internal_reader(*attrs) diff --git a/activesupport/lib/active_support/core_ext/module/attribute_accessors.rb b/activesupport/lib/active_support/core_ext/module/attribute_accessors.rb index e978bd41d6..580baffa2b 100644 --- a/activesupport/lib/active_support/core_ext/module/attribute_accessors.rb +++ b/activesupport/lib/active_support/core_ext/module/attribute_accessors.rb @@ -1,5 +1,7 @@ -require_relative "../array/extract_options" -require_relative "../regexp" +# frozen_string_literal: true + +require "active_support/core_ext/array/extract_options" +require "active_support/core_ext/regexp" # Extends the module object with class/module and instance accessors for # class/module attributes, just like the native attr* accessors for instance diff --git a/activesupport/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb b/activesupport/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb index 9ef834fa6f..4b9b6ea9bd 100644 --- a/activesupport/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +++ b/activesupport/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb @@ -1,5 +1,7 @@ -require_relative "../array/extract_options" -require_relative "../regexp" +# frozen_string_literal: true + +require "active_support/core_ext/array/extract_options" +require "active_support/core_ext/regexp" # Extends the module object with class/module and instance accessors for # class/module attributes, just like the native attr* accessors for instance diff --git a/activesupport/lib/active_support/core_ext/module/concerning.rb b/activesupport/lib/active_support/core_ext/module/concerning.rb index eb821aba60..7bbbf321ab 100644 --- a/activesupport/lib/active_support/core_ext/module/concerning.rb +++ b/activesupport/lib/active_support/core_ext/module/concerning.rb @@ -1,4 +1,6 @@ -require_relative "../../concern" +# frozen_string_literal: true + +require "active_support/concern" class Module # = Bite-sized separation of concerns @@ -20,7 +22,7 @@ class Module # # == Using comments: # - # class Todo + # class Todo < ApplicationRecord # # Other todo implementation # # ... # @@ -28,7 +30,6 @@ class Module # has_many :events # # before_create :track_creation - # after_destroy :track_deletion # # private # def track_creation @@ -40,7 +41,7 @@ class Module # # Noisy syntax. # - # class Todo + # class Todo < ApplicationRecord # # Other todo implementation # # ... # @@ -50,7 +51,6 @@ class Module # included do # has_many :events # before_create :track_creation - # after_destroy :track_deletion # end # # private @@ -68,7 +68,7 @@ class Module # increased overhead can be a reasonable tradeoff even if it reduces our # at-a-glance perception of how things work. # - # class Todo + # class Todo < ApplicationRecord # # Other todo implementation # # ... # @@ -80,7 +80,7 @@ class Module # By quieting the mix-in noise, we arrive at a natural, low-ceremony way to # separate bite-sized concerns. # - # class Todo + # class Todo < ApplicationRecord # # Other todo implementation # # ... # @@ -88,7 +88,6 @@ class Module # included do # has_many :events # before_create :track_creation - # after_destroy :track_deletion # end # # private @@ -99,7 +98,7 @@ class Module # end # # Todo.ancestors - # # => [Todo, Todo::EventTracking, Object] + # # => [Todo, Todo::EventTracking, ApplicationRecord, Object] # # This small step has some wonderful ripple effects. We can # * grok the behavior of our class in one glance, diff --git a/activesupport/lib/active_support/core_ext/module/delegation.rb b/activesupport/lib/active_support/core_ext/module/delegation.rb index 04f34e553d..4310df3024 100644 --- a/activesupport/lib/active_support/core_ext/module/delegation.rb +++ b/activesupport/lib/active_support/core_ext/module/delegation.rb @@ -1,5 +1,7 @@ +# frozen_string_literal: true + require "set" -require_relative "../regexp" +require "active_support/core_ext/regexp" class Module # Error generated by +delegate+ when a method is called on +nil+ and +allow_nil+ @@ -113,11 +115,8 @@ class Module # invoice.customer_address # => 'Vimmersvej 13' # # If the target is +nil+ and does not respond to the delegated method a - # +Module::DelegationError+ is raised, as with any other value. Sometimes, - # however, it makes sense to be robust to that situation and that is the - # purpose of the <tt>:allow_nil</tt> option: If the target is not +nil+, or it - # is and responds to the method, everything works as usual. But if it is +nil+ - # and does not respond to the delegated method, +nil+ is returned. + # +Module::DelegationError+ is raised. If you wish to instead return +nil+, + # use the <tt>:allow_nil</tt> option. # # class User < ActiveRecord::Base # has_one :profile @@ -174,7 +173,7 @@ class Module to = to.to_s to = "self.#{to}" if DELEGATION_RESERVED_METHOD_NAMES.include?(to) - methods.each do |method| + methods.map do |method| # Attribute writer methods only accept one argument. Makes sure []= # methods still accept two arguments. definition = /[^\]]=$/.match?(method) ? "arg" : "*args, &block" @@ -272,7 +271,15 @@ class Module if #{target}.respond_to?(method) #{target}.public_send(method, *args, &block) else - super + begin + super + rescue NoMethodError + if #{target}.nil? + raise DelegationError, "\#{method} delegated to #{target}, but #{target} is nil" + else + raise + end + end end end RUBY diff --git a/activesupport/lib/active_support/core_ext/module/deprecation.rb b/activesupport/lib/active_support/core_ext/module/deprecation.rb index f3f2e7f5fc..71c42eb357 100644 --- a/activesupport/lib/active_support/core_ext/module/deprecation.rb +++ b/activesupport/lib/active_support/core_ext/module/deprecation.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class Module # deprecate :foo # deprecate bar: 'message' diff --git a/activesupport/lib/active_support/core_ext/module/introspection.rb b/activesupport/lib/active_support/core_ext/module/introspection.rb index 4a7930792c..c5bb598bd1 100644 --- a/activesupport/lib/active_support/core_ext/module/introspection.rb +++ b/activesupport/lib/active_support/core_ext/module/introspection.rb @@ -1,4 +1,6 @@ -require_relative "../../inflector" +# frozen_string_literal: true + +require "active_support/inflector" class Module # Returns the name of the module containing this one. diff --git a/activesupport/lib/active_support/core_ext/module/reachable.rb b/activesupport/lib/active_support/core_ext/module/reachable.rb index 0f78999634..e9cbda5245 100644 --- a/activesupport/lib/active_support/core_ext/module/reachable.rb +++ b/activesupport/lib/active_support/core_ext/module/reachable.rb @@ -1,8 +1,11 @@ -require_relative "anonymous" -require_relative "../string/inflections" +# frozen_string_literal: true + +require "active_support/core_ext/module/anonymous" +require "active_support/core_ext/string/inflections" class Module def reachable? #:nodoc: !anonymous? && name.safe_constantize.equal?(self) end + deprecate :reachable? end diff --git a/activesupport/lib/active_support/core_ext/module/redefine_method.rb b/activesupport/lib/active_support/core_ext/module/redefine_method.rb new file mode 100644 index 0000000000..a0a6622ca4 --- /dev/null +++ b/activesupport/lib/active_support/core_ext/module/redefine_method.rb @@ -0,0 +1,49 @@ +# frozen_string_literal: true + +class Module + if RUBY_VERSION >= "2.3" + # Marks the named method as intended to be redefined, if it exists. + # Suppresses the Ruby method redefinition warning. Prefer + # #redefine_method where possible. + def silence_redefinition_of_method(method) + if method_defined?(method) || private_method_defined?(method) + # This suppresses the "method redefined" warning; the self-alias + # looks odd, but means we don't need to generate a unique name + alias_method method, method + end + end + else + def silence_redefinition_of_method(method) + if method_defined?(method) || private_method_defined?(method) + alias_method :__rails_redefine, method + remove_method :__rails_redefine + end + end + end + + # Replaces the existing method definition, if there is one, with the passed + # block as its body. + def redefine_method(method, &block) + visibility = method_visibility(method) + silence_redefinition_of_method(method) + define_method(method, &block) + send(visibility, method) + end + + # Replaces the existing singleton method definition, if there is one, with + # the passed block as its body. + def redefine_singleton_method(method, &block) + singleton_class.redefine_method(method, &block) + end + + def method_visibility(method) # :nodoc: + case + when private_method_defined?(method) + :private + when protected_method_defined?(method) + :protected + else + :public + end + end +end diff --git a/activesupport/lib/active_support/core_ext/module/remove_method.rb b/activesupport/lib/active_support/core_ext/module/remove_method.rb index d5ec16d68a..97eb5f9eca 100644 --- a/activesupport/lib/active_support/core_ext/module/remove_method.rb +++ b/activesupport/lib/active_support/core_ext/module/remove_method.rb @@ -1,3 +1,7 @@ +# frozen_string_literal: true + +require "active_support/core_ext/module/redefine_method" + class Module # Removes the named method, if it exists. def remove_possible_method(method) @@ -8,28 +12,6 @@ class Module # Removes the named singleton method, if it exists. def remove_possible_singleton_method(method) - singleton_class.instance_eval do - remove_possible_method(method) - end - end - - # Replaces the existing method definition, if there is one, with the passed - # block as its body. - def redefine_method(method, &block) - visibility = method_visibility(method) - remove_possible_method(method) - define_method(method, &block) - send(visibility, method) - end - - def method_visibility(method) # :nodoc: - case - when private_method_defined?(method) - :private - when protected_method_defined?(method) - :protected - else - :public - end + singleton_class.remove_possible_method(method) end end diff --git a/activesupport/lib/active_support/core_ext/name_error.rb b/activesupport/lib/active_support/core_ext/name_error.rb index 97a38efde2..6d37cd9dfd 100644 --- a/activesupport/lib/active_support/core_ext/name_error.rb +++ b/activesupport/lib/active_support/core_ext/name_error.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class NameError # Extract the name of the missing constant from the exception message. # diff --git a/activesupport/lib/active_support/core_ext/numeric.rb b/activesupport/lib/active_support/core_ext/numeric.rb index e10d7708bd..0b04e359f9 100644 --- a/activesupport/lib/active_support/core_ext/numeric.rb +++ b/activesupport/lib/active_support/core_ext/numeric.rb @@ -1,4 +1,6 @@ -require_relative "numeric/bytes" -require_relative "numeric/time" -require_relative "numeric/inquiry" -require_relative "numeric/conversions" +# frozen_string_literal: true + +require "active_support/core_ext/numeric/bytes" +require "active_support/core_ext/numeric/time" +require "active_support/core_ext/numeric/inquiry" +require "active_support/core_ext/numeric/conversions" diff --git a/activesupport/lib/active_support/core_ext/numeric/bytes.rb b/activesupport/lib/active_support/core_ext/numeric/bytes.rb index dfbca32474..b002eba406 100644 --- a/activesupport/lib/active_support/core_ext/numeric/bytes.rb +++ b/activesupport/lib/active_support/core_ext/numeric/bytes.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class Numeric KILOBYTE = 1024 MEGABYTE = KILOBYTE * 1024 diff --git a/activesupport/lib/active_support/core_ext/numeric/conversions.rb b/activesupport/lib/active_support/core_ext/numeric/conversions.rb index 397e32ee8e..f6c2713986 100644 --- a/activesupport/lib/active_support/core_ext/numeric/conversions.rb +++ b/activesupport/lib/active_support/core_ext/numeric/conversions.rb @@ -1,6 +1,8 @@ -require_relative "../big_decimal/conversions" -require_relative "../../number_helper" -require_relative "../module/deprecation" +# frozen_string_literal: true + +require "active_support/core_ext/big_decimal/conversions" +require "active_support/number_helper" +require "active_support/core_ext/module/deprecation" module ActiveSupport::NumericWithFormat # Provides options for converting numbers into formatted strings. @@ -106,19 +108,19 @@ module ActiveSupport::NumericWithFormat when Integer, String super(format) when :phone - return ActiveSupport::NumberHelper.number_to_phone(self, options || {}) + ActiveSupport::NumberHelper.number_to_phone(self, options || {}) when :currency - return ActiveSupport::NumberHelper.number_to_currency(self, options || {}) + ActiveSupport::NumberHelper.number_to_currency(self, options || {}) when :percentage - return ActiveSupport::NumberHelper.number_to_percentage(self, options || {}) + ActiveSupport::NumberHelper.number_to_percentage(self, options || {}) when :delimited - return ActiveSupport::NumberHelper.number_to_delimited(self, options || {}) + ActiveSupport::NumberHelper.number_to_delimited(self, options || {}) when :rounded - return ActiveSupport::NumberHelper.number_to_rounded(self, options || {}) + ActiveSupport::NumberHelper.number_to_rounded(self, options || {}) when :human - return ActiveSupport::NumberHelper.number_to_human(self, options || {}) + ActiveSupport::NumberHelper.number_to_human(self, options || {}) when :human_size - return ActiveSupport::NumberHelper.number_to_human_size(self, options || {}) + ActiveSupport::NumberHelper.number_to_human_size(self, options || {}) when Symbol super() else diff --git a/activesupport/lib/active_support/core_ext/numeric/inquiry.rb b/activesupport/lib/active_support/core_ext/numeric/inquiry.rb index ec79701189..15334c91f1 100644 --- a/activesupport/lib/active_support/core_ext/numeric/inquiry.rb +++ b/activesupport/lib/active_support/core_ext/numeric/inquiry.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + unless 1.respond_to?(:positive?) # TODO: Remove this file when we drop support to ruby < 2.3 class Numeric # Returns true if the number is positive. diff --git a/activesupport/lib/active_support/core_ext/numeric/time.rb b/activesupport/lib/active_support/core_ext/numeric/time.rb index cf002552fb..bc4627f7a2 100644 --- a/activesupport/lib/active_support/core_ext/numeric/time.rb +++ b/activesupport/lib/active_support/core_ext/numeric/time.rb @@ -1,23 +1,15 @@ -require_relative "../../duration" -require_relative "../time/calculations" -require_relative "../time/acts_like" -require_relative "../date/calculations" -require_relative "../date/acts_like" +# frozen_string_literal: true + +require "active_support/duration" +require "active_support/core_ext/time/calculations" +require "active_support/core_ext/time/acts_like" +require "active_support/core_ext/date/calculations" +require "active_support/core_ext/date/acts_like" class Numeric - # Enables the use of time calculations and declarations, like 45.minutes + 2.hours + 4.years. - # - # These methods use Time#advance for precise date calculations when using from_now, ago, etc. - # as well as adding or subtracting their results from a Time object. For example: - # - # # equivalent to Time.current.advance(months: 1) - # 1.month.from_now - # - # # equivalent to Time.current.advance(years: 2) - # 2.years.from_now + # Returns a Duration instance matching the number of seconds provided. # - # # equivalent to Time.current.advance(months: 4, years: 5) - # (4.months + 5.years).from_now + # 2.seconds # => 2 seconds def seconds ActiveSupport::Duration.seconds(self) end @@ -64,10 +56,10 @@ class Numeric alias :fortnight :fortnights # Returns the number of milliseconds equivalent to the seconds provided. - # Used with the standard time durations, like 1.hour.in_milliseconds -- - # so we can feed them to JavaScript functions like getTime(). + # Used with the standard time durations. # - # 2.in_milliseconds # => 2_000 + # 2.in_milliseconds # => 2000 + # 1.hour.in_milliseconds # => 3600000 def in_milliseconds self * 1000 end diff --git a/activesupport/lib/active_support/core_ext/object.rb b/activesupport/lib/active_support/core_ext/object.rb index 993cc6a059..efd34cc692 100644 --- a/activesupport/lib/active_support/core_ext/object.rb +++ b/activesupport/lib/active_support/core_ext/object.rb @@ -1,14 +1,16 @@ -require_relative "object/acts_like" -require_relative "object/blank" -require_relative "object/duplicable" -require_relative "object/deep_dup" -require_relative "object/try" -require_relative "object/inclusion" +# frozen_string_literal: true -require_relative "object/conversions" -require_relative "object/instance_variables" +require "active_support/core_ext/object/acts_like" +require "active_support/core_ext/object/blank" +require "active_support/core_ext/object/duplicable" +require "active_support/core_ext/object/deep_dup" +require "active_support/core_ext/object/try" +require "active_support/core_ext/object/inclusion" -require_relative "object/json" -require_relative "object/to_param" -require_relative "object/to_query" -require_relative "object/with_options" +require "active_support/core_ext/object/conversions" +require "active_support/core_ext/object/instance_variables" + +require "active_support/core_ext/object/json" +require "active_support/core_ext/object/to_param" +require "active_support/core_ext/object/to_query" +require "active_support/core_ext/object/with_options" diff --git a/activesupport/lib/active_support/core_ext/object/acts_like.rb b/activesupport/lib/active_support/core_ext/object/acts_like.rb index 3912cc5ace..403ee20e39 100644 --- a/activesupport/lib/active_support/core_ext/object/acts_like.rb +++ b/activesupport/lib/active_support/core_ext/object/acts_like.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class Object # A duck-type assistant method. For example, Active Support extends Date # to define an <tt>acts_like_date?</tt> method, and extends Time to define @@ -5,6 +7,15 @@ class Object # <tt>x.acts_like?(:date)</tt> to do duck-type-safe comparisons, since classes that # we want to act like Time simply need to define an <tt>acts_like_time?</tt> method. def acts_like?(duck) - respond_to? :"acts_like_#{duck}?" + case duck + when :time + respond_to? :acts_like_time? + when :date + respond_to? :acts_like_date? + when :string + respond_to? :acts_like_string? + else + respond_to? :"acts_like_#{duck}?" + end end end diff --git a/activesupport/lib/active_support/core_ext/object/blank.rb b/activesupport/lib/active_support/core_ext/object/blank.rb index c37c2649d6..2ca431ab10 100644 --- a/activesupport/lib/active_support/core_ext/object/blank.rb +++ b/activesupport/lib/active_support/core_ext/object/blank.rb @@ -1,4 +1,7 @@ -require_relative "../regexp" +# frozen_string_literal: true + +require "active_support/core_ext/regexp" +require "concurrent/map" class Object # An object is blank if it's false, empty, or a whitespace string. @@ -100,6 +103,9 @@ end class String BLANK_RE = /\A[[:space:]]*\z/ + ENCODED_BLANKS = Concurrent::Map.new do |h, enc| + h[enc] = Regexp.new(BLANK_RE.source.encode(enc), BLANK_RE.options | Regexp::FIXEDENCODING) + end # A string is blank if it's empty or contains whitespaces only: # @@ -117,7 +123,12 @@ class String # The regexp that matches blank strings is expensive. For the case of empty # strings we can speed up this method (~3.5x) with an empty? call. The # penalty for the rest of strings is marginal. - empty? || BLANK_RE.match?(self) + empty? || + begin + BLANK_RE.match?(self) + rescue Encoding::CompatibilityError + ENCODED_BLANKS[self.encoding].match?(self) + end end end diff --git a/activesupport/lib/active_support/core_ext/object/conversions.rb b/activesupport/lib/active_support/core_ext/object/conversions.rb index 9d3bdbc528..624fb8d77c 100644 --- a/activesupport/lib/active_support/core_ext/object/conversions.rb +++ b/activesupport/lib/active_support/core_ext/object/conversions.rb @@ -1,4 +1,6 @@ -require_relative "to_param" -require_relative "to_query" -require_relative "../array/conversions" -require_relative "../hash/conversions" +# frozen_string_literal: true + +require "active_support/core_ext/object/to_param" +require "active_support/core_ext/object/to_query" +require "active_support/core_ext/array/conversions" +require "active_support/core_ext/hash/conversions" diff --git a/activesupport/lib/active_support/core_ext/object/deep_dup.rb b/activesupport/lib/active_support/core_ext/object/deep_dup.rb index d966a29408..c66c5eb2d9 100644 --- a/activesupport/lib/active_support/core_ext/object/deep_dup.rb +++ b/activesupport/lib/active_support/core_ext/object/deep_dup.rb @@ -1,4 +1,6 @@ -require_relative "duplicable" +# frozen_string_literal: true + +require "active_support/core_ext/object/duplicable" class Object # Returns a deep copy of object if it's duplicable. If it's diff --git a/activesupport/lib/active_support/core_ext/object/duplicable.rb b/activesupport/lib/active_support/core_ext/object/duplicable.rb index b028df97ee..9bb99087bc 100644 --- a/activesupport/lib/active_support/core_ext/object/duplicable.rb +++ b/activesupport/lib/active_support/core_ext/object/duplicable.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + #-- # Most objects are cloneable, but not all. For example you can't dup methods: # @@ -106,8 +108,8 @@ require "bigdecimal" class BigDecimal # BigDecimals are duplicable: # - # BigDecimal.new("1.2").duplicable? # => true - # BigDecimal.new("1.2").dup # => #<BigDecimal:...,'0.12E1',18(18)> + # BigDecimal("1.2").duplicable? # => true + # BigDecimal("1.2").dup # => #<BigDecimal:...,'0.12E1',18(18)> def duplicable? true end diff --git a/activesupport/lib/active_support/core_ext/object/inclusion.rb b/activesupport/lib/active_support/core_ext/object/inclusion.rb index 98bf820d36..6064e92f20 100644 --- a/activesupport/lib/active_support/core_ext/object/inclusion.rb +++ b/activesupport/lib/active_support/core_ext/object/inclusion.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class Object # Returns true if this object is included in the argument. Argument must be # any object which responds to +#include?+. Usage: diff --git a/activesupport/lib/active_support/core_ext/object/instance_variables.rb b/activesupport/lib/active_support/core_ext/object/instance_variables.rb index 593a7a4940..12fdf840b5 100644 --- a/activesupport/lib/active_support/core_ext/object/instance_variables.rb +++ b/activesupport/lib/active_support/core_ext/object/instance_variables.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class Object # Returns a hash with string keys that maps instance variable names without "@" to their # corresponding values. diff --git a/activesupport/lib/active_support/core_ext/object/json.rb b/activesupport/lib/active_support/core_ext/object/json.rb index d54373d5f2..f7c623fe13 100644 --- a/activesupport/lib/active_support/core_ext/object/json.rb +++ b/activesupport/lib/active_support/core_ext/object/json.rb @@ -1,16 +1,18 @@ +# frozen_string_literal: true + # Hack to load json gem first so we can overwrite its to_json. require "json" require "bigdecimal" require "uri/generic" require "pathname" -require_relative "../big_decimal/conversions" # for #to_s -require_relative "../hash/except" -require_relative "../hash/slice" -require_relative "instance_variables" +require "active_support/core_ext/big_decimal/conversions" # for #to_s +require "active_support/core_ext/hash/except" +require "active_support/core_ext/hash/slice" +require "active_support/core_ext/object/instance_variables" require "time" -require_relative "../time/conversions" -require_relative "../date_time/conversions" -require_relative "../date/conversions" +require "active_support/core_ext/time/conversions" +require "active_support/core_ext/date_time/conversions" +require "active_support/core_ext/date/conversions" # The JSON gem adds a few modules to Ruby core classes containing :to_json definition, overwriting # their default behavior. That said, we need to define the basic to_json method in all of them, @@ -133,6 +135,12 @@ module Enumerable end end +class IO + def as_json(options = nil) #:nodoc: + to_s + end +end + class Range def as_json(options = nil) #:nodoc: to_s diff --git a/activesupport/lib/active_support/core_ext/object/to_param.rb b/activesupport/lib/active_support/core_ext/object/to_param.rb index d39727ce00..6d2bdd70f3 100644 --- a/activesupport/lib/active_support/core_ext/object/to_param.rb +++ b/activesupport/lib/active_support/core_ext/object/to_param.rb @@ -1 +1,3 @@ -require_relative "to_query" +# frozen_string_literal: true + +require "active_support/core_ext/object/to_query" diff --git a/activesupport/lib/active_support/core_ext/object/to_query.rb b/activesupport/lib/active_support/core_ext/object/to_query.rb index a3a3abacbb..abb461966a 100644 --- a/activesupport/lib/active_support/core_ext/object/to_query.rb +++ b/activesupport/lib/active_support/core_ext/object/to_query.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "cgi" class Object diff --git a/activesupport/lib/active_support/core_ext/object/try.rb b/activesupport/lib/active_support/core_ext/object/try.rb index b2be619b2d..c874691629 100644 --- a/activesupport/lib/active_support/core_ext/object/try.rb +++ b/activesupport/lib/active_support/core_ext/object/try.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "delegate" module ActiveSupport diff --git a/activesupport/lib/active_support/core_ext/object/with_options.rb b/activesupport/lib/active_support/core_ext/object/with_options.rb index 68a8da25ff..2838fd76be 100644 --- a/activesupport/lib/active_support/core_ext/object/with_options.rb +++ b/activesupport/lib/active_support/core_ext/object/with_options.rb @@ -1,4 +1,6 @@ -require_relative "../../option_merger" +# frozen_string_literal: true + +require "active_support/option_merger" class Object # An elegant way to factor duplication out of options passed to a series of @@ -60,7 +62,7 @@ class Object # # validates :content, length: { minimum: 50 }, if: -> { content.present? } # - # Hence the inherited default for `if` key is ignored. + # Hence the inherited default for +if+ key is ignored. # # NOTE: You cannot call class methods implicitly inside of with_options. # You can access these methods using the class name instead: diff --git a/activesupport/lib/active_support/core_ext/range.rb b/activesupport/lib/active_support/core_ext/range.rb index 3e17780b76..4074e91d17 100644 --- a/activesupport/lib/active_support/core_ext/range.rb +++ b/activesupport/lib/active_support/core_ext/range.rb @@ -1,4 +1,7 @@ -require_relative "range/conversions" -require_relative "range/include_range" -require_relative "range/overlaps" -require_relative "range/each" +# frozen_string_literal: true + +require "active_support/core_ext/range/conversions" +require "active_support/core_ext/range/include_range" +require "active_support/core_ext/range/include_time_with_zone" +require "active_support/core_ext/range/overlaps" +require "active_support/core_ext/range/each" diff --git a/activesupport/lib/active_support/core_ext/range/conversions.rb b/activesupport/lib/active_support/core_ext/range/conversions.rb index 69ea046cb6..8832fbcb3c 100644 --- a/activesupport/lib/active_support/core_ext/range/conversions.rb +++ b/activesupport/lib/active_support/core_ext/range/conversions.rb @@ -1,6 +1,14 @@ +# frozen_string_literal: true + module ActiveSupport::RangeWithFormat RANGE_FORMATS = { - db: Proc.new { |start, stop| "BETWEEN '#{start.to_s(:db)}' AND '#{stop.to_s(:db)}'" } + db: -> (start, stop) do + case start + when String then "BETWEEN '#{start}' AND '#{stop}'" + else + "BETWEEN '#{start.to_s(:db)}' AND '#{stop.to_s(:db)}'" + end + end } # Convert range to a formatted string. See RANGE_FORMATS for predefined formats. diff --git a/activesupport/lib/active_support/core_ext/range/each.rb b/activesupport/lib/active_support/core_ext/range/each.rb index dc6dad5ced..2f22cd0e92 100644 --- a/activesupport/lib/active_support/core_ext/range/each.rb +++ b/activesupport/lib/active_support/core_ext/range/each.rb @@ -1,3 +1,7 @@ +# frozen_string_literal: true + +require "active_support/time_with_zone" + module ActiveSupport module EachTimeWithZone #:nodoc: def each(&block) @@ -13,7 +17,7 @@ module ActiveSupport private def ensure_iteration_allowed - raise TypeError, "can't iterate from #{first.class}" if first.is_a?(Time) + raise TypeError, "can't iterate from #{first.class}" if first.is_a?(TimeWithZone) end end end diff --git a/activesupport/lib/active_support/core_ext/range/include_range.rb b/activesupport/lib/active_support/core_ext/range/include_range.rb index c69e1e3fb9..7ba1011921 100644 --- a/activesupport/lib/active_support/core_ext/range/include_range.rb +++ b/activesupport/lib/active_support/core_ext/range/include_range.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module ActiveSupport module IncludeWithRange #:nodoc: # Extends the default Range#include? to support range comparisons. diff --git a/activesupport/lib/active_support/core_ext/range/include_time_with_zone.rb b/activesupport/lib/active_support/core_ext/range/include_time_with_zone.rb new file mode 100644 index 0000000000..5f80acf68e --- /dev/null +++ b/activesupport/lib/active_support/core_ext/range/include_time_with_zone.rb @@ -0,0 +1,23 @@ +# frozen_string_literal: true + +require "active_support/time_with_zone" + +module ActiveSupport + module IncludeTimeWithZone #:nodoc: + # Extends the default Range#include? to support ActiveSupport::TimeWithZone. + # + # (1.hour.ago..1.hour.from_now).include?(Time.current) # => true + # + def include?(value) + if first.is_a?(TimeWithZone) + cover?(value) + elsif last.is_a?(TimeWithZone) + cover?(value) + else + super + end + end + end +end + +Range.prepend(ActiveSupport::IncludeTimeWithZone) diff --git a/activesupport/lib/active_support/core_ext/range/overlaps.rb b/activesupport/lib/active_support/core_ext/range/overlaps.rb index 603657c180..f753607f8b 100644 --- a/activesupport/lib/active_support/core_ext/range/overlaps.rb +++ b/activesupport/lib/active_support/core_ext/range/overlaps.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class Range # Compare two ranges and see if they overlap each other # (1..5).overlaps?(4..6) # => true diff --git a/activesupport/lib/active_support/core_ext/regexp.rb b/activesupport/lib/active_support/core_ext/regexp.rb index d77d01bf42..efbd708aee 100644 --- a/activesupport/lib/active_support/core_ext/regexp.rb +++ b/activesupport/lib/active_support/core_ext/regexp.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class Regexp #:nodoc: def multiline? options & MULTILINE == MULTILINE diff --git a/activesupport/lib/active_support/core_ext/securerandom.rb b/activesupport/lib/active_support/core_ext/securerandom.rb index a57685bea1..b4a491f5fd 100644 --- a/activesupport/lib/active_support/core_ext/securerandom.rb +++ b/activesupport/lib/active_support/core_ext/securerandom.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "securerandom" module SecureRandom diff --git a/activesupport/lib/active_support/core_ext/string.rb b/activesupport/lib/active_support/core_ext/string.rb index b16b35144e..757d15c51a 100644 --- a/activesupport/lib/active_support/core_ext/string.rb +++ b/activesupport/lib/active_support/core_ext/string.rb @@ -1,13 +1,15 @@ -require_relative "string/conversions" -require_relative "string/filters" -require_relative "string/multibyte" -require_relative "string/starts_ends_with" -require_relative "string/inflections" -require_relative "string/access" -require_relative "string/behavior" -require_relative "string/output_safety" -require_relative "string/exclude" -require_relative "string/strip" -require_relative "string/inquiry" -require_relative "string/indent" -require_relative "string/zones" +# frozen_string_literal: true + +require "active_support/core_ext/string/conversions" +require "active_support/core_ext/string/filters" +require "active_support/core_ext/string/multibyte" +require "active_support/core_ext/string/starts_ends_with" +require "active_support/core_ext/string/inflections" +require "active_support/core_ext/string/access" +require "active_support/core_ext/string/behavior" +require "active_support/core_ext/string/output_safety" +require "active_support/core_ext/string/exclude" +require "active_support/core_ext/string/strip" +require "active_support/core_ext/string/inquiry" +require "active_support/core_ext/string/indent" +require "active_support/core_ext/string/zones" diff --git a/activesupport/lib/active_support/core_ext/string/access.rb b/activesupport/lib/active_support/core_ext/string/access.rb index 6133826f37..58591bbaaf 100644 --- a/activesupport/lib/active_support/core_ext/string/access.rb +++ b/activesupport/lib/active_support/core_ext/string/access.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class String # If you pass a single integer, returns a substring of one character at that # position. The first character of the string is at position 0, the next at diff --git a/activesupport/lib/active_support/core_ext/string/behavior.rb b/activesupport/lib/active_support/core_ext/string/behavior.rb index 710f1f4670..35a5aa7840 100644 --- a/activesupport/lib/active_support/core_ext/string/behavior.rb +++ b/activesupport/lib/active_support/core_ext/string/behavior.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class String # Enables more predictable duck-typing on String-like classes. See <tt>Object#acts_like?</tt>. def acts_like_string? diff --git a/activesupport/lib/active_support/core_ext/string/conversions.rb b/activesupport/lib/active_support/core_ext/string/conversions.rb index 383d93e2cd..29a88b07ad 100644 --- a/activesupport/lib/active_support/core_ext/string/conversions.rb +++ b/activesupport/lib/active_support/core_ext/string/conversions.rb @@ -1,5 +1,7 @@ +# frozen_string_literal: true + require "date" -require_relative "../time/calculations" +require "active_support/core_ext/time/calculations" class String # Converts a string to a Time value. diff --git a/activesupport/lib/active_support/core_ext/string/exclude.rb b/activesupport/lib/active_support/core_ext/string/exclude.rb index 0ac684f6ee..8e462689f1 100644 --- a/activesupport/lib/active_support/core_ext/string/exclude.rb +++ b/activesupport/lib/active_support/core_ext/string/exclude.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class String # The inverse of <tt>String#include?</tt>. Returns true if the string # does not include the other string. diff --git a/activesupport/lib/active_support/core_ext/string/filters.rb b/activesupport/lib/active_support/core_ext/string/filters.rb index a9ec2eb842..66e721eea3 100644 --- a/activesupport/lib/active_support/core_ext/string/filters.rb +++ b/activesupport/lib/active_support/core_ext/string/filters.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class String # Returns the string, first removing all whitespace on both ends of # the string, and then changing remaining consecutive whitespace diff --git a/activesupport/lib/active_support/core_ext/string/indent.rb b/activesupport/lib/active_support/core_ext/string/indent.rb index d7b58301d3..af9d181487 100644 --- a/activesupport/lib/active_support/core_ext/string/indent.rb +++ b/activesupport/lib/active_support/core_ext/string/indent.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class String # Same as +indent+, except it indents the receiver in-place. # diff --git a/activesupport/lib/active_support/core_ext/string/inflections.rb b/activesupport/lib/active_support/core_ext/string/inflections.rb index 70c732ca44..8af301734a 100644 --- a/activesupport/lib/active_support/core_ext/string/inflections.rb +++ b/activesupport/lib/active_support/core_ext/string/inflections.rb @@ -1,5 +1,7 @@ -require_relative "../../inflector/methods" -require_relative "../../inflector/transliterate" +# frozen_string_literal: true + +require "active_support/inflector/methods" +require "active_support/inflector/transliterate" # String inflections define new methods on the String class to transform names for different purposes. # For instance, you can figure out the name of a table from the name of a class. @@ -92,6 +94,8 @@ class String ActiveSupport::Inflector.camelize(self, true) when :lower ActiveSupport::Inflector.camelize(self, false) + else + raise ArgumentError, "Invalid option, use either :upper or :lower." end end alias_method :camelcase, :camelize @@ -170,7 +174,7 @@ class String # <%= link_to(@person.name, person_path) %> # # => <a href="/person/1-donald-e-knuth">Donald E. Knuth</a> # - # To preserve the case of the characters in a string, use the `preserve_case` argument. + # To preserve the case of the characters in a string, use the +preserve_case+ argument. # # class Person # def to_param diff --git a/activesupport/lib/active_support/core_ext/string/inquiry.rb b/activesupport/lib/active_support/core_ext/string/inquiry.rb index dfa78b2ff8..a796d5fb4f 100644 --- a/activesupport/lib/active_support/core_ext/string/inquiry.rb +++ b/activesupport/lib/active_support/core_ext/string/inquiry.rb @@ -1,4 +1,6 @@ -require_relative "../../string_inquirer" +# frozen_string_literal: true + +require "active_support/string_inquirer" class String # Wraps the current string in the <tt>ActiveSupport::StringInquirer</tt> class, diff --git a/activesupport/lib/active_support/core_ext/string/multibyte.rb b/activesupport/lib/active_support/core_ext/string/multibyte.rb index 56a1cede1a..07c0d16398 100644 --- a/activesupport/lib/active_support/core_ext/string/multibyte.rb +++ b/activesupport/lib/active_support/core_ext/string/multibyte.rb @@ -1,4 +1,6 @@ -require_relative "../../multibyte" +# frozen_string_literal: true + +require "active_support/multibyte" class String # == Multibyte proxy @@ -14,6 +16,8 @@ class String # >> "lj".mb_chars.upcase.to_s # => "LJ" # + # NOTE: An above example is useful for pre Ruby 2.4. Ruby 2.4 supports Unicode case mappings. + # # == Method chaining # # All the methods on the Chars proxy which normally return a string will return a Chars object. This allows diff --git a/activesupport/lib/active_support/core_ext/string/output_safety.rb b/activesupport/lib/active_support/core_ext/string/output_safety.rb index 607870237b..f3bdc2977e 100644 --- a/activesupport/lib/active_support/core_ext/string/output_safety.rb +++ b/activesupport/lib/active_support/core_ext/string/output_safety.rb @@ -1,6 +1,9 @@ +# frozen_string_literal: true + require "erb" -require_relative "../kernel/singleton_class" -require_relative "../../multibyte/unicode" +require "active_support/core_ext/kernel/singleton_class" +require "active_support/core_ext/module/redefine_method" +require "active_support/multibyte/unicode" class ERB module Util @@ -12,22 +15,18 @@ class ERB # A utility method for escaping HTML tag characters. # This method is also aliased as <tt>h</tt>. # - # In your ERB templates, use this method to escape any unsafe content. For example: - # <%= h @person.name %> - # # puts html_escape('is a > 0 & a < 10?') # # => is a > 0 & a < 10? def html_escape(s) unwrapped_html_escape(s).html_safe end - # Aliasing twice issues a warning "discarding old...". Remove first to avoid it. - remove_method(:h) + silence_redefinition_of_method :h alias h html_escape module_function :h - singleton_class.send(:remove_method, :html_escape) + singleton_class.silence_redefinition_of_method :html_escape module_function :html_escape # HTML escapes strings but doesn't wrap them with an ActiveSupport::SafeBuffer. @@ -251,7 +250,7 @@ class String # Marks a string as trusted safe. It will be inserted into HTML with no # additional escaping performed. It is your responsibility to ensure that the # string contains no malicious content. This method is equivalent to the - # `raw` helper in views. It is recommended that you use `sanitize` instead of + # +raw+ helper in views. It is recommended that you use +sanitize+ instead of # this method. It should never be called on user input. def html_safe ActiveSupport::SafeBuffer.new(self) diff --git a/activesupport/lib/active_support/core_ext/string/starts_ends_with.rb b/activesupport/lib/active_support/core_ext/string/starts_ends_with.rb index 641acf62d0..919eb7a573 100644 --- a/activesupport/lib/active_support/core_ext/string/starts_ends_with.rb +++ b/activesupport/lib/active_support/core_ext/string/starts_ends_with.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class String alias_method :starts_with?, :start_with? alias_method :ends_with?, :end_with? diff --git a/activesupport/lib/active_support/core_ext/string/strip.rb b/activesupport/lib/active_support/core_ext/string/strip.rb index bb62e6c0ba..cc26274e4a 100644 --- a/activesupport/lib/active_support/core_ext/string/strip.rb +++ b/activesupport/lib/active_support/core_ext/string/strip.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class String # Strips indentation in heredocs. # diff --git a/activesupport/lib/active_support/core_ext/string/zones.rb b/activesupport/lib/active_support/core_ext/string/zones.rb index d8d22a6799..55dc231464 100644 --- a/activesupport/lib/active_support/core_ext/string/zones.rb +++ b/activesupport/lib/active_support/core_ext/string/zones.rb @@ -1,5 +1,7 @@ -require_relative "conversions" -require_relative "../time/zones" +# frozen_string_literal: true + +require "active_support/core_ext/string/conversions" +require "active_support/core_ext/time/zones" class String # Converts String to a TimeWithZone in the current zone if Time.zone or Time.zone_default diff --git a/activesupport/lib/active_support/core_ext/time.rb b/activesupport/lib/active_support/core_ext/time.rb index 19d4d91dac..c809def05f 100644 --- a/activesupport/lib/active_support/core_ext/time.rb +++ b/activesupport/lib/active_support/core_ext/time.rb @@ -1,5 +1,7 @@ -require_relative "time/acts_like" -require_relative "time/calculations" -require_relative "time/compatibility" -require_relative "time/conversions" -require_relative "time/zones" +# frozen_string_literal: true + +require "active_support/core_ext/time/acts_like" +require "active_support/core_ext/time/calculations" +require "active_support/core_ext/time/compatibility" +require "active_support/core_ext/time/conversions" +require "active_support/core_ext/time/zones" diff --git a/activesupport/lib/active_support/core_ext/time/acts_like.rb b/activesupport/lib/active_support/core_ext/time/acts_like.rb index 08756a2dae..8572b49639 100644 --- a/activesupport/lib/active_support/core_ext/time/acts_like.rb +++ b/activesupport/lib/active_support/core_ext/time/acts_like.rb @@ -1,4 +1,6 @@ -require_relative "../object/acts_like" +# frozen_string_literal: true + +require "active_support/core_ext/object/acts_like" class Time # Duck-types as a Time-like class. See Object#acts_like?. diff --git a/activesupport/lib/active_support/core_ext/time/calculations.rb b/activesupport/lib/active_support/core_ext/time/calculations.rb index 9ba6bf8fa1..120768dec5 100644 --- a/activesupport/lib/active_support/core_ext/time/calculations.rb +++ b/activesupport/lib/active_support/core_ext/time/calculations.rb @@ -1,9 +1,11 @@ -require_relative "../../duration" -require_relative "conversions" -require_relative "../../time_with_zone" -require_relative "zones" -require_relative "../date_and_time/calculations" -require_relative "../date/calculations" +# frozen_string_literal: true + +require "active_support/duration" +require "active_support/core_ext/time/conversions" +require "active_support/time_with_zone" +require "active_support/core_ext/time/zones" +require "active_support/core_ext/date_and_time/calculations" +require "active_support/core_ext/date/calculations" class Time include DateAndTime::Calculations diff --git a/activesupport/lib/active_support/core_ext/time/compatibility.rb b/activesupport/lib/active_support/core_ext/time/compatibility.rb index a554e71b74..495e4f307b 100644 --- a/activesupport/lib/active_support/core_ext/time/compatibility.rb +++ b/activesupport/lib/active_support/core_ext/time/compatibility.rb @@ -1,10 +1,12 @@ -require_relative "../date_and_time/compatibility" -require_relative "../module/remove_method" +# frozen_string_literal: true + +require "active_support/core_ext/date_and_time/compatibility" +require "active_support/core_ext/module/redefine_method" class Time include DateAndTime::Compatibility - remove_possible_method :to_time + silence_redefinition_of_method :to_time # Either return +self+ or the time in the local system timezone depending # on the setting of +ActiveSupport.to_time_preserves_timezone+. diff --git a/activesupport/lib/active_support/core_ext/time/conversions.rb b/activesupport/lib/active_support/core_ext/time/conversions.rb index 0dbce99ccb..345cb2832c 100644 --- a/activesupport/lib/active_support/core_ext/time/conversions.rb +++ b/activesupport/lib/active_support/core_ext/time/conversions.rb @@ -1,5 +1,7 @@ -require_relative "../../inflector/methods" -require_relative "../../values/time_zone" +# frozen_string_literal: true + +require "active_support/inflector/methods" +require "active_support/values/time_zone" class Time DATE_FORMATS = { diff --git a/activesupport/lib/active_support/core_ext/time/zones.rb b/activesupport/lib/active_support/core_ext/time/zones.rb index ba8b5b73f8..a5588fd488 100644 --- a/activesupport/lib/active_support/core_ext/time/zones.rb +++ b/activesupport/lib/active_support/core_ext/time/zones.rb @@ -1,6 +1,8 @@ -require_relative "../../time_with_zone" -require_relative "acts_like" -require_relative "../date_and_time/zones" +# frozen_string_literal: true + +require "active_support/time_with_zone" +require "active_support/core_ext/time/acts_like" +require "active_support/core_ext/date_and_time/zones" class Time include DateAndTime::Zones @@ -53,10 +55,10 @@ class Time # end # end # - # NOTE: This won't affect any <tt>ActiveSupport::TimeWithZone</tt> - # objects that have already been created, e.g. any model timestamp - # attributes that have been read before the block will remain in - # the application's default timezone. + # NOTE: This won't affect any <tt>ActiveSupport::TimeWithZone</tt> + # objects that have already been created, e.g. any model timestamp + # attributes that have been read before the block will remain in + # the application's default timezone. def use_zone(time_zone) new_zone = find_zone!(time_zone) begin diff --git a/activesupport/lib/active_support/core_ext/uri.rb b/activesupport/lib/active_support/core_ext/uri.rb index 342a5fcd52..c93c0b5c2d 100644 --- a/activesupport/lib/active_support/core_ext/uri.rb +++ b/activesupport/lib/active_support/core_ext/uri.rb @@ -1,10 +1,13 @@ +# frozen_string_literal: true + require "uri" str = "\xE6\x97\xA5\xE6\x9C\xAC\xE8\xAA\x9E" # Ni-ho-nn-go in UTF-8, means Japanese. parser = URI::Parser.new unless str == parser.unescape(parser.escape(str)) + require "active_support/core_ext/module/redefine_method" URI::Parser.class_eval do - remove_method :unescape + silence_redefinition_of_method :unescape def unescape(str, escaped = /%[a-fA-F\d]{2}/) # TODO: Are we actually sure that ASCII == UTF-8? # YK: My initial experiments say yes, but let's be sure please diff --git a/activesupport/lib/active_support/current_attributes.rb b/activesupport/lib/active_support/current_attributes.rb index 872b0663c7..4e6d8e4585 100644 --- a/activesupport/lib/active_support/current_attributes.rb +++ b/activesupport/lib/active_support/current_attributes.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module ActiveSupport # Abstract super class that provides a thread-isolated attributes singleton, which resets automatically # before and after each request. This allows you to keep all the per-request attributes easily @@ -31,7 +33,7 @@ module ActiveSupport # # private # def authenticate - # if authenticated_user = User.find_by(id: cookies.signed[:user_id]) + # if authenticated_user = User.find_by(id: cookies.encrypted[:user_id]) # Current.user = authenticated_user # else # redirect_to new_session_url diff --git a/activesupport/lib/active_support/dependencies.rb b/activesupport/lib/active_support/dependencies.rb index 05b9b5b211..82c10b3079 100644 --- a/activesupport/lib/active_support/dependencies.rb +++ b/activesupport/lib/active_support/dependencies.rb @@ -1,18 +1,20 @@ +# frozen_string_literal: true + require "set" require "thread" require "concurrent/map" require "pathname" -require_relative "core_ext/module/aliasing" -require_relative "core_ext/module/attribute_accessors" -require_relative "core_ext/module/introspection" -require_relative "core_ext/module/anonymous" -require_relative "core_ext/object/blank" -require_relative "core_ext/kernel/reporting" -require_relative "core_ext/load_error" -require_relative "core_ext/name_error" -require_relative "core_ext/string/starts_ends_with" -require_relative "dependencies/interlock" -require_relative "inflector" +require "active_support/core_ext/module/aliasing" +require "active_support/core_ext/module/attribute_accessors" +require "active_support/core_ext/module/introspection" +require "active_support/core_ext/module/anonymous" +require "active_support/core_ext/object/blank" +require "active_support/core_ext/kernel/reporting" +require "active_support/core_ext/load_error" +require "active_support/core_ext/name_error" +require "active_support/core_ext/string/starts_ends_with" +require "active_support/dependencies/interlock" +require "active_support/inflector" module ActiveSupport #:nodoc: module Dependencies #:nodoc: @@ -83,7 +85,7 @@ module ActiveSupport #:nodoc: # handles the new constants. # # If child.rb is being autoloaded, its constants will be added to - # autoloaded_constants. If it was being `require`d, they will be discarded. + # autoloaded_constants. If it was being required, they will be discarded. # # This is handled by walking back up the watch stack and adding the constants # found by child.rb to the list of original constants in parent.rb. @@ -613,7 +615,7 @@ module ActiveSupport #:nodoc: return false if desc.is_a?(Module) && desc.anonymous? name = to_constant_name desc return false unless qualified_const_defined?(name) - return autoloaded_constants.include?(name) + autoloaded_constants.include?(name) end # Will the provided constant descriptor be unloaded? diff --git a/activesupport/lib/active_support/dependencies/autoload.rb b/activesupport/lib/active_support/dependencies/autoload.rb index 9e4d3b783b..1cee85d98f 100644 --- a/activesupport/lib/active_support/dependencies/autoload.rb +++ b/activesupport/lib/active_support/dependencies/autoload.rb @@ -1,4 +1,6 @@ -require_relative "../inflector/methods" +# frozen_string_literal: true + +require "active_support/inflector/methods" module ActiveSupport # Autoload and eager load conveniences for your library. diff --git a/activesupport/lib/active_support/dependencies/interlock.rb b/activesupport/lib/active_support/dependencies/interlock.rb index b88cf08dd2..948be75638 100644 --- a/activesupport/lib/active_support/dependencies/interlock.rb +++ b/activesupport/lib/active_support/dependencies/interlock.rb @@ -1,4 +1,6 @@ -require_relative "../concurrency/share_lock" +# frozen_string_literal: true + +require "active_support/concurrency/share_lock" module ActiveSupport #:nodoc: module Dependencies #:nodoc: diff --git a/activesupport/lib/active_support/deprecation.rb b/activesupport/lib/active_support/deprecation.rb index eaaf198ccb..a1ad2ca465 100644 --- a/activesupport/lib/active_support/deprecation.rb +++ b/activesupport/lib/active_support/deprecation.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "singleton" module ActiveSupport @@ -12,13 +14,13 @@ module ActiveSupport # a circular require warning for active_support/deprecation.rb. # # So, we define the constant first, and load dependencies later. - require_relative "deprecation/instance_delegator" - require_relative "deprecation/behaviors" - require_relative "deprecation/reporting" - require_relative "deprecation/constant_accessor" - require_relative "deprecation/method_wrappers" - require_relative "deprecation/proxy_wrappers" - require_relative "core_ext/module/deprecation" + require "active_support/deprecation/instance_delegator" + require "active_support/deprecation/behaviors" + require "active_support/deprecation/reporting" + require "active_support/deprecation/constant_accessor" + require "active_support/deprecation/method_wrappers" + require "active_support/deprecation/proxy_wrappers" + require "active_support/core_ext/module/deprecation" include Singleton include InstanceDelegator diff --git a/activesupport/lib/active_support/deprecation/behaviors.rb b/activesupport/lib/active_support/deprecation/behaviors.rb index 409f4cf6a6..581db5f449 100644 --- a/activesupport/lib/active_support/deprecation/behaviors.rb +++ b/activesupport/lib/active_support/deprecation/behaviors.rb @@ -1,4 +1,6 @@ -require_relative "../notifications" +# frozen_string_literal: true + +require "active_support/notifications" module ActiveSupport # Raised when <tt>ActiveSupport::Deprecation::Behavior#behavior</tt> is set with <tt>:raise</tt>. @@ -25,7 +27,7 @@ module ActiveSupport if defined?(Rails.logger) && Rails.logger Rails.logger else - require_relative "../logger" + require "active_support/logger" ActiveSupport::Logger.new($stderr) end logger.warn message diff --git a/activesupport/lib/active_support/deprecation/constant_accessor.rb b/activesupport/lib/active_support/deprecation/constant_accessor.rb index 895b23e8ef..1ed0015812 100644 --- a/activesupport/lib/active_support/deprecation/constant_accessor.rb +++ b/activesupport/lib/active_support/deprecation/constant_accessor.rb @@ -1,4 +1,4 @@ -require_relative "../inflector/methods" +# frozen_string_literal: true module ActiveSupport class Deprecation @@ -15,7 +15,7 @@ module ActiveSupport # # PLANETS = %w(mercury venus earth mars jupiter saturn uranus neptune pluto) # - # (In a later update, the original implementation of `PLANETS` has been removed.) + # # (In a later update, the original implementation of `PLANETS` has been removed.) # # PLANETS_POST_2006 = %w(mercury venus earth mars jupiter saturn uranus neptune) # include ActiveSupport::Deprecation::DeprecatedConstantAccessor @@ -27,6 +27,8 @@ module ActiveSupport # ["Mercury", "Venus", "Earth", "Mars", "Jupiter", "Saturn", "Uranus", "Neptune"] module DeprecatedConstantAccessor def self.included(base) + require "active_support/inflector/methods" + extension = Module.new do def const_missing(missing_const_name) if class_variable_defined?(:@@_deprecated_constants) diff --git a/activesupport/lib/active_support/deprecation/instance_delegator.rb b/activesupport/lib/active_support/deprecation/instance_delegator.rb index 23eac0e5d3..8beda373a2 100644 --- a/activesupport/lib/active_support/deprecation/instance_delegator.rb +++ b/activesupport/lib/active_support/deprecation/instance_delegator.rb @@ -1,5 +1,7 @@ -require_relative "../core_ext/kernel/singleton_class" -require_relative "../core_ext/module/delegation" +# frozen_string_literal: true + +require "active_support/core_ext/kernel/singleton_class" +require "active_support/core_ext/module/delegation" module ActiveSupport class Deprecation diff --git a/activesupport/lib/active_support/deprecation/method_wrappers.rb b/activesupport/lib/active_support/deprecation/method_wrappers.rb index ed41e9aaa4..5be893d281 100644 --- a/activesupport/lib/active_support/deprecation/method_wrappers.rb +++ b/activesupport/lib/active_support/deprecation/method_wrappers.rb @@ -1,14 +1,14 @@ -require_relative "../core_ext/module/aliasing" -require_relative "../core_ext/array/extract_options" +# frozen_string_literal: true + +require "active_support/core_ext/module/aliasing" +require "active_support/core_ext/array/extract_options" module ActiveSupport class Deprecation module MethodWrapper # Declare that a method has been deprecated. # - # module Fred - # extend self - # + # class Fred # def aaa; end # def bbb; end # def ccc; end @@ -20,15 +20,15 @@ module ActiveSupport # ActiveSupport::Deprecation.deprecate_methods(Fred, :aaa, bbb: :zzz, ccc: 'use Bar#ccc instead') # # => Fred # - # Fred.aaa + # Fred.new.aaa # # DEPRECATION WARNING: aaa is deprecated and will be removed from Rails 5.1. (called from irb_binding at (irb):10) # # => nil # - # Fred.bbb + # Fred.new.bbb # # DEPRECATION WARNING: bbb is deprecated and will be removed from Rails 5.1 (use zzz instead). (called from irb_binding at (irb):11) # # => nil # - # Fred.ccc + # Fred.new.ccc # # DEPRECATION WARNING: ccc is deprecated and will be removed from Rails 5.1 (use Bar#ccc instead). (called from irb_binding at (irb):12) # # => nil # @@ -37,7 +37,7 @@ module ActiveSupport # ActiveSupport::Deprecation.deprecate_methods(Fred, ddd: :zzz, deprecator: custom_deprecator) # # => [:ddd] # - # Fred.ddd + # Fred.new.ddd # DEPRECATION WARNING: ddd is deprecated and will be removed from MyGem next-release (use zzz instead). (called from irb_binding at (irb):15) # # => nil # @@ -46,7 +46,7 @@ module ActiveSupport # custom_deprecator.deprecate_methods(Fred, eee: :zzz) # # => [:eee] # - # Fred.eee + # Fred.new.eee # DEPRECATION WARNING: eee is deprecated and will be removed from MyGem next-release (use zzz instead). (called from irb_binding at (irb):18) # # => nil def deprecate_methods(target_module, *method_names) @@ -60,6 +60,13 @@ module ActiveSupport deprecator.deprecation_warning(method_name, options[method_name]) super(*args, &block) end + + case + when target_module.protected_method_defined?(method_name) + protected method_name + when target_module.private_method_defined?(method_name) + private method_name + end end end diff --git a/activesupport/lib/active_support/deprecation/proxy_wrappers.rb b/activesupport/lib/active_support/deprecation/proxy_wrappers.rb index 64aaef3e43..896c0d2d8e 100644 --- a/activesupport/lib/active_support/deprecation/proxy_wrappers.rb +++ b/activesupport/lib/active_support/deprecation/proxy_wrappers.rb @@ -1,5 +1,6 @@ -require_relative "../inflector/methods" -require_relative "../core_ext/regexp" +# frozen_string_literal: true + +require "active_support/core_ext/regexp" module ActiveSupport class Deprecation @@ -112,7 +113,7 @@ module ActiveSupport # # PLANETS = %w(mercury venus earth mars jupiter saturn uranus neptune pluto) # - # (In a later update, the original implementation of `PLANETS` has been removed.) + # # (In a later update, the original implementation of `PLANETS` has been removed.) # # PLANETS_POST_2006 = %w(mercury venus earth mars jupiter saturn uranus neptune) # PLANETS = ActiveSupport::Deprecation::DeprecatedConstantProxy.new('PLANETS', 'PLANETS_POST_2006') @@ -123,6 +124,8 @@ module ActiveSupport # ["Mercury", "Venus", "Earth", "Mars", "Jupiter", "Saturn", "Uranus", "Neptune"] class DeprecatedConstantProxy < DeprecationProxy def initialize(old_const, new_const, deprecator = ActiveSupport::Deprecation.instance, message: "#{old_const} is deprecated! Use #{new_const} instead.") + require "active_support/inflector/methods" + @old_const = old_const @new_const = new_const @deprecator = deprecator diff --git a/activesupport/lib/active_support/deprecation/reporting.rb b/activesupport/lib/active_support/deprecation/reporting.rb index 140bdccbb3..242e21b782 100644 --- a/activesupport/lib/active_support/deprecation/reporting.rb +++ b/activesupport/lib/active_support/deprecation/reporting.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "rbconfig" module ActiveSupport diff --git a/activesupport/lib/active_support/descendants_tracker.rb b/activesupport/lib/active_support/descendants_tracker.rb index 27861e01d0..a4cee788b6 100644 --- a/activesupport/lib/active_support/descendants_tracker.rb +++ b/activesupport/lib/active_support/descendants_tracker.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module ActiveSupport # This module provides an internal implementation to track descendants # which is faster than iterating through ObjectSpace. diff --git a/activesupport/lib/active_support/digest.rb b/activesupport/lib/active_support/digest.rb new file mode 100644 index 0000000000..fba10fbdcf --- /dev/null +++ b/activesupport/lib/active_support/digest.rb @@ -0,0 +1,20 @@ +# frozen_string_literal: true + +module ActiveSupport + class Digest #:nodoc: + class <<self + def hash_digest_class + @hash_digest_class ||= ::Digest::MD5 + end + + def hash_digest_class=(klass) + raise ArgumentError, "#{klass} is expected to implement hexdigest class method" unless klass.respond_to?(:hexdigest) + @hash_digest_class = klass + end + + def hexdigest(arg) + hash_digest_class.hexdigest(arg)[0...32] + end + end + end +end diff --git a/activesupport/lib/active_support/duration.rb b/activesupport/lib/active_support/duration.rb index 0ad591e683..fe1058762b 100644 --- a/activesupport/lib/active_support/duration.rb +++ b/activesupport/lib/active_support/duration.rb @@ -1,8 +1,10 @@ -require_relative "core_ext/array/conversions" -require_relative "core_ext/module/delegation" -require_relative "core_ext/object/acts_like" -require_relative "core_ext/string/filters" -require_relative "deprecation" +# frozen_string_literal: true + +require "active_support/core_ext/array/conversions" +require "active_support/core_ext/module/delegation" +require "active_support/core_ext/object/acts_like" +require "active_support/core_ext/string/filters" +require "active_support/deprecation" module ActiveSupport # Provides accurate date and time measurements using Date#advance and @@ -74,15 +76,20 @@ module ActiveSupport def /(other) if Duration === other - new_parts = other.parts.map { |part, other_value| [part, value / other_value] }.to_h - new_value = new_parts.inject(0) { |total, (part, value)| total + value * Duration::PARTS_IN_SECONDS[part] } - - Duration.new(new_value, new_parts) + value / other.value else calculate(:/, other) end end + def %(other) + if Duration === other + Duration.build(value % other.value) + else + calculate(:%, other) + end + end + private def calculate(op, other) if Scalar === other @@ -116,6 +123,8 @@ module ActiveSupport years: SECONDS_PER_YEAR }.freeze + PARTS = [:years, :months, :weeks, :days, :hours, :minutes, :seconds].freeze + attr_accessor :value, :parts autoload :ISO8601Parser, "active_support/duration/iso8601_parser" @@ -124,7 +133,7 @@ module ActiveSupport class << self # Creates a new Duration from string formatted according to ISO 8601 Duration. # - # See {ISO 8601}[http://en.wikipedia.org/wiki/ISO_8601#Durations] for more information. + # See {ISO 8601}[https://en.wikipedia.org/wiki/ISO_8601#Durations] for more information. # This method allows negative parts to be present in pattern. # If invalid string is provided, it will raise +ActiveSupport::Duration::ISO8601Parser::ParsingError+. def parse(iso8601duration) @@ -166,6 +175,29 @@ module ActiveSupport new(value * SECONDS_PER_YEAR, [[:years, value]]) end + # Creates a new Duration from a seconds value that is converted + # to the individual parts: + # + # ActiveSupport::Duration.build(31556952).parts # => {:years=>1} + # ActiveSupport::Duration.build(2716146).parts # => {:months=>1, :days=>1} + # + def build(value) + parts = {} + remainder = value.to_f + + PARTS.each do |part| + unless part == :seconds + part_in_seconds = PARTS_IN_SECONDS[part] + parts[part] = remainder.div(part_in_seconds) + remainder = (remainder % part_in_seconds).round(9) + end + end + + parts[:seconds] = remainder + + new(value, parts) + end + private def calculate_total_seconds(parts) @@ -178,6 +210,7 @@ module ActiveSupport def initialize(value, parts) #:nodoc: @value, @parts = value, parts.to_h @parts.default = 0 + @parts.reject! { |k, v| v.zero? } end def coerce(other) #:nodoc: @@ -232,8 +265,10 @@ module ActiveSupport # Divides this Duration by a Numeric and returns a new Duration. def /(other) - if Scalar === other || Duration === other + if Scalar === other Duration.new(value / other.value, parts.map { |type, number| [type, number / other.value] }) + elsif Duration === other + value / other.value elsif Numeric === other Duration.new(value / other, parts.map { |type, number| [type, number / other] }) else @@ -241,6 +276,18 @@ module ActiveSupport end end + # Returns the modulo of this Duration by another Duration or Numeric. + # Numeric values are treated as seconds. + def %(other) + if Duration === other || Scalar === other + Duration.build(value % other.value) + elsif Numeric === other + Duration.build(value % other) + else + raise_type_error(other) + end + end + def -@ #:nodoc: Duration.new(-value, parts.map { |type, number| [type, -number] }) end @@ -323,9 +370,11 @@ module ActiveSupport alias :before :ago def inspect #:nodoc: + return "0 seconds" if parts.empty? + parts. reduce(::Hash.new(0)) { |h, (l, r)| h[l] += r; h }. - sort_by { |unit, _ | [:years, :months, :weeks, :days, :hours, :minutes, :seconds].index(unit) }. + sort_by { |unit, _ | PARTS.index(unit) }. map { |unit, val| "#{val} #{val == 1 ? unit.to_s.chop : unit.to_s}" }. to_sentence(locale: ::I18n.default_locale) end diff --git a/activesupport/lib/active_support/duration/iso8601_parser.rb b/activesupport/lib/active_support/duration/iso8601_parser.rb index 78a00b5e4f..1847eeaa86 100644 --- a/activesupport/lib/active_support/duration/iso8601_parser.rb +++ b/activesupport/lib/active_support/duration/iso8601_parser.rb @@ -1,11 +1,13 @@ +# frozen_string_literal: true + require "strscan" -require_relative "../core_ext/regexp" +require "active_support/core_ext/regexp" module ActiveSupport class Duration # Parses a string formatted according to ISO 8601 Duration into the hash. # - # See {ISO 8601}[http://en.wikipedia.org/wiki/ISO_8601#Durations] for more information. + # See {ISO 8601}[https://en.wikipedia.org/wiki/ISO_8601#Durations] for more information. # # This parser allows negative parts to be present in pattern. class ISO8601Parser # :nodoc: @@ -116,7 +118,7 @@ module ActiveSupport raise_parsing_error "(only last part can be fractional)" end - return true + true end end end diff --git a/activesupport/lib/active_support/duration/iso8601_serializer.rb b/activesupport/lib/active_support/duration/iso8601_serializer.rb index 83c3a46692..bb177ae5b7 100644 --- a/activesupport/lib/active_support/duration/iso8601_serializer.rb +++ b/activesupport/lib/active_support/duration/iso8601_serializer.rb @@ -1,5 +1,7 @@ -require_relative "../core_ext/object/blank" -require_relative "../core_ext/hash/transform_values" +# frozen_string_literal: true + +require "active_support/core_ext/object/blank" +require "active_support/core_ext/hash/transform_values" module ActiveSupport class Duration diff --git a/activesupport/lib/active_support/encrypted_configuration.rb b/activesupport/lib/active_support/encrypted_configuration.rb new file mode 100644 index 0000000000..dab953d5d5 --- /dev/null +++ b/activesupport/lib/active_support/encrypted_configuration.rb @@ -0,0 +1,49 @@ +# frozen_string_literal: true + +require "yaml" +require "active_support/encrypted_file" +require "active_support/ordered_options" +require "active_support/core_ext/object/inclusion" +require "active_support/core_ext/module/delegation" + +module ActiveSupport + class EncryptedConfiguration < EncryptedFile + delegate :[], :fetch, to: :config + delegate_missing_to :options + + def initialize(config_path:, key_path:, env_key:, raise_if_missing_key:) + super content_path: config_path, key_path: key_path, + env_key: env_key, raise_if_missing_key: raise_if_missing_key + end + + # Allow a config to be started without a file present + def read + super + rescue ActiveSupport::EncryptedFile::MissingContentError + "" + end + + def write(contents) + deserialize(contents) + + super + end + + def config + @config ||= deserialize(read).deep_symbolize_keys + end + + private + def options + @options ||= ActiveSupport::InheritableOptions.new(config) + end + + def serialize(config) + config.present? ? YAML.dump(config) : "" + end + + def deserialize(config) + config.present? ? YAML.load(config, content_path) : {} + end + end +end diff --git a/activesupport/lib/active_support/encrypted_file.rb b/activesupport/lib/active_support/encrypted_file.rb new file mode 100644 index 0000000000..671b6b6a69 --- /dev/null +++ b/activesupport/lib/active_support/encrypted_file.rb @@ -0,0 +1,99 @@ +# frozen_string_literal: true + +require "pathname" +require "active_support/message_encryptor" + +module ActiveSupport + class EncryptedFile + class MissingContentError < RuntimeError + def initialize(content_path) + super "Missing encrypted content file in #{content_path}." + end + end + + class MissingKeyError < RuntimeError + def initialize(key_path:, env_key:) + super \ + "Missing encryption key to decrypt file with. " + + "Ask your team for your master key and write it to #{key_path} or put it in the ENV['#{env_key}']." + end + end + + CIPHER = "aes-128-gcm" + + def self.generate_key + SecureRandom.hex(ActiveSupport::MessageEncryptor.key_len(CIPHER)) + end + + + attr_reader :content_path, :key_path, :env_key, :raise_if_missing_key + + def initialize(content_path:, key_path:, env_key:, raise_if_missing_key:) + @content_path, @key_path = Pathname.new(content_path), Pathname.new(key_path) + @env_key, @raise_if_missing_key = env_key, raise_if_missing_key + end + + def key + read_env_key || read_key_file || handle_missing_key + end + + def read + if !key.nil? && content_path.exist? + decrypt content_path.binread + else + raise MissingContentError, content_path + end + end + + def write(contents) + IO.binwrite "#{content_path}.tmp", encrypt(contents) + FileUtils.mv "#{content_path}.tmp", content_path + end + + def change(&block) + writing read, &block + end + + + private + def writing(contents) + tmp_file = "#{content_path.basename}.#{Process.pid}" + tmp_path = Pathname.new File.join(Dir.tmpdir, tmp_file) + tmp_path.binwrite contents + + yield tmp_path + + updated_contents = tmp_path.binread + + write(updated_contents) if updated_contents != contents + ensure + FileUtils.rm(tmp_path) if tmp_path.exist? + end + + + def encrypt(contents) + encryptor.encrypt_and_sign contents + end + + def decrypt(contents) + encryptor.decrypt_and_verify contents + end + + def encryptor + @encryptor ||= ActiveSupport::MessageEncryptor.new([ key ].pack("H*"), cipher: CIPHER) + end + + + def read_env_key + ENV[env_key] + end + + def read_key_file + key_path.binread.strip if key_path.exist? + end + + def handle_missing_key + raise MissingKeyError, key_path: key_path, env_key: env_key if raise_if_missing_key + end + end +end diff --git a/activesupport/lib/active_support/evented_file_update_checker.rb b/activesupport/lib/active_support/evented_file_update_checker.rb index f59f5d17dc..97e982eb05 100644 --- a/activesupport/lib/active_support/evented_file_update_checker.rb +++ b/activesupport/lib/active_support/evented_file_update_checker.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "set" require "pathname" require "concurrent/atomic/atomic_boolean" diff --git a/activesupport/lib/active_support/execution_wrapper.rb b/activesupport/lib/active_support/execution_wrapper.rb index 3513e9023c..f48c586cad 100644 --- a/activesupport/lib/active_support/execution_wrapper.rb +++ b/activesupport/lib/active_support/execution_wrapper.rb @@ -1,4 +1,6 @@ -require_relative "callbacks" +# frozen_string_literal: true + +require "active_support/callbacks" module ActiveSupport class ExecutionWrapper diff --git a/activesupport/lib/active_support/executor.rb b/activesupport/lib/active_support/executor.rb index 4a618d9fa2..ce391b07ec 100644 --- a/activesupport/lib/active_support/executor.rb +++ b/activesupport/lib/active_support/executor.rb @@ -1,4 +1,6 @@ -require_relative "execution_wrapper" +# frozen_string_literal: true + +require "active_support/execution_wrapper" module ActiveSupport class Executor < ExecutionWrapper diff --git a/activesupport/lib/active_support/file_update_checker.rb b/activesupport/lib/active_support/file_update_checker.rb index b9d8740569..1a0bb10815 100644 --- a/activesupport/lib/active_support/file_update_checker.rb +++ b/activesupport/lib/active_support/file_update_checker.rb @@ -1,4 +1,6 @@ -require_relative "core_ext/time/calculations" +# frozen_string_literal: true + +require "active_support/core_ext/time/calculations" module ActiveSupport # FileUpdateChecker specifies the API used by Rails to watch files diff --git a/activesupport/lib/active_support/gem_version.rb b/activesupport/lib/active_support/gem_version.rb index 371a39a5e6..1e09adbb52 100644 --- a/activesupport/lib/active_support/gem_version.rb +++ b/activesupport/lib/active_support/gem_version.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module ActiveSupport # Returns the version of the currently loaded Active Support as a <tt>Gem::Version</tt>. def self.gem_version @@ -8,7 +10,7 @@ module ActiveSupport MAJOR = 5 MINOR = 2 TINY = 0 - PRE = "alpha" + PRE = "beta2" STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".") end diff --git a/activesupport/lib/active_support/gzip.rb b/activesupport/lib/active_support/gzip.rb index 95a86889ec..7ffa6d90a2 100644 --- a/activesupport/lib/active_support/gzip.rb +++ b/activesupport/lib/active_support/gzip.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "zlib" require "stringio" diff --git a/activesupport/lib/active_support/hash_with_indifferent_access.rb b/activesupport/lib/active_support/hash_with_indifferent_access.rb index 6c98960292..2e2ed8a25d 100644 --- a/activesupport/lib/active_support/hash_with_indifferent_access.rb +++ b/activesupport/lib/active_support/hash_with_indifferent_access.rb @@ -1,5 +1,7 @@ -require_relative "core_ext/hash/keys" -require_relative "core_ext/hash/reverse_merge" +# frozen_string_literal: true + +require "active_support/core_ext/hash/keys" +require "active_support/core_ext/hash/reverse_merge" module ActiveSupport # Implements a hash where keys <tt>:foo</tt> and <tt>"foo"</tt> are considered @@ -74,16 +76,6 @@ module ActiveSupport end end - def default(*args) - arg_key = args.first - - if include?(key = convert_key(arg_key)) - self[key] - else - super - end - end - def self.[](*args) new.merge!(Hash[*args]) end @@ -185,6 +177,36 @@ module ActiveSupport super(convert_key(key), *extras) end + if Hash.new.respond_to?(:dig) + # Same as <tt>Hash#dig</tt> where the key passed as argument can be + # either a string or a symbol: + # + # counters = ActiveSupport::HashWithIndifferentAccess.new + # counters[:foo] = { bar: 1 } + # + # counters.dig('foo', 'bar') # => 1 + # counters.dig(:foo, :bar) # => 1 + # counters.dig(:zoo) # => nil + def dig(*args) + args[0] = convert_key(args[0]) if args.size > 0 + super(*args) + end + end + + # Same as <tt>Hash#default</tt> where the key passed as argument can be + # either a string or a symbol: + # + # hash = ActiveSupport::HashWithIndifferentAccess.new(1) + # hash.default # => 1 + # + # hash = ActiveSupport::HashWithIndifferentAccess.new { |hash, key| key } + # hash.default # => nil + # hash.default('foo') # => 'foo' + # hash.default(:foo) # => 'foo' + def default(*args) + super(*args.map { |arg| convert_key(arg) }) + end + # Returns an array of the values at the specified indices: # # hash = ActiveSupport::HashWithIndifferentAccess.new @@ -214,7 +236,7 @@ module ActiveSupport # dup = hash.dup # dup[:a][:c] = 'c' # - # hash[:a][:c] # => nil + # hash[:a][:c] # => "c" # dup[:a][:c] # => "c" def dup self.class.new(self).tap do |new_hash| @@ -242,7 +264,7 @@ module ActiveSupport # Same semantics as +reverse_merge+ but modifies the receiver in-place. def reverse_merge!(other_hash) - replace(reverse_merge(other_hash)) + super(self.class.new(other_hash)) end alias_method :with_defaults!, :reverse_merge! @@ -284,6 +306,21 @@ module ActiveSupport dup.tap { |hash| hash.transform_values!(*args, &block) } end + def transform_keys(*args, &block) + return to_enum(:transform_keys) unless block_given? + dup.tap { |hash| hash.transform_keys!(*args, &block) } + end + + def slice(*keys) + keys.map! { |key| convert_key(key) } + self.class.new(super) + end + + def slice!(*keys) + keys.map! { |key| convert_key(key) } + super + end + def compact dup.tap(&:compact!) end diff --git a/activesupport/lib/active_support/i18n.rb b/activesupport/lib/active_support/i18n.rb index 3f47da3b38..d60b3eff30 100644 --- a/activesupport/lib/active_support/i18n.rb +++ b/activesupport/lib/active_support/i18n.rb @@ -1,13 +1,15 @@ -require_relative "core_ext/hash/deep_merge" -require_relative "core_ext/hash/except" -require_relative "core_ext/hash/slice" +# frozen_string_literal: true + +require "active_support/core_ext/hash/deep_merge" +require "active_support/core_ext/hash/except" +require "active_support/core_ext/hash/slice" begin require "i18n" rescue LoadError => e $stderr.puts "The i18n gem is not available. Please add it to your Gemfile and run bundle install" raise e end -require_relative "lazy_load_hooks" +require "active_support/lazy_load_hooks" ActiveSupport.run_load_hooks(:i18n) I18n.load_path << File.expand_path("locale/en.yml", __dir__) diff --git a/activesupport/lib/active_support/i18n_railtie.rb b/activesupport/lib/active_support/i18n_railtie.rb index 6809a650cf..ce8bfbfd8c 100644 --- a/activesupport/lib/active_support/i18n_railtie.rb +++ b/activesupport/lib/active_support/i18n_railtie.rb @@ -1,6 +1,8 @@ +# frozen_string_literal: true + require "active_support" -require_relative "file_update_checker" -require_relative "core_ext/array/wrap" +require "active_support/file_update_checker" +require "active_support/core_ext/array/wrap" # :enddoc: diff --git a/activesupport/lib/active_support/inflections.rb b/activesupport/lib/active_support/inflections.rb index 1b94ce9b1b..baf1cb3038 100644 --- a/activesupport/lib/active_support/inflections.rb +++ b/activesupport/lib/active_support/inflections.rb @@ -1,4 +1,6 @@ -require_relative "inflector/inflections" +# frozen_string_literal: true + +require "active_support/inflector/inflections" #-- # Defines the standard inflection rules. These are the starting point for diff --git a/activesupport/lib/active_support/inflector.rb b/activesupport/lib/active_support/inflector.rb index a4bd8aaeb4..d77f04c9c5 100644 --- a/activesupport/lib/active_support/inflector.rb +++ b/activesupport/lib/active_support/inflector.rb @@ -1,7 +1,9 @@ +# frozen_string_literal: true + # in case active_support/inflector is required without the rest of active_support -require_relative "inflector/inflections" -require_relative "inflector/transliterate" -require_relative "inflector/methods" +require "active_support/inflector/inflections" +require "active_support/inflector/transliterate" +require "active_support/inflector/methods" -require_relative "inflections" -require_relative "core_ext/string/inflections" +require "active_support/inflections" +require "active_support/core_ext/string/inflections" diff --git a/activesupport/lib/active_support/inflector/inflections.rb b/activesupport/lib/active_support/inflector/inflections.rb index 2cb7828968..0450a4be4c 100644 --- a/activesupport/lib/active_support/inflector/inflections.rb +++ b/activesupport/lib/active_support/inflector/inflections.rb @@ -1,7 +1,10 @@ +# frozen_string_literal: true + require "concurrent/map" -require_relative "../core_ext/array/prepend_and_append" -require_relative "../core_ext/regexp" -require_relative "../i18n" +require "active_support/core_ext/array/prepend_and_append" +require "active_support/core_ext/regexp" +require "active_support/i18n" +require "active_support/deprecation" module ActiveSupport module Inflector @@ -65,16 +68,21 @@ module ActiveSupport end attr_reader :plurals, :singulars, :uncountables, :humans, :acronyms, :acronym_regex + deprecate :acronym_regex + + attr_reader :acronyms_camelize_regex, :acronyms_underscore_regex # :nodoc: def initialize - @plurals, @singulars, @uncountables, @humans, @acronyms, @acronym_regex = [], [], Uncountables.new, [], {}, /(?=a)b/ + @plurals, @singulars, @uncountables, @humans, @acronyms = [], [], Uncountables.new, [], {} + define_acronym_regex_patterns end # Private, for the test suite. def initialize_dup(orig) # :nodoc: - %w(plurals singulars uncountables humans acronyms acronym_regex).each do |scope| + %w(plurals singulars uncountables humans acronyms).each do |scope| instance_variable_set("@#{scope}", orig.send(scope).dup) end + define_acronym_regex_patterns end # Specifies a new acronym. An acronym must be specified as it will appear @@ -128,7 +136,7 @@ module ActiveSupport # camelize 'mcdonald' # => 'McDonald' def acronym(word) @acronyms[word.downcase] = word - @acronym_regex = /#{@acronyms.values.join("|")}/ + define_acronym_regex_patterns end # Specifies a new pluralization rule and its replacement. The rule can @@ -223,6 +231,14 @@ module ActiveSupport instance_variable_set "@#{scope}", [] end end + + private + + def define_acronym_regex_patterns + @acronym_regex = @acronyms.empty? ? /(?=a)b/ : /#{@acronyms.values.join("|")}/ + @acronyms_camelize_regex = /^(?:#{@acronym_regex}(?=\b|[A-Z_])|\w)/ + @acronyms_underscore_regex = /(?:(?<=([A-Za-z\d]))|\b)(#{@acronym_regex})(?=\b|[^a-z])/ + end end # Yields a singleton instance of Inflector::Inflections so you can specify diff --git a/activesupport/lib/active_support/inflector/methods.rb b/activesupport/lib/active_support/inflector/methods.rb index ba85d3bb33..60eeaa77cb 100644 --- a/activesupport/lib/active_support/inflector/methods.rb +++ b/activesupport/lib/active_support/inflector/methods.rb @@ -1,5 +1,7 @@ -require_relative "../inflections" -require_relative "../core_ext/regexp" +# frozen_string_literal: true + +require "active_support/inflections" +require "active_support/core_ext/regexp" module ActiveSupport # The Inflector transforms words from singular to plural, class names to table @@ -69,7 +71,7 @@ module ActiveSupport if uppercase_first_letter string = string.sub(/^[a-z\d]*/) { |match| inflections.acronyms[match] || match.capitalize } else - string = string.sub(/^(?:#{inflections.acronym_regex}(?=\b|[A-Z_])|\w)/) { |match| match.downcase } + string = string.sub(inflections.acronyms_camelize_regex) { |match| match.downcase } end string.gsub!(/(?:_|(\/))([a-z\d]*)/i) { "#{$1}#{inflections.acronyms[$2] || $2.capitalize}" } string.gsub!("/".freeze, "::".freeze) @@ -90,7 +92,7 @@ module ActiveSupport def underscore(camel_cased_word) return camel_cased_word unless /[A-Z-]|::/.match?(camel_cased_word) word = camel_cased_word.to_s.gsub("::".freeze, "/".freeze) - word.gsub!(/(?:(?<=([A-Za-z\d]))|\b)(#{inflections.acronym_regex})(?=\b|[^a-z])/) { "#{$1 && '_'.freeze }#{$2.downcase}" } + word.gsub!(inflections.acronyms_underscore_regex) { "#{$1 && '_'.freeze }#{$2.downcase}" } word.gsub!(/([A-Z\d]+)([A-Z][a-z])/, '\1_\2'.freeze) word.gsub!(/([a-z\d])([A-Z])/, '\1_\2'.freeze) word.tr!("-".freeze, "_".freeze) @@ -136,7 +138,7 @@ module ActiveSupport result.tr!("_".freeze, " ".freeze) result.gsub!(/([a-z\d]*)/i) do |match| - "#{inflections.acronyms[match] || match.downcase}" + "#{inflections.acronyms[match.downcase] || match.downcase}" end if capitalize diff --git a/activesupport/lib/active_support/inflector/transliterate.rb b/activesupport/lib/active_support/inflector/transliterate.rb index 0775ee51bc..6f2ca4999c 100644 --- a/activesupport/lib/active_support/inflector/transliterate.rb +++ b/activesupport/lib/active_support/inflector/transliterate.rb @@ -1,5 +1,7 @@ -require_relative "../core_ext/string/multibyte" -require_relative "../i18n" +# frozen_string_literal: true + +require "active_support/core_ext/string/multibyte" +require "active_support/i18n" module ActiveSupport module Inflector @@ -59,26 +61,33 @@ module ActiveSupport def transliterate(string, replacement = "?".freeze) raise ArgumentError, "Can only transliterate strings. Received #{string.class.name}" unless string.is_a?(String) - I18n.transliterate(ActiveSupport::Multibyte::Unicode.normalize( - ActiveSupport::Multibyte::Unicode.tidy_bytes(string), :c), - replacement: replacement) + I18n.transliterate( + ActiveSupport::Multibyte::Unicode.normalize( + ActiveSupport::Multibyte::Unicode.tidy_bytes(string), :c), + replacement: replacement) end # Replaces special characters in a string so that it may be used as part of # a 'pretty' URL. # # parameterize("Donald E. Knuth") # => "donald-e-knuth" - # parameterize("^trés|Jolie-- ") # => "tres-jolie" + # parameterize("^très|Jolie-- ") # => "tres-jolie" # - # To use a custom separator, override the `separator` argument. + # To use a custom separator, override the +separator+ argument. # # parameterize("Donald E. Knuth", separator: '_') # => "donald_e_knuth" - # parameterize("^trés|Jolie-- ", separator: '_') # => "tres_jolie" + # parameterize("^très|Jolie__ ", separator: '_') # => "tres_jolie" # - # To preserve the case of the characters in a string, use the `preserve_case` argument. + # To preserve the case of the characters in a string, use the +preserve_case+ argument. # # parameterize("Donald E. Knuth", preserve_case: true) # => "Donald-E-Knuth" - # parameterize("^trés|Jolie-- ", preserve_case: true) # => "tres-Jolie" + # parameterize("^très|Jolie-- ", preserve_case: true) # => "tres-Jolie" + # + # It preserves dashes and underscores unless they are used as separators: + # + # parameterize("^très|Jolie__ ") # => "tres-jolie__" + # parameterize("^très|Jolie-- ", separator: "_") # => "tres_jolie--" + # parameterize("^très_Jolie-- ", separator: ".") # => "tres_jolie--" # def parameterize(string, separator: "-", preserve_case: false) # Replace accented chars with their ASCII equivalents. diff --git a/activesupport/lib/active_support/json.rb b/activesupport/lib/active_support/json.rb index e0a6ab3768..d7887175c0 100644 --- a/activesupport/lib/active_support/json.rb +++ b/activesupport/lib/active_support/json.rb @@ -1,2 +1,4 @@ -require_relative "json/decoding" -require_relative "json/encoding" +# frozen_string_literal: true + +require "active_support/json/decoding" +require "active_support/json/encoding" diff --git a/activesupport/lib/active_support/json/decoding.rb b/activesupport/lib/active_support/json/decoding.rb index c60ebb2795..8c0e016dc5 100644 --- a/activesupport/lib/active_support/json/decoding.rb +++ b/activesupport/lib/active_support/json/decoding.rb @@ -1,5 +1,7 @@ -require_relative "../core_ext/module/attribute_accessors" -require_relative "../core_ext/module/delegation" +# frozen_string_literal: true + +require "active_support/core_ext/module/attribute_accessors" +require "active_support/core_ext/module/delegation" require "json" module ActiveSupport diff --git a/activesupport/lib/active_support/json/encoding.rb b/activesupport/lib/active_support/json/encoding.rb index e7679e4630..1339c75ffe 100644 --- a/activesupport/lib/active_support/json/encoding.rb +++ b/activesupport/lib/active_support/json/encoding.rb @@ -1,5 +1,7 @@ -require_relative "../core_ext/object/json" -require_relative "../core_ext/module/delegation" +# frozen_string_literal: true + +require "active_support/core_ext/object/json" +require "active_support/core_ext/module/delegation" module ActiveSupport class << self diff --git a/activesupport/lib/active_support/key_generator.rb b/activesupport/lib/active_support/key_generator.rb index 23ab804eb1..78f7d7ca8d 100644 --- a/activesupport/lib/active_support/key_generator.rb +++ b/activesupport/lib/active_support/key_generator.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "concurrent/map" require "openssl" @@ -57,7 +59,7 @@ module ActiveSupport if secret.blank? raise ArgumentError, "A secret is required to generate an integrity hash " \ "for cookie session data. Set a secret_key_base of at least " \ - "#{SECRET_MIN_LENGTH} characters in config/secrets.yml." + "#{SECRET_MIN_LENGTH} characters in via `bin/rails credentials:edit`." end if secret.length < SECRET_MIN_LENGTH diff --git a/activesupport/lib/active_support/lazy_load_hooks.rb b/activesupport/lib/active_support/lazy_load_hooks.rb index 720ed47331..dc8080c469 100644 --- a/activesupport/lib/active_support/lazy_load_hooks.rb +++ b/activesupport/lib/active_support/lazy_load_hooks.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module ActiveSupport # lazy_load_hooks allows Rails to lazily load a lot of components and thus # making the app boot faster. Because of this feature now there is no need to @@ -25,33 +27,51 @@ module ActiveSupport base.class_eval do @load_hooks = Hash.new { |h, k| h[k] = [] } @loaded = Hash.new { |h, k| h[k] = [] } + @run_once = Hash.new { |h, k| h[k] = [] } end end # Declares a block that will be executed when a Rails component is fully # loaded. + # + # Options: + # + # * <tt>:yield</tt> - Yields the object that run_load_hooks to +block+. + # * <tt>:run_once</tt> - Given +block+ will run only once. def on_load(name, options = {}, &block) @loaded[name].each do |base| - execute_hook(base, options, block) + execute_hook(name, base, options, block) end @load_hooks[name] << [block, options] end - def execute_hook(base, options, block) - if options[:yield] - block.call(base) - else - base.instance_eval(&block) - end - end - def run_load_hooks(name, base = Object) @loaded[name] << base @load_hooks[name].each do |hook, options| - execute_hook(base, options, hook) + execute_hook(name, base, options, hook) end end + + private + + def with_execution_control(name, block, once) + unless @run_once[name].include?(block) + @run_once[name] << block if once + + yield + end + end + + def execute_hook(name, base, options, block) + with_execution_control(name, block, options[:run_once]) do + if options[:yield] + block.call(base) + else + base.instance_eval(&block) + end + end + end end extend LazyLoadHooks diff --git a/activesupport/lib/active_support/log_subscriber.rb b/activesupport/lib/active_support/log_subscriber.rb index 2b494e6d6c..0f7be06c8e 100644 --- a/activesupport/lib/active_support/log_subscriber.rb +++ b/activesupport/lib/active_support/log_subscriber.rb @@ -1,6 +1,8 @@ -require_relative "core_ext/module/attribute_accessors" -require_relative "core_ext/class/attribute" -require_relative "subscriber" +# frozen_string_literal: true + +require "active_support/core_ext/module/attribute_accessors" +require "active_support/core_ext/class/attribute" +require "active_support/subscriber" module ActiveSupport # ActiveSupport::LogSubscriber is an object set to consume diff --git a/activesupport/lib/active_support/log_subscriber/test_helper.rb b/activesupport/lib/active_support/log_subscriber/test_helper.rb index 469e6c6bb4..3f19ef5009 100644 --- a/activesupport/lib/active_support/log_subscriber/test_helper.rb +++ b/activesupport/lib/active_support/log_subscriber/test_helper.rb @@ -1,6 +1,8 @@ -require_relative "../log_subscriber" -require_relative "../logger" -require_relative "../notifications" +# frozen_string_literal: true + +require "active_support/log_subscriber" +require "active_support/logger" +require "active_support/notifications" module ActiveSupport class LogSubscriber diff --git a/activesupport/lib/active_support/logger.rb b/activesupport/lib/active_support/logger.rb index 677ec8d5bc..8152a182b4 100644 --- a/activesupport/lib/active_support/logger.rb +++ b/activesupport/lib/active_support/logger.rb @@ -1,5 +1,7 @@ -require_relative "logger_silence" -require_relative "logger_thread_safe_level" +# frozen_string_literal: true + +require "active_support/logger_silence" +require "active_support/logger_thread_safe_level" require "logger" module ActiveSupport diff --git a/activesupport/lib/active_support/logger_silence.rb b/activesupport/lib/active_support/logger_silence.rb index 7f85f54542..89f32b6782 100644 --- a/activesupport/lib/active_support/logger_silence.rb +++ b/activesupport/lib/active_support/logger_silence.rb @@ -1,5 +1,7 @@ -require_relative "concern" -require_relative "core_ext/module/attribute_accessors" +# frozen_string_literal: true + +require "active_support/concern" +require "active_support/core_ext/module/attribute_accessors" require "concurrent" module LoggerSilence diff --git a/activesupport/lib/active_support/logger_thread_safe_level.rb b/activesupport/lib/active_support/logger_thread_safe_level.rb index 405bb239cf..ba32813d3d 100644 --- a/activesupport/lib/active_support/logger_thread_safe_level.rb +++ b/activesupport/lib/active_support/logger_thread_safe_level.rb @@ -1,4 +1,6 @@ -require_relative "concern" +# frozen_string_literal: true + +require "active_support/concern" module ActiveSupport module LoggerThreadSafeLevel # :nodoc: diff --git a/activesupport/lib/active_support/message_encryptor.rb b/activesupport/lib/active_support/message_encryptor.rb index 3aaa1ae02c..5236c776dd 100644 --- a/activesupport/lib/active_support/message_encryptor.rb +++ b/activesupport/lib/active_support/message_encryptor.rb @@ -1,7 +1,10 @@ +# frozen_string_literal: true + require "openssl" require "base64" -require_relative "core_ext/array/extract_options" -require_relative "message_verifier" +require "active_support/core_ext/array/extract_options" +require "active_support/message_verifier" +require "active_support/messages/metadata" module ActiveSupport # MessageEncryptor is a simple way to encrypt values which get stored @@ -13,15 +16,74 @@ module ActiveSupport # This can be used in situations similar to the <tt>MessageVerifier</tt>, but # where you don't want users to be able to determine the value of the payload. # - # salt = SecureRandom.random_bytes(64) - # key = ActiveSupport::KeyGenerator.new('password').generate_key(salt, 32) # => "\x89\xE0\x156\xAC..." - # crypt = ActiveSupport::MessageEncryptor.new(key) # => #<ActiveSupport::MessageEncryptor ...> - # encrypted_data = crypt.encrypt_and_sign('my secret data') # => "NlFBTTMwOUV5UlA1QlNEN2xkY2d6eThYWWh..." - # crypt.decrypt_and_verify(encrypted_data) # => "my secret data" + # len = ActiveSupport::MessageEncryptor.key_len + # salt = SecureRandom.random_bytes(len) + # key = ActiveSupport::KeyGenerator.new('password').generate_key(salt, len) # => "\x89\xE0\x156\xAC..." + # crypt = ActiveSupport::MessageEncryptor.new(key) # => #<ActiveSupport::MessageEncryptor ...> + # encrypted_data = crypt.encrypt_and_sign('my secret data') # => "NlFBTTMwOUV5UlA1QlNEN2xkY2d6eThYWWh..." + # crypt.decrypt_and_verify(encrypted_data) # => "my secret data" + # + # === Confining messages to a specific purpose + # + # By default any message can be used throughout your app. But they can also be + # confined to a specific +:purpose+. + # + # token = crypt.encrypt_and_sign("this is the chair", purpose: :login) + # + # Then that same purpose must be passed when verifying to get the data back out: + # + # crypt.decrypt_and_verify(token, purpose: :login) # => "this is the chair" + # crypt.decrypt_and_verify(token, purpose: :shipping) # => nil + # crypt.decrypt_and_verify(token) # => nil + # + # Likewise, if a message has no purpose it won't be returned when verifying with + # a specific purpose. + # + # token = crypt.encrypt_and_sign("the conversation is lively") + # crypt.decrypt_and_verify(token, purpose: :scare_tactics) # => nil + # crypt.decrypt_and_verify(token) # => "the conversation is lively" + # + # === Making messages expire + # + # By default messages last forever and verifying one year from now will still + # return the original value. But messages can be set to expire at a given + # time with +:expires_in+ or +:expires_at+. + # + # crypt.encrypt_and_sign(parcel, expires_in: 1.month) + # crypt.encrypt_and_sign(doowad, expires_at: Time.now.end_of_year) + # + # Then the messages can be verified and returned upto the expire time. + # Thereafter, verifying returns +nil+. + # + # === Rotating keys + # + # MessageEncryptor also supports rotating out old configurations by falling + # back to a stack of encryptors. Call +rotate+ to build and add an encryptor + # so +decrypt_and_verify+ will also try the fallback. + # + # By default any rotated encryptors use the values of the primary + # encryptor unless specified otherwise. + # + # You'd give your encryptor the new defaults: + # + # crypt = ActiveSupport::MessageEncryptor.new(@secret, cipher: "aes-256-gcm") + # + # Then gradually rotate the old values out by adding them as fallbacks. Any message + # generated with the old values will then work until the rotation is removed. + # + # crypt.rotate old_secret # Fallback to an old secret instead of @secret. + # crypt.rotate cipher: "aes-256-cbc" # Fallback to an old cipher instead of aes-256-gcm. + # + # Though if both the secret and the cipher was changed at the same time, + # the above should be combined into: + # + # crypt.rotate old_secret, cipher: "aes-256-cbc" class MessageEncryptor - class << self - attr_accessor :use_authenticated_message_encryption #:nodoc: + prepend Messages::Rotator::Encryptor + cattr_accessor :use_authenticated_message_encryption, instance_accessor: false, default: false + + class << self def default_cipher #:nodoc: if use_authenticated_message_encryption "aes-256-gcm" @@ -83,15 +145,15 @@ module ActiveSupport end # Encrypt and sign a message. We need to sign the message in order to avoid - # padding attacks. Reference: http://www.limited-entropy.com/padding-oracle-attacks. - def encrypt_and_sign(value) - verifier.generate(_encrypt(value)) + # padding attacks. Reference: https://www.limited-entropy.com/padding-oracle-attacks/. + def encrypt_and_sign(value, expires_at: nil, expires_in: nil, purpose: nil) + verifier.generate(_encrypt(value, expires_at: expires_at, expires_in: expires_in, purpose: purpose)) end # Decrypt and verify a message. We need to verify the message in order to - # avoid padding attacks. Reference: http://www.limited-entropy.com/padding-oracle-attacks. - def decrypt_and_verify(value) - _decrypt(verifier.verify(value)) + # avoid padding attacks. Reference: https://www.limited-entropy.com/padding-oracle-attacks/. + def decrypt_and_verify(data, purpose: nil, **) + _decrypt(verifier.verify(data), purpose) end # Given a cipher, returns the key length of the cipher to help generate the key of desired size @@ -100,8 +162,7 @@ module ActiveSupport end private - - def _encrypt(value) + def _encrypt(value, **metadata_options) cipher = new_cipher cipher.encrypt cipher.key = @secret @@ -110,7 +171,7 @@ module ActiveSupport iv = cipher.random_iv cipher.auth_data = "" if aead_mode? - encrypted_data = cipher.update(@serializer.dump(value)) + encrypted_data = cipher.update(Messages::Metadata.wrap(@serializer.dump(value), metadata_options)) encrypted_data << cipher.final blob = "#{::Base64.strict_encode64 encrypted_data}--#{::Base64.strict_encode64 iv}" @@ -118,7 +179,7 @@ module ActiveSupport blob end - def _decrypt(encrypted_message) + def _decrypt(encrypted_message, purpose) cipher = new_cipher encrypted_data, iv, auth_tag = encrypted_message.split("--".freeze).map { |v| ::Base64.strict_decode64(v) } @@ -138,7 +199,8 @@ module ActiveSupport decrypted_data = cipher.update(encrypted_data) decrypted_data << cipher.final - @serializer.load(decrypted_data) + message = Messages::Metadata.verify(decrypted_data, purpose) + @serializer.load(message) if message rescue OpenSSLCipherError, TypeError, ArgumentError raise InvalidMessage end diff --git a/activesupport/lib/active_support/message_verifier.rb b/activesupport/lib/active_support/message_verifier.rb index e71dcd3a5b..83c39c0a86 100644 --- a/activesupport/lib/active_support/message_verifier.rb +++ b/activesupport/lib/active_support/message_verifier.rb @@ -1,6 +1,10 @@ +# frozen_string_literal: true + require "base64" -require_relative "core_ext/object/blank" -require_relative "security_utils" +require "active_support/core_ext/object/blank" +require "active_support/security_utils" +require "active_support/messages/metadata" +require "active_support/messages/rotator" module ActiveSupport # +MessageVerifier+ makes it easy to generate and verify messages which are @@ -27,10 +31,76 @@ module ActiveSupport # # +MessageVerifier+ creates HMAC signatures using SHA1 hash algorithm by default. # If you want to use a different hash algorithm, you can change it by providing - # `:digest` key as an option while initializing the verifier: + # +:digest+ key as an option while initializing the verifier: # # @verifier = ActiveSupport::MessageVerifier.new('s3Krit', digest: 'SHA256') + # + # === Confining messages to a specific purpose + # + # By default any message can be used throughout your app. But they can also be + # confined to a specific +:purpose+. + # + # token = @verifier.generate("this is the chair", purpose: :login) + # + # Then that same purpose must be passed when verifying to get the data back out: + # + # @verifier.verified(token, purpose: :login) # => "this is the chair" + # @verifier.verified(token, purpose: :shipping) # => nil + # @verifier.verified(token) # => nil + # + # @verifier.verify(token, purpose: :login) # => "this is the chair" + # @verifier.verify(token, purpose: :shipping) # => ActiveSupport::MessageVerifier::InvalidSignature + # @verifier.verify(token) # => ActiveSupport::MessageVerifier::InvalidSignature + # + # Likewise, if a message has no purpose it won't be returned when verifying with + # a specific purpose. + # + # token = @verifier.generate("the conversation is lively") + # @verifier.verified(token, purpose: :scare_tactics) # => nil + # @verifier.verified(token) # => "the conversation is lively" + # + # @verifier.verify(token, purpose: :scare_tactics) # => ActiveSupport::MessageVerifier::InvalidSignature + # @verifier.verify(token) # => "the conversation is lively" + # + # === Making messages expire + # + # By default messages last forever and verifying one year from now will still + # return the original value. But messages can be set to expire at a given + # time with +:expires_in+ or +:expires_at+. + # + # @verifier.generate(parcel, expires_in: 1.month) + # @verifier.generate(doowad, expires_at: Time.now.end_of_year) + # + # Then the messages can be verified and returned upto the expire time. + # Thereafter, the +verified+ method returns +nil+ while +verify+ raises + # <tt>ActiveSupport::MessageVerifier::InvalidSignature</tt>. + # + # === Rotating keys + # + # MessageVerifier also supports rotating out old configurations by falling + # back to a stack of verifiers. Call +rotate+ to build and add a verifier to + # so either +verified+ or +verify+ will also try verifying with the fallback. + # + # By default any rotated verifiers use the values of the primary + # verifier unless specified otherwise. + # + # You'd give your verifier the new defaults: + # + # verifier = ActiveSupport::MessageVerifier.new(@secret, digest: "SHA512", serializer: JSON) + # + # Then gradually rotate the old values out by adding them as fallbacks. Any message + # generated with the old values will then work until the rotation is removed. + # + # verifier.rotate old_secret # Fallback to an old secret instead of @secret. + # verifier.rotate digest: "SHA256" # Fallback to an old digest instead of SHA512. + # verifier.rotate serializer: Marshal # Fallback to an old serializer instead of JSON. + # + # Though the above would most likely be combined into one rotation: + # + # verifier.rotate old_secret, digest: "SHA256", serializer: Marshal class MessageVerifier + prepend Messages::Rotator::Verifier + class InvalidSignature < StandardError; end def initialize(secret, options = {}) @@ -77,11 +147,12 @@ module ActiveSupport # # incompatible_message = "test--dad7b06c94abba8d46a15fafaef56c327665d5ff" # verifier.verified(incompatible_message) # => TypeError: incompatible marshal file format - def verified(signed_message) + def verified(signed_message, purpose: nil, **) if valid_message?(signed_message) begin data = signed_message.split("--".freeze)[0] - @serializer.load(decode(data)) + message = Messages::Metadata.verify(decode(data), purpose) + @serializer.load(message) if message rescue ArgumentError => argument_error return if argument_error.message.include?("invalid base64") raise @@ -101,8 +172,8 @@ module ActiveSupport # # other_verifier = ActiveSupport::MessageVerifier.new 'd1ff3r3nt-s3Krit' # other_verifier.verify(signed_message) # => ActiveSupport::MessageVerifier::InvalidSignature - def verify(signed_message) - verified(signed_message) || raise(InvalidSignature) + def verify(*args) + verified(*args) || raise(InvalidSignature) end # Generates a signed message for the provided value. @@ -112,8 +183,8 @@ module ActiveSupport # # verifier = ActiveSupport::MessageVerifier.new 's3Krit' # verifier.generate 'a private message' # => "BAhJIhRwcml2YXRlLW1lc3NhZ2UGOgZFVA==--e2d724331ebdee96a10fb99b089508d1c72bd772" - def generate(value) - data = encode(@serializer.dump(value)) + def generate(value, expires_at: nil, expires_in: nil, purpose: nil) + data = encode(Messages::Metadata.wrap(@serializer.dump(value), expires_at: expires_at, expires_in: expires_in, purpose: purpose)) "#{data}--#{generate_digest(data)}" end diff --git a/activesupport/lib/active_support/messages/metadata.rb b/activesupport/lib/active_support/messages/metadata.rb new file mode 100644 index 0000000000..e97caac766 --- /dev/null +++ b/activesupport/lib/active_support/messages/metadata.rb @@ -0,0 +1,71 @@ +# frozen_string_literal: true + +require "time" + +module ActiveSupport + module Messages #:nodoc: + class Metadata #:nodoc: + def initialize(message, expires_at = nil, purpose = nil) + @message, @expires_at, @purpose = message, expires_at, purpose + end + + def as_json(options = {}) + { _rails: { message: @message, exp: @expires_at, pur: @purpose } } + end + + class << self + def wrap(message, expires_at: nil, expires_in: nil, purpose: nil) + if expires_at || expires_in || purpose + JSON.encode new(encode(message), pick_expiry(expires_at, expires_in), purpose) + else + message + end + end + + def verify(message, purpose) + extract_metadata(message).verify(purpose) + end + + private + def pick_expiry(expires_at, expires_in) + if expires_at + expires_at.utc.iso8601(3) + elsif expires_in + Time.now.utc.advance(seconds: expires_in).iso8601(3) + end + end + + def extract_metadata(message) + data = JSON.decode(message) rescue nil + + if data.is_a?(Hash) && data.key?("_rails") + new(decode(data["_rails"]["message"]), data["_rails"]["exp"], data["_rails"]["pur"]) + else + new(message) + end + end + + def encode(message) + ::Base64.strict_encode64(message) + end + + def decode(message) + ::Base64.strict_decode64(message) + end + end + + def verify(purpose) + @message if match?(purpose) && fresh? + end + + private + def match?(purpose) + @purpose.to_s == purpose.to_s + end + + def fresh? + @expires_at.nil? || Time.now.utc < Time.iso8601(@expires_at) + end + end + end +end diff --git a/activesupport/lib/active_support/messages/rotation_configuration.rb b/activesupport/lib/active_support/messages/rotation_configuration.rb new file mode 100644 index 0000000000..bd50d6d348 --- /dev/null +++ b/activesupport/lib/active_support/messages/rotation_configuration.rb @@ -0,0 +1,22 @@ +# frozen_string_literal: true + +module ActiveSupport + module Messages + class RotationConfiguration # :nodoc: + attr_reader :signed, :encrypted + + def initialize + @signed, @encrypted = [], [] + end + + def rotate(kind, *args) + case kind + when :signed + @signed << args + when :encrypted + @encrypted << args + end + end + end + end +end diff --git a/activesupport/lib/active_support/messages/rotator.rb b/activesupport/lib/active_support/messages/rotator.rb new file mode 100644 index 0000000000..823a399d67 --- /dev/null +++ b/activesupport/lib/active_support/messages/rotator.rb @@ -0,0 +1,56 @@ +# frozen_string_literal: true + +module ActiveSupport + module Messages + module Rotator # :nodoc: + def initialize(*, **options) + super + + @options = options + @rotations = [] + end + + def rotate(*secrets, **options) + @rotations << build_rotation(*secrets, @options.merge(options)) + end + + module Encryptor + include Rotator + + def decrypt_and_verify(*args, on_rotation: nil, **options) + super + rescue MessageEncryptor::InvalidMessage, MessageVerifier::InvalidSignature + run_rotations(on_rotation) { |encryptor| encryptor.decrypt_and_verify(*args, options) } || raise + end + + private + def build_rotation(secret = @secret, sign_secret = @sign_secret, options) + self.class.new(secret, sign_secret, options) + end + end + + module Verifier + include Rotator + + def verified(*args, on_rotation: nil, **options) + super || run_rotations(on_rotation) { |verifier| verifier.verified(*args, options) } + end + + private + def build_rotation(secret = @secret, options) + self.class.new(secret, options) + end + end + + private + def run_rotations(on_rotation) + @rotations.find do |rotation| + if message = yield(rotation) rescue next + on_rotation.call if on_rotation + return message + end + end + end + end + end +end diff --git a/activesupport/lib/active_support/multibyte.rb b/activesupport/lib/active_support/multibyte.rb index f7c7befee0..3fe3a05e93 100644 --- a/activesupport/lib/active_support/multibyte.rb +++ b/activesupport/lib/active_support/multibyte.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module ActiveSupport #:nodoc: module Multibyte autoload :Chars, "active_support/multibyte/chars" diff --git a/activesupport/lib/active_support/multibyte/chars.rb b/activesupport/lib/active_support/multibyte/chars.rb index e4c544d1fa..8152b8fd22 100644 --- a/activesupport/lib/active_support/multibyte/chars.rb +++ b/activesupport/lib/active_support/multibyte/chars.rb @@ -1,8 +1,10 @@ -require_relative "../json" -require_relative "../core_ext/string/access" -require_relative "../core_ext/string/behavior" -require_relative "../core_ext/module/delegation" -require_relative "../core_ext/regexp" +# frozen_string_literal: true + +require "active_support/json" +require "active_support/core_ext/string/access" +require "active_support/core_ext/string/behavior" +require "active_support/core_ext/module/delegation" +require "active_support/core_ext/regexp" module ActiveSupport #:nodoc: module Multibyte #:nodoc: diff --git a/activesupport/lib/active_support/multibyte/unicode.rb b/activesupport/lib/active_support/multibyte/unicode.rb index 8223e45e5a..a64223c0e0 100644 --- a/activesupport/lib/active_support/multibyte/unicode.rb +++ b/activesupport/lib/active_support/multibyte/unicode.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module ActiveSupport module Multibyte module Unicode diff --git a/activesupport/lib/active_support/notifications.rb b/activesupport/lib/active_support/notifications.rb index 10e40e04f9..6207de8094 100644 --- a/activesupport/lib/active_support/notifications.rb +++ b/activesupport/lib/active_support/notifications.rb @@ -1,6 +1,8 @@ -require_relative "notifications/instrumenter" -require_relative "notifications/fanout" -require_relative "per_thread_registry" +# frozen_string_literal: true + +require "active_support/notifications/instrumenter" +require "active_support/notifications/fanout" +require "active_support/per_thread_registry" module ActiveSupport # = Notifications diff --git a/activesupport/lib/active_support/notifications/fanout.rb b/activesupport/lib/active_support/notifications/fanout.rb index 9da115f552..25aab175b4 100644 --- a/activesupport/lib/active_support/notifications/fanout.rb +++ b/activesupport/lib/active_support/notifications/fanout.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "mutex_m" require "concurrent/map" diff --git a/activesupport/lib/active_support/notifications/instrumenter.rb b/activesupport/lib/active_support/notifications/instrumenter.rb index e11e2e0689..e99f5ee688 100644 --- a/activesupport/lib/active_support/notifications/instrumenter.rb +++ b/activesupport/lib/active_support/notifications/instrumenter.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "securerandom" module ActiveSupport diff --git a/activesupport/lib/active_support/number_helper.rb b/activesupport/lib/active_support/number_helper.rb index 9cb2821cb6..8fd6e932f1 100644 --- a/activesupport/lib/active_support/number_helper.rb +++ b/activesupport/lib/active_support/number_helper.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module ActiveSupport module NumberHelper extend ActiveSupport::Autoload diff --git a/activesupport/lib/active_support/number_helper/number_converter.rb b/activesupport/lib/active_support/number_helper/number_converter.rb index f3fed6e88b..06ba797a13 100644 --- a/activesupport/lib/active_support/number_helper/number_converter.rb +++ b/activesupport/lib/active_support/number_helper/number_converter.rb @@ -1,8 +1,10 @@ -require_relative "../core_ext/big_decimal/conversions" -require_relative "../core_ext/object/blank" -require_relative "../core_ext/hash/keys" -require_relative "../i18n" -require_relative "../core_ext/class/attribute" +# frozen_string_literal: true + +require "active_support/core_ext/big_decimal/conversions" +require "active_support/core_ext/object/blank" +require "active_support/core_ext/hash/keys" +require "active_support/i18n" +require "active_support/core_ext/class/attribute" module ActiveSupport module NumberHelper diff --git a/activesupport/lib/active_support/number_helper/number_to_currency_converter.rb b/activesupport/lib/active_support/number_helper/number_to_currency_converter.rb index 7bd2d4869a..3f037c73ed 100644 --- a/activesupport/lib/active_support/number_helper/number_to_currency_converter.rb +++ b/activesupport/lib/active_support/number_helper/number_to_currency_converter.rb @@ -1,4 +1,6 @@ -require_relative "../core_ext/numeric/inquiry" +# frozen_string_literal: true + +require "active_support/core_ext/numeric/inquiry" module ActiveSupport module NumberHelper diff --git a/activesupport/lib/active_support/number_helper/number_to_delimited_converter.rb b/activesupport/lib/active_support/number_helper/number_to_delimited_converter.rb index e3b35531b1..d5b5706705 100644 --- a/activesupport/lib/active_support/number_helper/number_to_delimited_converter.rb +++ b/activesupport/lib/active_support/number_helper/number_to_delimited_converter.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module ActiveSupport module NumberHelper class NumberToDelimitedConverter < NumberConverter #:nodoc: diff --git a/activesupport/lib/active_support/number_helper/number_to_human_converter.rb b/activesupport/lib/active_support/number_helper/number_to_human_converter.rb index 040343b5dd..03eb6671ec 100644 --- a/activesupport/lib/active_support/number_helper/number_to_human_converter.rb +++ b/activesupport/lib/active_support/number_helper/number_to_human_converter.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module ActiveSupport module NumberHelper class NumberToHumanConverter < NumberConverter # :nodoc: diff --git a/activesupport/lib/active_support/number_helper/number_to_human_size_converter.rb b/activesupport/lib/active_support/number_helper/number_to_human_size_converter.rb index f263dbe9f8..842f2fc8df 100644 --- a/activesupport/lib/active_support/number_helper/number_to_human_size_converter.rb +++ b/activesupport/lib/active_support/number_helper/number_to_human_size_converter.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module ActiveSupport module NumberHelper class NumberToHumanSizeConverter < NumberConverter #:nodoc: diff --git a/activesupport/lib/active_support/number_helper/number_to_percentage_converter.rb b/activesupport/lib/active_support/number_helper/number_to_percentage_converter.rb index ac647ca9b7..4dcdad2e2c 100644 --- a/activesupport/lib/active_support/number_helper/number_to_percentage_converter.rb +++ b/activesupport/lib/active_support/number_helper/number_to_percentage_converter.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module ActiveSupport module NumberHelper class NumberToPercentageConverter < NumberConverter # :nodoc: diff --git a/activesupport/lib/active_support/number_helper/number_to_phone_converter.rb b/activesupport/lib/active_support/number_helper/number_to_phone_converter.rb index 3546ee5c2a..96410f4995 100644 --- a/activesupport/lib/active_support/number_helper/number_to_phone_converter.rb +++ b/activesupport/lib/active_support/number_helper/number_to_phone_converter.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module ActiveSupport module NumberHelper class NumberToPhoneConverter < NumberConverter #:nodoc: diff --git a/activesupport/lib/active_support/number_helper/number_to_rounded_converter.rb b/activesupport/lib/active_support/number_helper/number_to_rounded_converter.rb index c32d85a45f..eb528a0583 100644 --- a/activesupport/lib/active_support/number_helper/number_to_rounded_converter.rb +++ b/activesupport/lib/active_support/number_helper/number_to_rounded_converter.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module ActiveSupport module NumberHelper class NumberToRoundedConverter < NumberConverter # :nodoc: @@ -35,26 +37,6 @@ module ActiveSupport private - def digits_and_rounded_number(precision) - if zero? - [1, 0] - else - digits = digit_count(number) - multiplier = 10**(digits - precision) - rounded_number = calculate_rounded_number(multiplier) - digits = digit_count(rounded_number) # After rounding, the number of digits may have changed - [digits, rounded_number] - end - end - - def calculate_rounded_number(multiplier) - (number / BigDecimal.new(multiplier.to_f.to_s)).round * multiplier - end - - def digit_count(number) - number.zero? ? 1 : (Math.log10(absolute_number(number)) + 1).floor - end - def strip_insignificant_zeros options[:strip_insignificant_zeros] end diff --git a/activesupport/lib/active_support/number_helper/rounding_helper.rb b/activesupport/lib/active_support/number_helper/rounding_helper.rb index 63b48444a6..2ad8d49c4e 100644 --- a/activesupport/lib/active_support/number_helper/rounding_helper.rb +++ b/activesupport/lib/active_support/number_helper/rounding_helper.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module ActiveSupport module NumberHelper class RoundingHelper # :nodoc: @@ -34,7 +36,7 @@ module ActiveSupport return 0 if number.zero? digits = digit_count(number) multiplier = 10**(digits - precision) - (number / BigDecimal.new(multiplier.to_f.to_s)).round * multiplier + (number / BigDecimal(multiplier.to_f.to_s)).round * multiplier end def convert_to_decimal(number) diff --git a/activesupport/lib/active_support/option_merger.rb b/activesupport/lib/active_support/option_merger.rb index 9edb0e6cd8..ab9ca727f6 100644 --- a/activesupport/lib/active_support/option_merger.rb +++ b/activesupport/lib/active_support/option_merger.rb @@ -1,4 +1,6 @@ -require_relative "core_ext/hash/deep_merge" +# frozen_string_literal: true + +require "active_support/core_ext/hash/deep_merge" module ActiveSupport class OptionMerger #:nodoc: diff --git a/activesupport/lib/active_support/ordered_hash.rb b/activesupport/lib/active_support/ordered_hash.rb index 3aa0a14f04..5758513021 100644 --- a/activesupport/lib/active_support/ordered_hash.rb +++ b/activesupport/lib/active_support/ordered_hash.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "yaml" YAML.add_builtin_type("omap") do |type, val| diff --git a/activesupport/lib/active_support/ordered_options.rb b/activesupport/lib/active_support/ordered_options.rb index c0f39a392b..c4e419f546 100644 --- a/activesupport/lib/active_support/ordered_options.rb +++ b/activesupport/lib/active_support/ordered_options.rb @@ -1,4 +1,6 @@ -require_relative "core_ext/object/blank" +# frozen_string_literal: true + +require "active_support/core_ext/object/blank" module ActiveSupport # Usually key value pairs are handled something like this: @@ -22,7 +24,7 @@ module ActiveSupport # To raise an exception when the value is blank, append a # bang to the key name, like: # - # h.dog! # => raises KeyError: key not found: :dog + # h.dog! # => raises KeyError: :dog is blank # class OrderedOptions < Hash alias_method :_get, :[] # preserve the original #[] method @@ -44,7 +46,7 @@ module ActiveSupport bangs = name_string.chomp!("!") if bangs - fetch(name_string.to_sym).presence || raise(KeyError.new("#{name_string} is blank.")) + self[name_string].presence || raise(KeyError.new(":#{name_string} is blank")) else self[name_string] end diff --git a/activesupport/lib/active_support/per_thread_registry.rb b/activesupport/lib/active_support/per_thread_registry.rb index 1e0d8345a0..eb92fb4371 100644 --- a/activesupport/lib/active_support/per_thread_registry.rb +++ b/activesupport/lib/active_support/per_thread_registry.rb @@ -1,4 +1,6 @@ -require_relative "core_ext/module/delegation" +# frozen_string_literal: true + +require "active_support/core_ext/module/delegation" module ActiveSupport # NOTE: This approach has been deprecated for end-user code in favor of {thread_mattr_accessor}[rdoc-ref:Module#thread_mattr_accessor] and friends. diff --git a/activesupport/lib/active_support/proxy_object.rb b/activesupport/lib/active_support/proxy_object.rb index 20a0fd8e62..0965fcd2d9 100644 --- a/activesupport/lib/active_support/proxy_object.rb +++ b/activesupport/lib/active_support/proxy_object.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module ActiveSupport # A class with no predefined methods that behaves similarly to Builder's # BlankSlate. Used for proxy classes. diff --git a/activesupport/lib/active_support/rails.rb b/activesupport/lib/active_support/rails.rb index 656af6dee9..5c34a0abb3 100644 --- a/activesupport/lib/active_support/rails.rb +++ b/activesupport/lib/active_support/rails.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # This is private interface. # # Rails components cherry pick from Active Support as needed, but there are a @@ -9,25 +11,25 @@ # Rails and can change anytime. # Defines Object#blank? and Object#present?. -require_relative "core_ext/object/blank" +require "active_support/core_ext/object/blank" # Rails own autoload, eager_load, etc. -require_relative "dependencies/autoload" +require "active_support/dependencies/autoload" # Support for ClassMethods and the included macro. -require_relative "concern" +require "active_support/concern" # Defines Class#class_attribute. -require_relative "core_ext/class/attribute" +require "active_support/core_ext/class/attribute" # Defines Module#delegate. -require_relative "core_ext/module/delegation" +require "active_support/core_ext/module/delegation" # Defines ActiveSupport::Deprecation. -require_relative "deprecation" +require "active_support/deprecation" # Defines Regexp#match?. # # This should be removed when Rails needs Ruby 2.4 or later, and the require # added where other Regexp extensions are being used (easy to grep). -require_relative "core_ext/regexp" +require "active_support/core_ext/regexp" diff --git a/activesupport/lib/active_support/railtie.rb b/activesupport/lib/active_support/railtie.rb index 3377748263..6b8fa676a9 100644 --- a/activesupport/lib/active_support/railtie.rb +++ b/activesupport/lib/active_support/railtie.rb @@ -1,5 +1,7 @@ +# frozen_string_literal: true + require "active_support" -require_relative "i18n_railtie" +require "active_support/i18n_railtie" module ActiveSupport class Railtie < Rails::Railtie # :nodoc: @@ -8,9 +10,11 @@ module ActiveSupport config.eager_load_namespaces << ActiveSupport initializer "active_support.set_authenticated_message_encryption" do |app| - if app.config.active_support.respond_to?(:use_authenticated_message_encryption) - ActiveSupport::MessageEncryptor.use_authenticated_message_encryption = - app.config.active_support.use_authenticated_message_encryption + config.after_initialize do + unless app.config.active_support.use_authenticated_message_encryption.nil? + ActiveSupport::MessageEncryptor.use_authenticated_message_encryption = + app.config.active_support.use_authenticated_message_encryption + end end end @@ -34,24 +38,42 @@ module ActiveSupport rescue TZInfo::DataSourceNotFound => e raise e.exception "tzinfo-data is not present. Please add gem 'tzinfo-data' to your Gemfile and run bundle install" end - require_relative "core_ext/time/zones" + require "active_support/core_ext/time/zones" Time.zone_default = Time.find_zone!(app.config.time_zone) end # Sets the default week start # If assigned value is not a valid day symbol (e.g. :sunday, :monday, ...), an exception will be raised. initializer "active_support.initialize_beginning_of_week" do |app| - require_relative "core_ext/date/calculations" + require "active_support/core_ext/date/calculations" beginning_of_week_default = Date.find_beginning_of_week!(app.config.beginning_of_week) Date.beginning_of_week_default = beginning_of_week_default end + initializer "active_support.require_master_key" do |app| + if app.config.respond_to?(:require_master_key) && app.config.require_master_key + begin + app.credentials.key + rescue ActiveSupport::EncryptedFile::MissingKeyError => error + $stderr.puts error.message + exit 1 + end + end + end + initializer "active_support.set_configs" do |app| app.config.active_support.each do |k, v| k = "#{k}=" ActiveSupport.send(k, v) if ActiveSupport.respond_to? k end end + + initializer "active_support.set_hash_digest_class" do |app| + if app.config.active_support.hash_digest_class + ActiveSupport::Digest.hash_digest_class = + app.config.active_support.hash_digest_class + end + end end end diff --git a/activesupport/lib/active_support/reloader.rb b/activesupport/lib/active_support/reloader.rb index a87c82e68a..b26d9c3665 100644 --- a/activesupport/lib/active_support/reloader.rb +++ b/activesupport/lib/active_support/reloader.rb @@ -1,4 +1,6 @@ -require_relative "execution_wrapper" +# frozen_string_literal: true + +require "active_support/execution_wrapper" module ActiveSupport #-- @@ -26,14 +28,17 @@ module ActiveSupport define_callbacks :class_unload + # Registers a callback that will run once at application startup and every time the code is reloaded. def self.to_prepare(*args, &block) set_callback(:prepare, *args, &block) end + # Registers a callback that will run immediately before the classes are unloaded. def self.before_class_unload(*args, &block) set_callback(:class_unload, *args, &block) end + # Registers a callback that will run immediately after the classes are unloaded. def self.after_class_unload(*args, &block) set_callback(:class_unload, :after, *args, &block) end diff --git a/activesupport/lib/active_support/rescuable.rb b/activesupport/lib/active_support/rescuable.rb index 06f6a71de4..e0fa29cacb 100644 --- a/activesupport/lib/active_support/rescuable.rb +++ b/activesupport/lib/active_support/rescuable.rb @@ -1,6 +1,8 @@ -require_relative "concern" -require_relative "core_ext/class/attribute" -require_relative "core_ext/string/inflections" +# frozen_string_literal: true + +require "active_support/concern" +require "active_support/core_ext/class/attribute" +require "active_support/core_ext/string/inflections" module ActiveSupport # Rescuable module adds support for easier exception handling. diff --git a/activesupport/lib/active_support/security_utils.rb b/activesupport/lib/active_support/security_utils.rb index b655d64449..20b6b9cd3f 100644 --- a/activesupport/lib/active_support/security_utils.rb +++ b/activesupport/lib/active_support/security_utils.rb @@ -1,15 +1,15 @@ -require "digest" +# frozen_string_literal: true + +require "digest/sha2" module ActiveSupport module SecurityUtils - # Constant time string comparison. + # Constant time string comparison, for fixed length strings. # # The values compared should be of fixed length, such as strings - # that have already been processed by HMAC. This should not be used - # on variable length plaintext strings because it could leak length info - # via timing attacks. - def secure_compare(a, b) - return false unless a.bytesize == b.bytesize + # that have already been processed by HMAC. Raises in case of length mismatch. + def fixed_length_secure_compare(a, b) + raise ArgumentError, "string length mismatch." unless a.bytesize == b.bytesize l = a.unpack "C#{a.bytesize}" @@ -17,11 +17,15 @@ module ActiveSupport b.each_byte { |byte| res |= byte ^ l.shift } res == 0 end - module_function :secure_compare + module_function :fixed_length_secure_compare - def variable_size_secure_compare(a, b) # :nodoc: - secure_compare(::Digest::SHA256.hexdigest(a), ::Digest::SHA256.hexdigest(b)) + # Constant time string comparison, for variable length strings. + # + # The values are first processed by SHA256, so that we don't leak length info + # via timing attacks. + def secure_compare(a, b) + fixed_length_secure_compare(::Digest::SHA256.hexdigest(a), ::Digest::SHA256.hexdigest(b)) && a == b end - module_function :variable_size_secure_compare + module_function :secure_compare end end diff --git a/activesupport/lib/active_support/string_inquirer.rb b/activesupport/lib/active_support/string_inquirer.rb index 90eac89c9e..a3af36720e 100644 --- a/activesupport/lib/active_support/string_inquirer.rb +++ b/activesupport/lib/active_support/string_inquirer.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module ActiveSupport # Wrapping a string in this class gives you a prettier way to test # for equality. The value returned by <tt>Rails.env</tt> is wrapped diff --git a/activesupport/lib/active_support/subscriber.rb b/activesupport/lib/active_support/subscriber.rb index 3a54482c75..d6dd5474d0 100644 --- a/activesupport/lib/active_support/subscriber.rb +++ b/activesupport/lib/active_support/subscriber.rb @@ -1,5 +1,7 @@ -require_relative "per_thread_registry" -require_relative "notifications" +# frozen_string_literal: true + +require "active_support/per_thread_registry" +require "active_support/notifications" module ActiveSupport # ActiveSupport::Subscriber is an object set to consume diff --git a/activesupport/lib/active_support/tagged_logging.rb b/activesupport/lib/active_support/tagged_logging.rb index 90d096c397..8561cba9f1 100644 --- a/activesupport/lib/active_support/tagged_logging.rb +++ b/activesupport/lib/active_support/tagged_logging.rb @@ -1,7 +1,9 @@ -require_relative "core_ext/module/delegation" -require_relative "core_ext/object/blank" +# frozen_string_literal: true + +require "active_support/core_ext/module/delegation" +require "active_support/core_ext/object/blank" require "logger" -require_relative "logger" +require "active_support/logger" module ActiveSupport # Wraps any standard Logger object to provide tagging capabilities. diff --git a/activesupport/lib/active_support/test_case.rb b/activesupport/lib/active_support/test_case.rb index f2940a176f..d1f7e6ea09 100644 --- a/activesupport/lib/active_support/test_case.rb +++ b/activesupport/lib/active_support/test_case.rb @@ -1,15 +1,16 @@ +# frozen_string_literal: true + gem "minitest" # make sure we get the gem, not stdlib require "minitest" -require_relative "testing/tagged_logging" -require_relative "testing/setup_and_teardown" -require_relative "testing/assertions" -require_relative "testing/deprecation" -require_relative "testing/declarative" -require_relative "testing/isolation" -require_relative "testing/constant_lookup" -require_relative "testing/time_helpers" -require_relative "testing/file_fixtures" -require_relative "core_ext/kernel/reporting" +require "active_support/testing/tagged_logging" +require "active_support/testing/setup_and_teardown" +require "active_support/testing/assertions" +require "active_support/testing/deprecation" +require "active_support/testing/declarative" +require "active_support/testing/isolation" +require "active_support/testing/constant_lookup" +require "active_support/testing/time_helpers" +require "active_support/testing/file_fixtures" module ActiveSupport class TestCase < ::Minitest::Test diff --git a/activesupport/lib/active_support/testing/assertions.rb b/activesupport/lib/active_support/testing/assertions.rb index 28e1df8870..6f69c48674 100644 --- a/activesupport/lib/active_support/testing/assertions.rb +++ b/activesupport/lib/active_support/testing/assertions.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module ActiveSupport module Testing module Assertions @@ -154,11 +156,12 @@ module ActiveSupport after = exp.call - if to == UNTRACKED - error = "#{expression.inspect} didn't changed" - error = "#{message}.\n#{error}" if message - assert_not_equal before, after, error - else + error = "#{expression.inspect} didn't change" + error = "#{error}. It was already #{to}" if before == to + error = "#{message}.\n#{error}" if message + assert before != after, error + + unless to == UNTRACKED error = "#{expression.inspect} didn't change to #{to}" error = "#{message}.\n#{error}" if message assert to === after, error @@ -188,7 +191,7 @@ module ActiveSupport error = "#{expression.inspect} did change to #{after}" error = "#{message}.\n#{error}" if message - assert_equal before, after, error + assert before == after, error retval end diff --git a/activesupport/lib/active_support/testing/autorun.rb b/activesupport/lib/active_support/testing/autorun.rb index a18788f38e..889b41659a 100644 --- a/activesupport/lib/active_support/testing/autorun.rb +++ b/activesupport/lib/active_support/testing/autorun.rb @@ -1,9 +1,7 @@ +# frozen_string_literal: true + gem "minitest" require "minitest" -if Minitest.respond_to?(:run_via) && !Minitest.run_via.set? - Minitest.run_via = :ruby -end - Minitest.autorun diff --git a/activesupport/lib/active_support/testing/constant_lookup.rb b/activesupport/lib/active_support/testing/constant_lookup.rb index c0b58aba96..51167e9237 100644 --- a/activesupport/lib/active_support/testing/constant_lookup.rb +++ b/activesupport/lib/active_support/testing/constant_lookup.rb @@ -1,5 +1,7 @@ -require_relative "../concern" -require_relative "../inflector" +# frozen_string_literal: true + +require "active_support/concern" +require "active_support/inflector" module ActiveSupport module Testing diff --git a/activesupport/lib/active_support/testing/declarative.rb b/activesupport/lib/active_support/testing/declarative.rb index 53ab3ebf78..7c3403684d 100644 --- a/activesupport/lib/active_support/testing/declarative.rb +++ b/activesupport/lib/active_support/testing/declarative.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module ActiveSupport module Testing module Declarative diff --git a/activesupport/lib/active_support/testing/deprecation.rb b/activesupport/lib/active_support/testing/deprecation.rb index 6ee49530f0..f655435729 100644 --- a/activesupport/lib/active_support/testing/deprecation.rb +++ b/activesupport/lib/active_support/testing/deprecation.rb @@ -1,5 +1,7 @@ -require_relative "../deprecation" -require_relative "../core_ext/regexp" +# frozen_string_literal: true + +require "active_support/deprecation" +require "active_support/core_ext/regexp" module ActiveSupport module Testing diff --git a/activesupport/lib/active_support/testing/file_fixtures.rb b/activesupport/lib/active_support/testing/file_fixtures.rb index affb84cda5..ad923d1aab 100644 --- a/activesupport/lib/active_support/testing/file_fixtures.rb +++ b/activesupport/lib/active_support/testing/file_fixtures.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module ActiveSupport module Testing # Adds simple access to sample files called file fixtures. diff --git a/activesupport/lib/active_support/testing/isolation.rb b/activesupport/lib/active_support/testing/isolation.rb index 54c3263efa..fa9bebb181 100644 --- a/activesupport/lib/active_support/testing/isolation.rb +++ b/activesupport/lib/active_support/testing/isolation.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module ActiveSupport module Testing module Isolation @@ -53,7 +55,7 @@ module ActiveSupport write.close result = read.read Process.wait2(pid) - return result.unpack("m")[0] + result.unpack("m")[0] end end diff --git a/activesupport/lib/active_support/testing/method_call_assertions.rb b/activesupport/lib/active_support/testing/method_call_assertions.rb index 6b07416fdc..c6358002ea 100644 --- a/activesupport/lib/active_support/testing/method_call_assertions.rb +++ b/activesupport/lib/active_support/testing/method_call_assertions.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "minitest/mock" module ActiveSupport diff --git a/activesupport/lib/active_support/testing/setup_and_teardown.rb b/activesupport/lib/active_support/testing/setup_and_teardown.rb index c39f3bac2b..1dbf3c5da0 100644 --- a/activesupport/lib/active_support/testing/setup_and_teardown.rb +++ b/activesupport/lib/active_support/testing/setup_and_teardown.rb @@ -1,5 +1,7 @@ -require_relative "../concern" -require_relative "../callbacks" +# frozen_string_literal: true + +require "active_support/concern" +require "active_support/callbacks" module ActiveSupport module Testing diff --git a/activesupport/lib/active_support/testing/stream.rb b/activesupport/lib/active_support/testing/stream.rb index 1d06b94559..d070a1793d 100644 --- a/activesupport/lib/active_support/testing/stream.rb +++ b/activesupport/lib/active_support/testing/stream.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module ActiveSupport module Testing module Stream #:nodoc: diff --git a/activesupport/lib/active_support/testing/tagged_logging.rb b/activesupport/lib/active_support/testing/tagged_logging.rb index afdff87b45..9ca50c7918 100644 --- a/activesupport/lib/active_support/testing/tagged_logging.rb +++ b/activesupport/lib/active_support/testing/tagged_logging.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module ActiveSupport module Testing # Logs a "PostsControllerTest: test name" heading before each test to diff --git a/activesupport/lib/active_support/testing/time_helpers.rb b/activesupport/lib/active_support/testing/time_helpers.rb index 4db7065ddf..998a51a34c 100644 --- a/activesupport/lib/active_support/testing/time_helpers.rb +++ b/activesupport/lib/active_support/testing/time_helpers.rb @@ -1,5 +1,8 @@ -require_relative "../core_ext/string/strip" # for strip_heredoc -require_relative "../core_ext/time/calculations" +# frozen_string_literal: true + +require "active_support/core_ext/module/redefine_method" +require "active_support/core_ext/string/strip" # for strip_heredoc +require "active_support/core_ext/time/calculations" require "concurrent/map" module ActiveSupport @@ -41,7 +44,7 @@ module ActiveSupport def unstub_object(stub) singleton_class = stub.object.singleton_class - singleton_class.send :undef_method, stub.method_name + singleton_class.send :silence_redefinition_of_method, stub.method_name singleton_class.send :alias_method, stub.method_name, stub.original_method singleton_class.send :undef_method, stub.original_method end @@ -49,8 +52,14 @@ module ActiveSupport # Contains helpers that help you test passage of time. module TimeHelpers + def after_teardown + travel_back + super + end + # Changes current time to the time in the future or in the past by a given time difference by - # stubbing +Time.now+, +Date.today+, and +DateTime.now+. + # stubbing +Time.now+, +Date.today+, and +DateTime.now+. The stubs are automatically removed + # at the end of the test. # # Time.current # => Sat, 09 Nov 2013 15:34:49 EST -05:00 # travel 1.day @@ -72,6 +81,7 @@ module ActiveSupport # Changes current time to the given time by stubbing +Time.now+, # +Date.today+, and +DateTime.now+ to return the time or date passed into this method. + # The stubs are automatically removed at the end of the test. # # Time.current # => Sat, 09 Nov 2013 15:34:49 EST -05:00 # travel_to Time.zone.local(2004, 11, 24, 01, 04, 44) @@ -149,7 +159,7 @@ module ActiveSupport end # Returns the current time back to its original state, by removing the stubs added by - # `travel` and `travel_to`. + # +travel+ and +travel_to+. # # Time.current # => Sat, 09 Nov 2013 15:34:49 EST -05:00 # travel_to Time.zone.local(2004, 11, 24, 01, 04, 44) @@ -160,6 +170,26 @@ module ActiveSupport simple_stubs.unstub_all! end + # Calls +travel_to+ with +Time.now+. + # + # Time.current # => Sun, 09 Jul 2017 15:34:49 EST -05:00 + # freeze_time + # sleep(1) + # Time.current # => Sun, 09 Jul 2017 15:34:49 EST -05:00 + # + # This method also accepts a block, which will return the current time back to its original + # state at the end of the block: + # + # Time.current # => Sun, 09 Jul 2017 15:34:49 EST -05:00 + # freeze_time do + # sleep(1) + # User.create.created_at # => Sun, 09 Jul 2017 15:34:49 EST -05:00 + # end + # Time.current # => Sun, 09 Jul 2017 15:34:50 EST -05:00 + def freeze_time(&block) + travel_to Time.now, &block + end + private def simple_stubs diff --git a/activesupport/lib/active_support/time.rb b/activesupport/lib/active_support/time.rb index bc5f0177e2..51854675bf 100644 --- a/activesupport/lib/active_support/time.rb +++ b/activesupport/lib/active_support/time.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module ActiveSupport autoload :Duration, "active_support/duration" autoload :TimeWithZone, "active_support/time_with_zone" @@ -7,12 +9,12 @@ end require "date" require "time" -require_relative "core_ext/time" -require_relative "core_ext/date" -require_relative "core_ext/date_time" +require "active_support/core_ext/time" +require "active_support/core_ext/date" +require "active_support/core_ext/date_time" -require_relative "core_ext/integer/time" -require_relative "core_ext/numeric/time" +require "active_support/core_ext/integer/time" +require "active_support/core_ext/numeric/time" -require_relative "core_ext/string/conversions" -require_relative "core_ext/string/zones" +require "active_support/core_ext/string/conversions" +require "active_support/core_ext/string/zones" diff --git a/activesupport/lib/active_support/time_with_zone.rb b/activesupport/lib/active_support/time_with_zone.rb index 67d4a8683b..20650ce714 100644 --- a/activesupport/lib/active_support/time_with_zone.rb +++ b/activesupport/lib/active_support/time_with_zone.rb @@ -1,7 +1,9 @@ -require_relative "duration" -require_relative "values/time_zone" -require_relative "core_ext/object/acts_like" -require_relative "core_ext/date_and_time/compatibility" +# frozen_string_literal: true + +require "active_support/duration" +require "active_support/values/time_zone" +require "active_support/core_ext/object/acts_like" +require "active_support/core_ext/date_and_time/compatibility" module ActiveSupport # A Time-like class that can represent a time in any time zone. Necessary diff --git a/activesupport/lib/active_support/values/time_zone.rb b/activesupport/lib/active_support/values/time_zone.rb index 0659b39981..4d81ac939e 100644 --- a/activesupport/lib/active_support/values/time_zone.rb +++ b/activesupport/lib/active_support/values/time_zone.rb @@ -1,6 +1,8 @@ +# frozen_string_literal: true + require "tzinfo" require "concurrent/map" -require_relative "../core_ext/object/blank" +require "active_support/core_ext/object/blank" module ActiveSupport # The TimeZone class serves as a wrapper around TZInfo::Timezone instances. @@ -28,7 +30,7 @@ module ActiveSupport class TimeZone # Keys are Rails TimeZone names, values are TZInfo identifiers. MAPPING = { - "International Date Line West" => "Pacific/Midway", + "International Date Line West" => "Etc/GMT+12", "Midway Island" => "Pacific/Midway", "American Samoa" => "Pacific/Pago_Pago", "Hawaii" => "Pacific/Honolulu", @@ -254,6 +256,13 @@ module ActiveSupport @country_zones[code] ||= load_country_zones(code) end + def clear #:nodoc: + @lazy_zones_map = Concurrent::Map.new + @country_zones = Concurrent::Map.new + @zones = nil + @zones_map = nil + end + private def load_country_zones(code) country = TZInfo::Country.get(code) @@ -267,9 +276,8 @@ module ActiveSupport end def zones_map - @zones_map ||= begin - MAPPING.each_key { |place| self[place] } # load all the zones - @lazy_zones_map + @zones_map ||= MAPPING.each_with_object({}) do |(name, _), zones| + zones[name] = self[name] end end end @@ -359,7 +367,7 @@ module ActiveSupport # Time.zone.iso8601('1999-12-31') # => Fri, 31 Dec 1999 00:00:00 HST -10:00 # # If the string is invalid then an +ArgumentError+ will be raised unlike +parse+ - # which returns +nil+ when given an invalid date string. + # which usually returns +nil+ when given an invalid date string. def iso8601(str) parts = Date._iso8601(str) @@ -398,6 +406,8 @@ module ActiveSupport # components are supplied, then the day of the month defaults to 1: # # Time.zone.parse('Mar 2000') # => Wed, 01 Mar 2000 00:00:00 HST -10:00 + # + # If the string is invalid then an +ArgumentError+ could be raised. def parse(str, now = now()) parts_to_time(Date._parse(str, false), now) end @@ -502,7 +512,7 @@ module ActiveSupport # Available so that TimeZone instances respond like TZInfo::Timezone # instances. def period_for_local(time, dst = true) - tzinfo.period_for_local(time, dst) + tzinfo.period_for_local(time, dst) { |periods| periods.last } end def periods_for_local(time) #:nodoc: diff --git a/activesupport/lib/active_support/version.rb b/activesupport/lib/active_support/version.rb index 20b91ac911..928838c837 100644 --- a/activesupport/lib/active_support/version.rb +++ b/activesupport/lib/active_support/version.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require_relative "gem_version" module ActiveSupport diff --git a/activesupport/lib/active_support/xml_mini.rb b/activesupport/lib/active_support/xml_mini.rb index 14725ffd64..ee2048cb54 100644 --- a/activesupport/lib/active_support/xml_mini.rb +++ b/activesupport/lib/active_support/xml_mini.rb @@ -1,9 +1,11 @@ +# frozen_string_literal: true + require "time" require "base64" require "bigdecimal" -require_relative "core_ext/module/delegation" -require_relative "core_ext/string/inflections" -require_relative "core_ext/date_time/calculations" +require "active_support/core_ext/module/delegation" +require "active_support/core_ext/string/inflections" +require "active_support/core_ext/date_time/calculations" module ActiveSupport # = XmlMini @@ -197,7 +199,7 @@ module ActiveSupport if name.is_a?(Module) name else - require_relative "xml_mini/#{name.downcase}" + require "active_support/xml_mini/#{name.downcase}" ActiveSupport.const_get("XmlMini_#{name}") end end diff --git a/activesupport/lib/active_support/xml_mini/jdom.rb b/activesupport/lib/active_support/xml_mini/jdom.rb index 331d9960e7..7f94a64016 100644 --- a/activesupport/lib/active_support/xml_mini/jdom.rb +++ b/activesupport/lib/active_support/xml_mini/jdom.rb @@ -1,9 +1,11 @@ +# frozen_string_literal: true + raise "JRuby is required to use the JDOM backend for XmlMini" unless RUBY_PLATFORM.include?("java") require "jruby" include Java -require_relative "../core_ext/object/blank" +require "active_support/core_ext/object/blank" java_import javax.xml.parsers.DocumentBuilder unless defined? DocumentBuilder java_import javax.xml.parsers.DocumentBuilderFactory unless defined? DocumentBuilderFactory @@ -38,7 +40,7 @@ module ActiveSupport else @dbf = DocumentBuilderFactory.new_instance # secure processing of java xml - # http://www.ibm.com/developerworks/xml/library/x-tipcfsx/index.html + # https://archive.is/9xcQQ @dbf.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", false) @dbf.setFeature("http://xml.org/sax/features/external-general-entities", false) @dbf.setFeature("http://xml.org/sax/features/external-parameter-entities", false) @@ -167,7 +169,7 @@ module ActiveSupport # element:: # XML element to be checked. def empty_content?(element) - text = "" + text = "".dup child_nodes = element.child_nodes (0...child_nodes.length).each do |i| item = child_nodes.item(i) diff --git a/activesupport/lib/active_support/xml_mini/libxml.rb b/activesupport/lib/active_support/xml_mini/libxml.rb index d7097dcc64..0b000fea60 100644 --- a/activesupport/lib/active_support/xml_mini/libxml.rb +++ b/activesupport/lib/active_support/xml_mini/libxml.rb @@ -1,5 +1,7 @@ +# frozen_string_literal: true + require "libxml" -require_relative "../core_ext/object/blank" +require "active_support/core_ext/object/blank" require "stringio" module ActiveSupport diff --git a/activesupport/lib/active_support/xml_mini/libxmlsax.rb b/activesupport/lib/active_support/xml_mini/libxmlsax.rb index 0cfa2b2cd3..dcf16e6084 100644 --- a/activesupport/lib/active_support/xml_mini/libxmlsax.rb +++ b/activesupport/lib/active_support/xml_mini/libxmlsax.rb @@ -1,5 +1,7 @@ +# frozen_string_literal: true + require "libxml" -require_relative "../core_ext/object/blank" +require "active_support/core_ext/object/blank" require "stringio" module ActiveSupport diff --git a/activesupport/lib/active_support/xml_mini/nokogiri.rb b/activesupport/lib/active_support/xml_mini/nokogiri.rb index 57d8cec0c6..5ee6fc8159 100644 --- a/activesupport/lib/active_support/xml_mini/nokogiri.rb +++ b/activesupport/lib/active_support/xml_mini/nokogiri.rb @@ -1,10 +1,12 @@ +# frozen_string_literal: true + begin require "nokogiri" rescue LoadError => e $stderr.puts "You don't have nokogiri installed in your application. Please add it to your Gemfile and run bundle install" raise e end -require_relative "../core_ext/object/blank" +require "active_support/core_ext/object/blank" require "stringio" module ActiveSupport diff --git a/activesupport/lib/active_support/xml_mini/nokogirisax.rb b/activesupport/lib/active_support/xml_mini/nokogirisax.rb index 8fc1dfa727..b01ed00a14 100644 --- a/activesupport/lib/active_support/xml_mini/nokogirisax.rb +++ b/activesupport/lib/active_support/xml_mini/nokogirisax.rb @@ -1,10 +1,12 @@ +# frozen_string_literal: true + begin require "nokogiri" rescue LoadError => e $stderr.puts "You don't have nokogiri installed in your application. Please add it to your Gemfile and run bundle install" raise e end -require_relative "../core_ext/object/blank" +require "active_support/core_ext/object/blank" require "stringio" module ActiveSupport diff --git a/activesupport/lib/active_support/xml_mini/rexml.rb b/activesupport/lib/active_support/xml_mini/rexml.rb index 04d12c6109..32458d5b0d 100644 --- a/activesupport/lib/active_support/xml_mini/rexml.rb +++ b/activesupport/lib/active_support/xml_mini/rexml.rb @@ -1,5 +1,7 @@ -require_relative "../core_ext/kernel/reporting" -require_relative "../core_ext/object/blank" +# frozen_string_literal: true + +require "active_support/core_ext/kernel/reporting" +require "active_support/core_ext/object/blank" require "stringio" module ActiveSupport diff --git a/activesupport/test/abstract_unit.rb b/activesupport/test/abstract_unit.rb index c4f34c0abf..f214898145 100644 --- a/activesupport/test/abstract_unit.rb +++ b/activesupport/test/abstract_unit.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + ORIG_ARGV = ARGV.dup require "active_support/core_ext/kernel/reporting" @@ -36,4 +38,8 @@ class ActiveSupport::TestCase private def jruby_skip(message = "") skip message if defined?(JRUBY_VERSION) end + + def frozen_error_class + Object.const_defined?(:FrozenError) ? FrozenError : RuntimeError + end end diff --git a/activesupport/test/array_inquirer_test.rb b/activesupport/test/array_inquirer_test.rb index 5b2bc82905..d5419b862d 100644 --- a/activesupport/test/array_inquirer_test.rb +++ b/activesupport/test/array_inquirer_test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "abstract_unit" require "active_support/core_ext/array" diff --git a/activesupport/test/autoload_test.rb b/activesupport/test/autoload_test.rb index 6c8aa3e055..216b069420 100644 --- a/activesupport/test/autoload_test.rb +++ b/activesupport/test/autoload_test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "abstract_unit" class TestAutoloadModule < ActiveSupport::TestCase diff --git a/activesupport/test/autoloading_fixtures/a/b.rb b/activesupport/test/autoloading_fixtures/a/b.rb index 0dbbbbd181..27baaea08c 100644 --- a/activesupport/test/autoloading_fixtures/a/b.rb +++ b/activesupport/test/autoloading_fixtures/a/b.rb @@ -1,2 +1,4 @@ +# frozen_string_literal: true + class A::B end diff --git a/activesupport/test/autoloading_fixtures/a/c/d.rb b/activesupport/test/autoloading_fixtures/a/c/d.rb index 2c0ec5f182..f07128673f 100644 --- a/activesupport/test/autoloading_fixtures/a/c/d.rb +++ b/activesupport/test/autoloading_fixtures/a/c/d.rb @@ -1,2 +1,4 @@ +# frozen_string_literal: true + class A::C::D end diff --git a/activesupport/test/autoloading_fixtures/a/c/em/f.rb b/activesupport/test/autoloading_fixtures/a/c/em/f.rb index 3ff1b7efa0..78c96cf45f 100644 --- a/activesupport/test/autoloading_fixtures/a/c/em/f.rb +++ b/activesupport/test/autoloading_fixtures/a/c/em/f.rb @@ -1,2 +1,4 @@ +# frozen_string_literal: true + class A::C::EM::F end diff --git a/activesupport/test/autoloading_fixtures/application.rb b/activesupport/test/autoloading_fixtures/application.rb index d7d3096dcb..971cbe1b17 100644 --- a/activesupport/test/autoloading_fixtures/application.rb +++ b/activesupport/test/autoloading_fixtures/application.rb @@ -1 +1,3 @@ +# frozen_string_literal: true + ApplicationController = 10 diff --git a/activesupport/test/autoloading_fixtures/circular1.rb b/activesupport/test/autoloading_fixtures/circular1.rb index a45761f066..7f891b5eb1 100644 --- a/activesupport/test/autoloading_fixtures/circular1.rb +++ b/activesupport/test/autoloading_fixtures/circular1.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + silence_warnings do Circular2 end diff --git a/activesupport/test/autoloading_fixtures/circular2.rb b/activesupport/test/autoloading_fixtures/circular2.rb index c847fa5001..1fdb4c261f 100644 --- a/activesupport/test/autoloading_fixtures/circular2.rb +++ b/activesupport/test/autoloading_fixtures/circular2.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + Circular1 class Circular2 diff --git a/activesupport/test/autoloading_fixtures/class_folder.rb b/activesupport/test/autoloading_fixtures/class_folder.rb index 6ee8182214..ff0826c298 100644 --- a/activesupport/test/autoloading_fixtures/class_folder.rb +++ b/activesupport/test/autoloading_fixtures/class_folder.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class ClassFolder ConstantInClassFolder = "indeed" end diff --git a/activesupport/test/autoloading_fixtures/class_folder/class_folder_subclass.rb b/activesupport/test/autoloading_fixtures/class_folder/class_folder_subclass.rb index 4df069cab6..cd901e9d71 100644 --- a/activesupport/test/autoloading_fixtures/class_folder/class_folder_subclass.rb +++ b/activesupport/test/autoloading_fixtures/class_folder/class_folder_subclass.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class ClassFolder::ClassFolderSubclass < ClassFolder ConstantInClassFolder = "indeed" end diff --git a/activesupport/test/autoloading_fixtures/class_folder/inline_class.rb b/activesupport/test/autoloading_fixtures/class_folder/inline_class.rb index 8235e90724..960bfcbc70 100644 --- a/activesupport/test/autoloading_fixtures/class_folder/inline_class.rb +++ b/activesupport/test/autoloading_fixtures/class_folder/inline_class.rb @@ -1,2 +1,4 @@ +# frozen_string_literal: true + class ClassFolder::InlineClass end diff --git a/activesupport/test/autoloading_fixtures/class_folder/nested_class.rb b/activesupport/test/autoloading_fixtures/class_folder/nested_class.rb index 57a13d89ea..98426b797d 100644 --- a/activesupport/test/autoloading_fixtures/class_folder/nested_class.rb +++ b/activesupport/test/autoloading_fixtures/class_folder/nested_class.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class ClassFolder class NestedClass end diff --git a/activesupport/test/autoloading_fixtures/conflict.rb b/activesupport/test/autoloading_fixtures/conflict.rb index d7f42b5d5f..c5d3f6bdc0 100644 --- a/activesupport/test/autoloading_fixtures/conflict.rb +++ b/activesupport/test/autoloading_fixtures/conflict.rb @@ -1 +1,3 @@ +# frozen_string_literal: true + Conflict = 2 diff --git a/activesupport/test/autoloading_fixtures/counting_loader.rb b/activesupport/test/autoloading_fixtures/counting_loader.rb index 4225c4412c..6ac3a9828d 100644 --- a/activesupport/test/autoloading_fixtures/counting_loader.rb +++ b/activesupport/test/autoloading_fixtures/counting_loader.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + $counting_loaded_times ||= 0 $counting_loaded_times += 1 diff --git a/activesupport/test/autoloading_fixtures/cross_site_dependency.rb b/activesupport/test/autoloading_fixtures/cross_site_dependency.rb index de941bf271..8a18dcff10 100644 --- a/activesupport/test/autoloading_fixtures/cross_site_dependency.rb +++ b/activesupport/test/autoloading_fixtures/cross_site_dependency.rb @@ -1,2 +1,4 @@ +# frozen_string_literal: true + class CrossSiteDependency end diff --git a/activesupport/test/autoloading_fixtures/d.rb b/activesupport/test/autoloading_fixtures/d.rb index 52850e1e1a..72752d878e 100644 --- a/activesupport/test/autoloading_fixtures/d.rb +++ b/activesupport/test/autoloading_fixtures/d.rb @@ -1,2 +1,4 @@ +# frozen_string_literal: true + class D end diff --git a/activesupport/test/autoloading_fixtures/em.rb b/activesupport/test/autoloading_fixtures/em.rb index e47024999e..2e0ac9a6f9 100644 --- a/activesupport/test/autoloading_fixtures/em.rb +++ b/activesupport/test/autoloading_fixtures/em.rb @@ -1,2 +1,4 @@ +# frozen_string_literal: true + class EM end diff --git a/activesupport/test/autoloading_fixtures/html/some_class.rb b/activesupport/test/autoloading_fixtures/html/some_class.rb index b43d15d891..fbbfd4a214 100644 --- a/activesupport/test/autoloading_fixtures/html/some_class.rb +++ b/activesupport/test/autoloading_fixtures/html/some_class.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module HTML class SomeClass end diff --git a/activesupport/test/autoloading_fixtures/load_path/loaded_constant.rb b/activesupport/test/autoloading_fixtures/load_path/loaded_constant.rb index d2c4f6b0c5..8735ce87e1 100644 --- a/activesupport/test/autoloading_fixtures/load_path/loaded_constant.rb +++ b/activesupport/test/autoloading_fixtures/load_path/loaded_constant.rb @@ -1,2 +1,4 @@ +# frozen_string_literal: true + module LoadedConstant end diff --git a/activesupport/test/autoloading_fixtures/loads_constant.rb b/activesupport/test/autoloading_fixtures/loads_constant.rb index 0b30dc8bca..0bb434a956 100644 --- a/activesupport/test/autoloading_fixtures/loads_constant.rb +++ b/activesupport/test/autoloading_fixtures/loads_constant.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module LoadsConstant end diff --git a/activesupport/test/autoloading_fixtures/module_folder/inline_class.rb b/activesupport/test/autoloading_fixtures/module_folder/inline_class.rb index ca83437046..c11246b528 100644 --- a/activesupport/test/autoloading_fixtures/module_folder/inline_class.rb +++ b/activesupport/test/autoloading_fixtures/module_folder/inline_class.rb @@ -1,2 +1,4 @@ +# frozen_string_literal: true + class ModuleFolder::InlineClass end diff --git a/activesupport/test/autoloading_fixtures/module_folder/nested_class.rb b/activesupport/test/autoloading_fixtures/module_folder/nested_class.rb index fc4076bd0a..69226b405c 100644 --- a/activesupport/test/autoloading_fixtures/module_folder/nested_class.rb +++ b/activesupport/test/autoloading_fixtures/module_folder/nested_class.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module ModuleFolder class NestedClass end diff --git a/activesupport/test/autoloading_fixtures/module_folder/nested_sibling.rb b/activesupport/test/autoloading_fixtures/module_folder/nested_sibling.rb index 04c426833e..30de83af11 100644 --- a/activesupport/test/autoloading_fixtures/module_folder/nested_sibling.rb +++ b/activesupport/test/autoloading_fixtures/module_folder/nested_sibling.rb @@ -1,2 +1,4 @@ +# frozen_string_literal: true + class ModuleFolder::NestedSibling end diff --git a/activesupport/test/autoloading_fixtures/module_with_custom_const_missing/a/b.rb b/activesupport/test/autoloading_fixtures/module_with_custom_const_missing/a/b.rb index 4f2020c503..f688c1ef35 100644 --- a/activesupport/test/autoloading_fixtures/module_with_custom_const_missing/a/b.rb +++ b/activesupport/test/autoloading_fixtures/module_with_custom_const_missing/a/b.rb @@ -1 +1,3 @@ +# frozen_string_literal: true + ModuleWithCustomConstMissing::A::B = "10" diff --git a/activesupport/test/autoloading_fixtures/multiple_constant_file.rb b/activesupport/test/autoloading_fixtures/multiple_constant_file.rb index a9ff4eb89c..1da26e6c2c 100644 --- a/activesupport/test/autoloading_fixtures/multiple_constant_file.rb +++ b/activesupport/test/autoloading_fixtures/multiple_constant_file.rb @@ -1,2 +1,4 @@ +# frozen_string_literal: true + MultipleConstantFile = 10 SiblingConstant = MultipleConstantFile * 2 diff --git a/activesupport/test/autoloading_fixtures/prepend.rb b/activesupport/test/autoloading_fixtures/prepend.rb index 3134d1df2b..bf9e36e12c 100644 --- a/activesupport/test/autoloading_fixtures/prepend.rb +++ b/activesupport/test/autoloading_fixtures/prepend.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class SubClassConflict end diff --git a/activesupport/test/autoloading_fixtures/prepend/sub_class_conflict.rb b/activesupport/test/autoloading_fixtures/prepend/sub_class_conflict.rb index 090dda3043..506c3c5920 100644 --- a/activesupport/test/autoloading_fixtures/prepend/sub_class_conflict.rb +++ b/activesupport/test/autoloading_fixtures/prepend/sub_class_conflict.rb @@ -1,2 +1,4 @@ +# frozen_string_literal: true + class Prepend::SubClassConflict end diff --git a/activesupport/test/autoloading_fixtures/raises_arbitrary_exception.rb b/activesupport/test/autoloading_fixtures/raises_arbitrary_exception.rb index e477ab21d0..118ee6bdd1 100644 --- a/activesupport/test/autoloading_fixtures/raises_arbitrary_exception.rb +++ b/activesupport/test/autoloading_fixtures/raises_arbitrary_exception.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + RaisesArbitraryException = 1 _ = A::B # Autoloading recursion, also expected to be watched and discarded. diff --git a/activesupport/test/autoloading_fixtures/raises_name_error.rb b/activesupport/test/autoloading_fixtures/raises_name_error.rb index a49960abf0..c23afb7b12 100644 --- a/activesupport/test/autoloading_fixtures/raises_name_error.rb +++ b/activesupport/test/autoloading_fixtures/raises_name_error.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class RaisesNameError FooBarBaz end diff --git a/activesupport/test/autoloading_fixtures/raises_no_method_error.rb b/activesupport/test/autoloading_fixtures/raises_no_method_error.rb index e1b8fce24a..1000ce1cf5 100644 --- a/activesupport/test/autoloading_fixtures/raises_no_method_error.rb +++ b/activesupport/test/autoloading_fixtures/raises_no_method_error.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class RaisesNoMethodError self.foobar_method_doesnt_exist end diff --git a/activesupport/test/autoloading_fixtures/requires_constant.rb b/activesupport/test/autoloading_fixtures/requires_constant.rb index f04dcc4091..6e51998949 100644 --- a/activesupport/test/autoloading_fixtures/requires_constant.rb +++ b/activesupport/test/autoloading_fixtures/requires_constant.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "loaded_constant" module RequiresConstant diff --git a/activesupport/test/autoloading_fixtures/should_not_be_required.rb b/activesupport/test/autoloading_fixtures/should_not_be_required.rb index 1fcf170cc5..8deffa1816 100644 --- a/activesupport/test/autoloading_fixtures/should_not_be_required.rb +++ b/activesupport/test/autoloading_fixtures/should_not_be_required.rb @@ -1 +1,3 @@ +# frozen_string_literal: true + ShouldNotBeAutoloaded = 0 diff --git a/activesupport/test/autoloading_fixtures/throws.rb b/activesupport/test/autoloading_fixtures/throws.rb index e1d96cc512..b6fb391032 100644 --- a/activesupport/test/autoloading_fixtures/throws.rb +++ b/activesupport/test/autoloading_fixtures/throws.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + Throws = 1 _ = A::B # Autoloading recursion, expected to be discarded. diff --git a/activesupport/test/autoloading_fixtures/typo.rb b/activesupport/test/autoloading_fixtures/typo.rb index 0ffe07c2b3..d45cddbcf5 100644 --- a/activesupport/test/autoloading_fixtures/typo.rb +++ b/activesupport/test/autoloading_fixtures/typo.rb @@ -1 +1,3 @@ +# frozen_string_literal: true + TypO = 1 diff --git a/activesupport/test/benchmarkable_test.rb b/activesupport/test/benchmarkable_test.rb index 210b9cb9fd..424da0a52c 100644 --- a/activesupport/test/benchmarkable_test.rb +++ b/activesupport/test/benchmarkable_test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "abstract_unit" class BenchmarkableTest < ActiveSupport::TestCase diff --git a/activesupport/test/broadcast_logger_test.rb b/activesupport/test/broadcast_logger_test.rb index 184d0ebddd..181113e70a 100644 --- a/activesupport/test/broadcast_logger_test.rb +++ b/activesupport/test/broadcast_logger_test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "abstract_unit" module ActiveSupport diff --git a/activesupport/test/cache/behaviors.rb b/activesupport/test/cache/behaviors.rb index efd045ac5e..cb08a10bba 100644 --- a/activesupport/test/cache/behaviors.rb +++ b/activesupport/test/cache/behaviors.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require_relative "behaviors/autoloading_cache_behavior" require_relative "behaviors/cache_delete_matched_behavior" require_relative "behaviors/cache_increment_decrement_behavior" diff --git a/activesupport/test/cache/behaviors/autoloading_cache_behavior.rb b/activesupport/test/cache/behaviors/autoloading_cache_behavior.rb index 5f8af331f6..b340eb6c48 100644 --- a/activesupport/test/cache/behaviors/autoloading_cache_behavior.rb +++ b/activesupport/test/cache/behaviors/autoloading_cache_behavior.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "dependencies_test_helpers" module AutoloadingCacheBehavior diff --git a/activesupport/test/cache/behaviors/cache_delete_matched_behavior.rb b/activesupport/test/cache/behaviors/cache_delete_matched_behavior.rb index b872eb0279..6f59ce48d2 100644 --- a/activesupport/test/cache/behaviors/cache_delete_matched_behavior.rb +++ b/activesupport/test/cache/behaviors/cache_delete_matched_behavior.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module CacheDeleteMatchedBehavior def test_delete_matched @cache.write("foo", "bar") diff --git a/activesupport/test/cache/behaviors/cache_increment_decrement_behavior.rb b/activesupport/test/cache/behaviors/cache_increment_decrement_behavior.rb index 0d32339565..16b7abc679 100644 --- a/activesupport/test/cache/behaviors/cache_increment_decrement_behavior.rb +++ b/activesupport/test/cache/behaviors/cache_increment_decrement_behavior.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module CacheIncrementDecrementBehavior def test_increment @cache.write("foo", 1, raw: true) @@ -6,7 +8,9 @@ module CacheIncrementDecrementBehavior assert_equal 2, @cache.read("foo").to_i assert_equal 3, @cache.increment("foo") assert_equal 3, @cache.read("foo").to_i - assert_nil @cache.increment("bar") + + missing = @cache.increment("bar") + assert(missing.nil? || missing == 1) end def test_decrement @@ -16,6 +20,8 @@ module CacheIncrementDecrementBehavior assert_equal 2, @cache.read("foo").to_i assert_equal 1, @cache.decrement("foo") assert_equal 1, @cache.read("foo").to_i - assert_nil @cache.decrement("bar") + + missing = @cache.decrement("bar") + assert(missing.nil? || missing == -1) end end diff --git a/activesupport/test/cache/behaviors/cache_store_behavior.rb b/activesupport/test/cache/behaviors/cache_store_behavior.rb index 4631e6aee8..bdc689b8b4 100644 --- a/activesupport/test/cache/behaviors/cache_store_behavior.rb +++ b/activesupport/test/cache/behaviors/cache_store_behavior.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # Tests the base functionality that should be identical across all cache stores. module CacheStoreBehavior def test_should_read_and_write_strings @@ -144,6 +146,16 @@ module CacheStoreBehavior assert_nil @cache.read("foo") end + def test_read_and_write_uncompressed_small_data + @cache.write("foo", "bar", compress: false) + assert_equal "bar", @cache.read("foo") + end + + def test_read_and_write_uncompressed_nil + @cache.write("foo", nil, compress: false) + assert_nil @cache.read("foo") + end + def test_cache_key obj = Object.new def obj.cache_key @@ -162,6 +174,18 @@ module CacheStoreBehavior assert_equal "bar", @cache.read("foo") end + def test_unversioned_cache_key + obj = Object.new + def obj.cache_key + "foo" + end + def obj.cache_key_with_version + "foo-v1" + end + @cache.write(obj, "bar") + assert_equal "bar", @cache.read("foo") + end + def test_array_as_cache_key @cache.write([:fu, "foo"], "bar") assert_equal "bar", @cache.read("fu/foo") diff --git a/activesupport/test/cache/behaviors/cache_store_version_behavior.rb b/activesupport/test/cache/behaviors/cache_store_version_behavior.rb index a0170c896f..c2e4d046af 100644 --- a/activesupport/test/cache/behaviors/cache_store_version_behavior.rb +++ b/activesupport/test/cache/behaviors/cache_store_version_behavior.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module CacheStoreVersionBehavior ModelWithKeyAndVersion = Struct.new(:cache_key, :cache_version) diff --git a/activesupport/test/cache/behaviors/encoded_key_cache_behavior.rb b/activesupport/test/cache/behaviors/encoded_key_cache_behavior.rb index 6adef2916d..da16142496 100644 --- a/activesupport/test/cache/behaviors/encoded_key_cache_behavior.rb +++ b/activesupport/test/cache/behaviors/encoded_key_cache_behavior.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + # https://rails.lighthouseapp.com/projects/8994/tickets/6225-memcachestore-cant-deal-with-umlauts-and-special-characters # The error is caused by character encodings that can't be compared with ASCII-8BIT regular expressions and by special # characters like the umlaut in UTF-8. diff --git a/activesupport/test/cache/behaviors/local_cache_behavior.rb b/activesupport/test/cache/behaviors/local_cache_behavior.rb index 8530296374..f7302df4c8 100644 --- a/activesupport/test/cache/behaviors/local_cache_behavior.rb +++ b/activesupport/test/cache/behaviors/local_cache_behavior.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module LocalCacheBehavior def test_local_writes_are_persistent_on_the_remote_cache retval = @cache.with_local_cache do @@ -18,7 +20,11 @@ module LocalCacheBehavior end def test_cleanup_clears_local_cache_but_not_remote_cache - skip unless @cache.class.instance_methods(false).include?(:cleanup) + begin + @cache.cleanup + rescue NotImplementedError + skip + end @cache.with_local_cache do @cache.write("foo", "bar") diff --git a/activesupport/test/cache/cache_entry_test.rb b/activesupport/test/cache/cache_entry_test.rb index e446e39b10..80ff7ad564 100644 --- a/activesupport/test/cache/cache_entry_test.rb +++ b/activesupport/test/cache/cache_entry_test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "abstract_unit" require "active_support/cache" @@ -12,16 +14,23 @@ class CacheEntryTest < ActiveSupport::TestCase end end - def test_compress_values + def test_compressed_values value = "value" * 100 entry = ActiveSupport::Cache::Entry.new(value, compress: true, compress_threshold: 1) assert_equal value, entry.value assert(value.bytesize > entry.size, "value is compressed") end - def test_non_compress_values + def test_compressed_by_default + value = "value" * 100 + entry = ActiveSupport::Cache::Entry.new(value, compress_threshold: 1) + assert_equal value, entry.value + assert(value.bytesize > entry.size, "value is compressed") + end + + def test_uncompressed_values value = "value" * 100 - entry = ActiveSupport::Cache::Entry.new(value) + entry = ActiveSupport::Cache::Entry.new(value, compress: false) assert_equal value, entry.value assert_equal value.bytesize, entry.size end diff --git a/activesupport/test/cache/cache_key_test.rb b/activesupport/test/cache/cache_key_test.rb index ea39d7a299..84e656f504 100644 --- a/activesupport/test/cache/cache_key_test.rb +++ b/activesupport/test/cache/cache_key_test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "abstract_unit" require "active_support/cache" diff --git a/activesupport/test/cache/cache_store_logger_test.rb b/activesupport/test/cache/cache_store_logger_test.rb index 621cfebb10..1af6893cc9 100644 --- a/activesupport/test/cache/cache_store_logger_test.rb +++ b/activesupport/test/cache/cache_store_logger_test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "abstract_unit" require "active_support/cache" diff --git a/activesupport/test/cache/cache_store_namespace_test.rb b/activesupport/test/cache/cache_store_namespace_test.rb index e395c88271..b52a61c500 100644 --- a/activesupport/test/cache/cache_store_namespace_test.rb +++ b/activesupport/test/cache/cache_store_namespace_test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "abstract_unit" require "active_support/cache" diff --git a/activesupport/test/cache/cache_store_setting_test.rb b/activesupport/test/cache/cache_store_setting_test.rb index cb9b006abe..368cb39f97 100644 --- a/activesupport/test/cache/cache_store_setting_test.rb +++ b/activesupport/test/cache/cache_store_setting_test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "abstract_unit" require "active_support/cache" require "dalli" diff --git a/activesupport/test/cache/cache_store_write_multi_test.rb b/activesupport/test/cache/cache_store_write_multi_test.rb index 16e3f3b842..5b6fd678c5 100644 --- a/activesupport/test/cache/cache_store_write_multi_test.rb +++ b/activesupport/test/cache/cache_store_write_multi_test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "abstract_unit" require "active_support/cache" diff --git a/activesupport/test/cache/local_cache_middleware_test.rb b/activesupport/test/cache/local_cache_middleware_test.rb index 352502fb43..e59fae0b4c 100644 --- a/activesupport/test/cache/local_cache_middleware_test.rb +++ b/activesupport/test/cache/local_cache_middleware_test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "abstract_unit" require "active_support/cache" diff --git a/activesupport/test/cache/stores/file_store_test.rb b/activesupport/test/cache/stores/file_store_test.rb index 48b304fe6e..66231b0a82 100644 --- a/activesupport/test/cache/stores/file_store_test.rb +++ b/activesupport/test/cache/stores/file_store_test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "abstract_unit" require "active_support/cache" require_relative "../behaviors" @@ -116,6 +118,7 @@ class FileStoreTest < ActiveSupport::TestCase assert_not @cache.exist?("foo") assert @cache.exist?("baz") assert @cache.exist?("quux") + assert_equal 2, Dir.glob(File.join(cache_dir, "**")).size end end diff --git a/activesupport/test/cache/stores/mem_cache_store_test.rb b/activesupport/test/cache/stores/mem_cache_store_test.rb index 2dd5264818..99624caf8a 100644 --- a/activesupport/test/cache/stores/mem_cache_store_test.rb +++ b/activesupport/test/cache/stores/mem_cache_store_test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "abstract_unit" require "active_support/cache" require_relative "../behaviors" @@ -22,7 +24,7 @@ class MemCacheStoreTest < ActiveSupport::TestCase @data = @cache.instance_variable_get(:@data) @cache.clear @cache.silence! - @cache.logger = ActiveSupport::Logger.new("/dev/null") + @cache.logger = ActiveSupport::Logger.new(File::NULL) end include CacheStoreBehavior @@ -55,6 +57,22 @@ class MemCacheStoreTest < ActiveSupport::TestCase end end + def test_increment_expires_in + cache = ActiveSupport::Cache.lookup_store(:mem_cache_store, raw: true) + cache.clear + assert_called_with cache.instance_variable_get(:@data), :incr, [ "foo", 1, 60 ] do + cache.increment("foo", 1, expires_in: 60) + end + end + + def test_decrement_expires_in + cache = ActiveSupport::Cache.lookup_store(:mem_cache_store, raw: true) + cache.clear + assert_called_with cache.instance_variable_get(:@data), :decr, [ "foo", 1, 60 ] do + cache.decrement("foo", 1, expires_in: 60) + end + end + def test_local_cache_raw_values_with_marshal cache = ActiveSupport::Cache.lookup_store(:mem_cache_store, raw: true) cache.clear diff --git a/activesupport/test/cache/stores/memory_store_test.rb b/activesupport/test/cache/stores/memory_store_test.rb index 3dd1646d56..3981f05331 100644 --- a/activesupport/test/cache/stores/memory_store_test.rb +++ b/activesupport/test/cache/stores/memory_store_test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "abstract_unit" require "active_support/cache" require_relative "../behaviors" diff --git a/activesupport/test/cache/stores/null_store_test.rb b/activesupport/test/cache/stores/null_store_test.rb index 23c4e64ee4..a891cbffc8 100644 --- a/activesupport/test/cache/stores/null_store_test.rb +++ b/activesupport/test/cache/stores/null_store_test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "abstract_unit" require "active_support/cache" require_relative "../behaviors" diff --git a/activesupport/test/cache/stores/redis_cache_store_test.rb b/activesupport/test/cache/stores/redis_cache_store_test.rb new file mode 100644 index 0000000000..7f684f7a0f --- /dev/null +++ b/activesupport/test/cache/stores/redis_cache_store_test.rb @@ -0,0 +1,151 @@ +# frozen_string_literal: true + +require "abstract_unit" +require "active_support/cache" +require "active_support/cache/redis_cache_store" +require_relative "../behaviors" + +module ActiveSupport::Cache::RedisCacheStoreTests + class LookupTest < ActiveSupport::TestCase + test "may be looked up as :redis_cache_store" do + assert_kind_of ActiveSupport::Cache::RedisCacheStore, + ActiveSupport::Cache.lookup_store(:redis_cache_store) + end + end + + class InitializationTest < ActiveSupport::TestCase + test "omitted URL uses Redis client with default settings" do + assert_called_with Redis, :new, [ + url: nil, + connect_timeout: 20, read_timeout: 1, write_timeout: 1, + reconnect_attempts: 0, + ] do + build + end + end + + test "no URLs uses Redis client with default settings" do + assert_called_with Redis, :new, [ + url: nil, + connect_timeout: 20, read_timeout: 1, write_timeout: 1, + reconnect_attempts: 0, + ] do + build url: [] + end + end + + test "singular URL uses Redis client" do + assert_called_with Redis, :new, [ + url: "redis://localhost:6379/0", + connect_timeout: 20, read_timeout: 1, write_timeout: 1, + reconnect_attempts: 0, + ] do + build url: "redis://localhost:6379/0" + end + end + + test "one URL uses Redis client" do + assert_called_with Redis, :new, [ + url: "redis://localhost:6379/0", + connect_timeout: 20, read_timeout: 1, write_timeout: 1, + reconnect_attempts: 0, + ] do + build url: %w[ redis://localhost:6379/0 ] + end + end + + test "multiple URLs uses Redis::Distributed client" do + assert_called_with Redis, :new, [ + [ url: "redis://localhost:6379/0", + connect_timeout: 20, read_timeout: 1, write_timeout: 1, + reconnect_attempts: 0 ], + [ url: "redis://localhost:6379/1", + connect_timeout: 20, read_timeout: 1, write_timeout: 1, + reconnect_attempts: 0 ], + ], returns: Redis.new do + @cache = build url: %w[ redis://localhost:6379/0 redis://localhost:6379/1 ] + assert_kind_of ::Redis::Distributed, @cache.redis + end + end + + test "block argument uses yielded client" do + block = -> { :custom_redis_client } + assert_called block, :call do + build redis: block + end + end + + private + def build(**kwargs) + ActiveSupport::Cache::RedisCacheStore.new(**kwargs).tap do |cache| + cache.redis + end + end + end + + class StoreTest < ActiveSupport::TestCase + setup do + @namespace = "namespace" + + @cache = ActiveSupport::Cache::RedisCacheStore.new(timeout: 0.1, namespace: @namespace, expires_in: 60) + # @cache.logger = Logger.new($stdout) # For test debugging + + # For LocalCacheBehavior tests + @peek = ActiveSupport::Cache::RedisCacheStore.new(timeout: 0.1, namespace: @namespace) + end + + teardown do + @cache.clear + @cache.redis.disconnect! + end + end + + class RedisCacheStoreCommonBehaviorTest < StoreTest + include CacheStoreBehavior + include CacheStoreVersionBehavior + include LocalCacheBehavior + include CacheIncrementDecrementBehavior + include AutoloadingCacheBehavior + end + + # Separate test class so we can omit the namespace which causes expected, + # appropriate complaints about incompatible string encodings. + class KeyEncodingSafetyTest < StoreTest + include EncodedKeyCacheBehavior + + setup do + @cache = ActiveSupport::Cache::RedisCacheStore.new(timeout: 0.1) + @cache.logger = nil + end + end + + class StoreAPITest < StoreTest + end + + class FailureSafetyTest < StoreTest + test "fetch read failure returns nil" do + end + + test "fetch read failure does not attempt to write" do + end + + test "write failure returns nil" do + end + end + + class DeleteMatchedTest < StoreTest + test "deletes keys matching glob" do + @cache.write("foo", "bar") + @cache.write("fu", "baz") + @cache.delete_matched("foo*") + assert !@cache.exist?("foo") + assert @cache.exist?("fu") + end + + test "fails with regexp matchers" do + assert_raise ArgumentError do + @cache.delete_matched(/OO/i) + end + end + end +end diff --git a/activesupport/test/callback_inheritance_test.rb b/activesupport/test/callback_inheritance_test.rb index 9e2f7527e0..67813a749e 100644 --- a/activesupport/test/callback_inheritance_test.rb +++ b/activesupport/test/callback_inheritance_test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "abstract_unit" class GrandParent diff --git a/activesupport/test/callbacks_test.rb b/activesupport/test/callbacks_test.rb index 4f00afb581..30f1632460 100644 --- a/activesupport/test/callbacks_test.rb +++ b/activesupport/test/callbacks_test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "abstract_unit" module CallbacksTest @@ -75,7 +77,7 @@ module CallbacksTest skip_callback :save, :after, :after_save_method, unless: :yes skip_callback :save, :after, :after_save_method, if: :no skip_callback :save, :before, :before_save_method, unless: :no - skip_callback :save, :before, CallbackClass , if: :yes + skip_callback :save, :before, CallbackClass, if: :yes def yes; true; end def no; false; end end @@ -191,13 +193,6 @@ module CallbacksTest before_save Proc.new { |r| r.history << "b00m" }, if: :no before_save Proc.new { |r| r.history << [:before_save, :symbol] }, unless: :no before_save Proc.new { |r| r.history << "b00m" }, unless: :yes - # string - ActiveSupport::Deprecation.silence do - before_save Proc.new { |r| r.history << [:before_save, :string] }, if: "yes" - before_save Proc.new { |r| r.history << "b00m" }, if: "no" - before_save Proc.new { |r| r.history << [:before_save, :string] }, unless: "no" - before_save Proc.new { |r| r.history << "b00m" }, unless: "yes" - end # Combined if and unless before_save Proc.new { |r| r.history << [:before_save, :combined_symbol] }, if: :yes, unless: :no before_save Proc.new { |r| r.history << "b00m" }, if: :yes, unless: :yes @@ -590,8 +585,6 @@ module CallbacksTest [:before_save, :proc], [:before_save, :symbol], [:before_save, :symbol], - [:before_save, :string], - [:before_save, :string], [:before_save, :combined_symbol], ], person.history end @@ -1180,14 +1173,15 @@ module CallbacksTest end end - class DeprecatedWarningTest < ActiveSupport::TestCase - def test_deprecate_string_conditional_options + class NotSupportedStringConditionalTest < ActiveSupport::TestCase + def test_string_conditional_options klass = Class.new(Record) - assert_deprecated { klass.before_save :tweedle, if: "true" } - assert_deprecated { klass.after_save :tweedle, unless: "false" } - assert_deprecated { klass.skip_callback :save, :before, :tweedle, if: "true" } - assert_deprecated { klass.skip_callback :save, :after, :tweedle, unless: "false" } + assert_raises(ArgumentError) { klass.before_save :tweedle, if: ["true"] } + assert_raises(ArgumentError) { klass.before_save :tweedle, if: "true" } + assert_raises(ArgumentError) { klass.after_save :tweedle, unless: "false" } + assert_raises(ArgumentError) { klass.skip_callback :save, :before, :tweedle, if: "true" } + assert_raises(ArgumentError) { klass.skip_callback :save, :after, :tweedle, unless: "false" } end end diff --git a/activesupport/test/class_cache_test.rb b/activesupport/test/class_cache_test.rb index 004b4dc9ce..7b97028e8c 100644 --- a/activesupport/test/class_cache_test.rb +++ b/activesupport/test/class_cache_test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "abstract_unit" require "active_support/dependencies" diff --git a/activesupport/test/clean_backtrace_test.rb b/activesupport/test/clean_backtrace_test.rb index 5ed518cdb0..1b44c7c9bf 100644 --- a/activesupport/test/clean_backtrace_test.rb +++ b/activesupport/test/clean_backtrace_test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "abstract_unit" class BacktraceCleanerFilterTest < ActiveSupport::TestCase @@ -8,8 +10,8 @@ class BacktraceCleanerFilterTest < ActiveSupport::TestCase test "backtrace should filter all lines in a backtrace, removing prefixes" do assert_equal \ - ["/my/class.rb", "/my/module.rb"], - @bc.clean(["/my/prefix/my/class.rb", "/my/prefix/my/module.rb"]) + ["/my/class.rb", "/my/module.rb"], + @bc.clean(["/my/prefix/my/class.rb", "/my/prefix/my/module.rb"]) end test "backtrace cleaner should allow removing filters" do diff --git a/activesupport/test/clean_logger_test.rb b/activesupport/test/clean_logger_test.rb index cf37fc5639..6d8f7064ce 100644 --- a/activesupport/test/clean_logger_test.rb +++ b/activesupport/test/clean_logger_test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "abstract_unit" require "stringio" require "active_support/logger" diff --git a/activesupport/test/concern_test.rb b/activesupport/test/concern_test.rb index 7a5a5414a7..ef75a320d1 100644 --- a/activesupport/test/concern_test.rb +++ b/activesupport/test/concern_test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "abstract_unit" require "active_support/concern" diff --git a/activesupport/test/concurrency/load_interlock_aware_monitor_test.rb b/activesupport/test/concurrency/load_interlock_aware_monitor_test.rb new file mode 100644 index 0000000000..2d0f45ec5f --- /dev/null +++ b/activesupport/test/concurrency/load_interlock_aware_monitor_test.rb @@ -0,0 +1,55 @@ +# frozen_string_literal: true + +require "abstract_unit" +require "concurrent/atomic/count_down_latch" +require "active_support/concurrency/load_interlock_aware_monitor" + +module ActiveSupport + module Concurrency + class LoadInterlockAwareMonitorTest < ActiveSupport::TestCase + def setup + @monitor = ActiveSupport::Concurrency::LoadInterlockAwareMonitor.new + end + + def test_entering_with_no_blocking + assert @monitor.mon_enter + end + + def test_entering_with_blocking + load_interlock_latch = Concurrent::CountDownLatch.new + monitor_latch = Concurrent::CountDownLatch.new + + able_to_use_monitor = false + able_to_load = false + + thread_with_load_interlock = Thread.new do + ActiveSupport::Dependencies.interlock.running do + load_interlock_latch.count_down + monitor_latch.wait + + @monitor.synchronize do + able_to_use_monitor = true + end + end + end + + thread_with_monitor_lock = Thread.new do + @monitor.synchronize do + monitor_latch.count_down + load_interlock_latch.wait + + ActiveSupport::Dependencies.interlock.loading do + able_to_load = true + end + end + end + + thread_with_load_interlock.join + thread_with_monitor_lock.join + + assert able_to_use_monitor + assert able_to_load + end + end + end +end diff --git a/activesupport/test/configurable_test.rb b/activesupport/test/configurable_test.rb index 3cd6d2d4d0..10719596df 100644 --- a/activesupport/test/configurable_test.rb +++ b/activesupport/test/configurable_test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "abstract_unit" require "active_support/configurable" diff --git a/activesupport/test/constantize_test_cases.rb b/activesupport/test/constantize_test_cases.rb index 32b720bcbb..2c6145940b 100644 --- a/activesupport/test/constantize_test_cases.rb +++ b/activesupport/test/constantize_test_cases.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "dependencies_test_helpers" module Ace diff --git a/activesupport/test/core_ext/array/access_test.rb b/activesupport/test/core_ext/array/access_test.rb index a38ea36d00..8c217023cf 100644 --- a/activesupport/test/core_ext/array/access_test.rb +++ b/activesupport/test/core_ext/array/access_test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "abstract_unit" require "active_support/core_ext/array" diff --git a/activesupport/test/core_ext/array/conversions_test.rb b/activesupport/test/core_ext/array/conversions_test.rb index bbe81ae70c..0a7c43d421 100644 --- a/activesupport/test/core_ext/array/conversions_test.rb +++ b/activesupport/test/core_ext/array/conversions_test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "abstract_unit" require "active_support/core_ext/array" require "active_support/core_ext/big_decimal" @@ -88,7 +90,7 @@ class ToXmlTest < ActiveSupport::TestCase def test_to_xml_with_hash_elements xml = [ { name: "David", age: 26, age_in_millis: 820497600000 }, - { name: "Jason", age: 31, age_in_millis: BigDecimal.new("1.0") } + { name: "Jason", age: 31, age_in_millis: BigDecimal("1.0") } ].to_xml(skip_instruct: true, indent: 0) assert_equal '<objects type="array"><object>', xml.first(30) @@ -171,7 +173,7 @@ class ToXmlTest < ActiveSupport::TestCase def test_to_xml_with_instruct xml = [ { name: "David", age: 26, age_in_millis: 820497600000 }, - { name: "Jason", age: 31, age_in_millis: BigDecimal.new("1.0") } + { name: "Jason", age: 31, age_in_millis: BigDecimal("1.0") } ].to_xml(skip_instruct: false, indent: 0) assert_match(/^<\?xml [^>]*/, xml) @@ -181,7 +183,7 @@ class ToXmlTest < ActiveSupport::TestCase def test_to_xml_with_block xml = [ { name: "David", age: 26, age_in_millis: 820497600000 }, - { name: "Jason", age: 31, age_in_millis: BigDecimal.new("1.0") } + { name: "Jason", age: 31, age_in_millis: BigDecimal("1.0") } ].to_xml(skip_instruct: true, indent: 0) do |builder| builder.count 2 end diff --git a/activesupport/test/core_ext/array/extract_options_test.rb b/activesupport/test/core_ext/array/extract_options_test.rb index 1651bee0f6..7a4b15cd71 100644 --- a/activesupport/test/core_ext/array/extract_options_test.rb +++ b/activesupport/test/core_ext/array/extract_options_test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "abstract_unit" require "active_support/core_ext/array" require "active_support/core_ext/hash" diff --git a/activesupport/test/core_ext/array/grouping_test.rb b/activesupport/test/core_ext/array/grouping_test.rb index 4c6aadba8c..c182b91826 100644 --- a/activesupport/test/core_ext/array/grouping_test.rb +++ b/activesupport/test/core_ext/array/grouping_test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "abstract_unit" require "active_support/core_ext/array" @@ -114,7 +116,7 @@ class SplitTest < ActiveSupport::TestCase def test_split_with_block a = (1..10).to_a assert_equal [[1, 2], [4, 5], [7, 8], [10]], a.split { |i| i % 3 == 0 } - assert_equal [1, 2, 3, 4, 5, 6, 7, 8, 9 , 10], a + assert_equal [1, 2, 3, 4, 5, 6, 7, 8, 9, 10], a end def test_split_with_edge_values diff --git a/activesupport/test/core_ext/array/prepend_append_test.rb b/activesupport/test/core_ext/array/prepend_append_test.rb index 763e26191d..c34acd66ad 100644 --- a/activesupport/test/core_ext/array/prepend_append_test.rb +++ b/activesupport/test/core_ext/array/prepend_append_test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "abstract_unit" require "active_support/core_ext/array" diff --git a/activesupport/test/core_ext/array/wrap_test.rb b/activesupport/test/core_ext/array/wrap_test.rb index ae846cb3f2..46564b4d73 100644 --- a/activesupport/test/core_ext/array/wrap_test.rb +++ b/activesupport/test/core_ext/array/wrap_test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "abstract_unit" require "active_support/core_ext/array" diff --git a/activesupport/test/core_ext/bigdecimal_test.rb b/activesupport/test/core_ext/bigdecimal_test.rb index 43b659546f..62588be33b 100644 --- a/activesupport/test/core_ext/bigdecimal_test.rb +++ b/activesupport/test/core_ext/bigdecimal_test.rb @@ -1,9 +1,11 @@ +# frozen_string_literal: true + require "abstract_unit" require "active_support/core_ext/big_decimal" class BigDecimalTest < ActiveSupport::TestCase def test_to_s - bd = BigDecimal.new "0.01" + bd = BigDecimal "0.01" assert_equal "0.01", bd.to_s assert_equal "+0.01", bd.to_s("+F") assert_equal "+0.0 1", bd.to_s("+1F") diff --git a/activesupport/test/core_ext/class/attribute_test.rb b/activesupport/test/core_ext/class/attribute_test.rb index f16043c612..be6ad82367 100644 --- a/activesupport/test/core_ext/class/attribute_test.rb +++ b/activesupport/test/core_ext/class/attribute_test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "abstract_unit" require "active_support/core_ext/class/attribute" diff --git a/activesupport/test/core_ext/class_test.rb b/activesupport/test/core_ext/class_test.rb index a7905196ae..9cc006fc63 100644 --- a/activesupport/test/core_ext/class_test.rb +++ b/activesupport/test/core_ext/class_test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "abstract_unit" require "active_support/core_ext/class" require "set" diff --git a/activesupport/test/core_ext/date_and_time_behavior.rb b/activesupport/test/core_ext/date_and_time_behavior.rb index 6c77e8f313..1176ed647a 100644 --- a/activesupport/test/core_ext/date_and_time_behavior.rb +++ b/activesupport/test/core_ext/date_and_time_behavior.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "abstract_unit" module DateAndTimeBehavior @@ -7,6 +9,11 @@ module DateAndTimeBehavior end def test_prev_day + assert_equal date_time_init(2005, 2, 24, 10, 10, 10), date_time_init(2005, 2, 22, 10, 10, 10).prev_day(-2) + assert_equal date_time_init(2005, 2, 23, 10, 10, 10), date_time_init(2005, 2, 22, 10, 10, 10).prev_day(-1) + assert_equal date_time_init(2005, 2, 22, 10, 10, 10), date_time_init(2005, 2, 22, 10, 10, 10).prev_day(0) + assert_equal date_time_init(2005, 2, 21, 10, 10, 10), date_time_init(2005, 2, 22, 10, 10, 10).prev_day(1) + assert_equal date_time_init(2005, 2, 20, 10, 10, 10), date_time_init(2005, 2, 22, 10, 10, 10).prev_day(2) assert_equal date_time_init(2005, 2, 21, 10, 10, 10), date_time_init(2005, 2, 22, 10, 10, 10).prev_day assert_equal date_time_init(2005, 2, 28, 10, 10, 10), date_time_init(2005, 3, 2, 10, 10, 10).prev_day.prev_day end @@ -17,6 +24,11 @@ module DateAndTimeBehavior end def test_next_day + assert_equal date_time_init(2005, 2, 20, 10, 10, 10), date_time_init(2005, 2, 22, 10, 10, 10).next_day(-2) + assert_equal date_time_init(2005, 2, 21, 10, 10, 10), date_time_init(2005, 2, 22, 10, 10, 10).next_day(-1) + assert_equal date_time_init(2005, 2, 22, 10, 10, 10), date_time_init(2005, 2, 22, 10, 10, 10).next_day(0) + assert_equal date_time_init(2005, 2, 23, 10, 10, 10), date_time_init(2005, 2, 22, 10, 10, 10).next_day(1) + assert_equal date_time_init(2005, 2, 24, 10, 10, 10), date_time_init(2005, 2, 22, 10, 10, 10).next_day(2) assert_equal date_time_init(2005, 2, 23, 10, 10, 10), date_time_init(2005, 2, 22, 10, 10, 10).next_day assert_equal date_time_init(2005, 3, 2, 10, 10, 10), date_time_init(2005, 2, 28, 10, 10, 10).next_day.next_day end @@ -149,6 +161,16 @@ module DateAndTimeBehavior assert_equal date_time_init(2015, 1, 5, 15, 15, 10), date_time_init(2015, 1, 3, 15, 15, 10).next_weekday end + def test_next_month + assert_equal date_time_init(2004, 12, 22, 10, 10, 10), date_time_init(2005, 2, 22, 10, 10, 10).next_month(-2) + assert_equal date_time_init(2005, 1, 22, 10, 10, 10), date_time_init(2005, 2, 22, 10, 10, 10).next_month(-1) + assert_equal date_time_init(2005, 2, 22, 10, 10, 10), date_time_init(2005, 2, 22, 10, 10, 10).next_month(0) + assert_equal date_time_init(2005, 3, 22, 10, 10, 10), date_time_init(2005, 2, 22, 10, 10, 10).next_month(1) + assert_equal date_time_init(2005, 4, 22, 10, 10, 10), date_time_init(2005, 2, 22, 10, 10, 10).next_month(2) + assert_equal date_time_init(2005, 3, 22, 10, 10, 10), date_time_init(2005, 2, 22, 10, 10, 10).next_month + assert_equal date_time_init(2005, 4, 22, 10, 10, 10), date_time_init(2005, 2, 22, 10, 10, 10).next_month.next_month + end + def test_next_month_on_31st assert_equal date_time_init(2005, 9, 30, 15, 15, 10), date_time_init(2005, 8, 31, 15, 15, 10).next_month end @@ -158,7 +180,13 @@ module DateAndTimeBehavior end def test_next_year + assert_equal date_time_init(2003, 6, 5, 10, 10, 10), date_time_init(2005, 6, 5, 10, 10, 10).next_year(-2) + assert_equal date_time_init(2004, 6, 5, 10, 10, 10), date_time_init(2005, 6, 5, 10, 10, 10).next_year(-1) + assert_equal date_time_init(2005, 6, 5, 10, 10, 10), date_time_init(2005, 6, 5, 10, 10, 10).next_year(0) + assert_equal date_time_init(2006, 6, 5, 10, 10, 10), date_time_init(2005, 6, 5, 10, 10, 10).next_year(1) + assert_equal date_time_init(2007, 6, 5, 10, 10, 10), date_time_init(2005, 6, 5, 10, 10, 10).next_year(2) assert_equal date_time_init(2006, 6, 5, 10, 10, 10), date_time_init(2005, 6, 5, 10, 10, 10).next_year + assert_equal date_time_init(2007, 6, 5, 10, 10, 10), date_time_init(2005, 6, 5, 10, 10, 10).next_year.next_year end def test_prev_week @@ -201,6 +229,16 @@ module DateAndTimeBehavior assert_equal date_time_init(2015, 1, 2, 15, 15, 10), date_time_init(2015, 1, 4, 15, 15, 10).prev_weekday end + def test_prev_month + assert_equal date_time_init(2005, 4, 22, 10, 10, 10), date_time_init(2005, 2, 22, 10, 10, 10).prev_month(-2) + assert_equal date_time_init(2005, 3, 22, 10, 10, 10), date_time_init(2005, 2, 22, 10, 10, 10).prev_month(-1) + assert_equal date_time_init(2005, 2, 22, 10, 10, 10), date_time_init(2005, 2, 22, 10, 10, 10).prev_month(0) + assert_equal date_time_init(2005, 1, 22, 10, 10, 10), date_time_init(2005, 2, 22, 10, 10, 10).prev_month(1) + assert_equal date_time_init(2004, 12, 22, 10, 10, 10), date_time_init(2005, 2, 22, 10, 10, 10).prev_month(2) + assert_equal date_time_init(2005, 1, 22, 10, 10, 10), date_time_init(2005, 2, 22, 10, 10, 10).prev_month + assert_equal date_time_init(2004, 12, 22, 10, 10, 10), date_time_init(2005, 2, 22, 10, 10, 10).prev_month.prev_month + end + def test_prev_month_on_31st assert_equal date_time_init(2004, 2, 29, 10, 10, 10), date_time_init(2004, 3, 31, 10, 10, 10).prev_month end @@ -210,7 +248,21 @@ module DateAndTimeBehavior end def test_prev_year + assert_equal date_time_init(2007, 6, 5, 10, 10, 10), date_time_init(2005, 6, 5, 10, 10, 10).prev_year(-2) + assert_equal date_time_init(2006, 6, 5, 10, 10, 10), date_time_init(2005, 6, 5, 10, 10, 10).prev_year(-1) + assert_equal date_time_init(2005, 6, 5, 10, 10, 10), date_time_init(2005, 6, 5, 10, 10, 10).prev_year(0) + assert_equal date_time_init(2004, 6, 5, 10, 10, 10), date_time_init(2005, 6, 5, 10, 10, 10).prev_year(1) + assert_equal date_time_init(2003, 6, 5, 10, 10, 10), date_time_init(2005, 6, 5, 10, 10, 10).prev_year(2) assert_equal date_time_init(2004, 6, 5, 10, 10, 10), date_time_init(2005, 6, 5, 10, 10, 10).prev_year + assert_equal date_time_init(2003, 6, 5, 10, 10, 10), date_time_init(2005, 6, 5, 10, 10, 10).prev_year.prev_year + end + + def test_last_month_on_31st + assert_equal date_time_init(2004, 2, 29, 0, 0, 0), date_time_init(2004, 3, 31, 0, 0, 0).last_month + end + + def test_last_year + assert_equal date_time_init(2004, 6, 5, 10, 0, 0), date_time_init(2005, 6, 5, 10, 0, 0).last_year end def test_days_to_week_start @@ -245,24 +297,24 @@ module DateAndTimeBehavior def test_beginning_of_week assert_equal date_time_init(2005, 1, 31, 0, 0, 0), date_time_init(2005, 2, 4, 10, 10, 10).beginning_of_week - assert_equal date_time_init(2005, 11, 28, 0, 0, 0), date_time_init(2005, 11, 28, 0, 0, 0).beginning_of_week #monday - assert_equal date_time_init(2005, 11, 28, 0, 0, 0), date_time_init(2005, 11, 29, 0, 0, 0).beginning_of_week #tuesday - assert_equal date_time_init(2005, 11, 28, 0, 0, 0), date_time_init(2005, 11, 30, 0, 0, 0).beginning_of_week #wednesday - assert_equal date_time_init(2005, 11, 28, 0, 0, 0), date_time_init(2005, 12, 01, 0, 0, 0).beginning_of_week #thursday - assert_equal date_time_init(2005, 11, 28, 0, 0, 0), date_time_init(2005, 12, 02, 0, 0, 0).beginning_of_week #friday - assert_equal date_time_init(2005, 11, 28, 0, 0, 0), date_time_init(2005, 12, 03, 0, 0, 0).beginning_of_week #saturday - assert_equal date_time_init(2005, 11, 28, 0, 0, 0), date_time_init(2005, 12, 04, 0, 0, 0).beginning_of_week #sunday + assert_equal date_time_init(2005, 11, 28, 0, 0, 0), date_time_init(2005, 11, 28, 0, 0, 0).beginning_of_week # monday + assert_equal date_time_init(2005, 11, 28, 0, 0, 0), date_time_init(2005, 11, 29, 0, 0, 0).beginning_of_week # tuesday + assert_equal date_time_init(2005, 11, 28, 0, 0, 0), date_time_init(2005, 11, 30, 0, 0, 0).beginning_of_week # wednesday + assert_equal date_time_init(2005, 11, 28, 0, 0, 0), date_time_init(2005, 12, 01, 0, 0, 0).beginning_of_week # thursday + assert_equal date_time_init(2005, 11, 28, 0, 0, 0), date_time_init(2005, 12, 02, 0, 0, 0).beginning_of_week # friday + assert_equal date_time_init(2005, 11, 28, 0, 0, 0), date_time_init(2005, 12, 03, 0, 0, 0).beginning_of_week # saturday + assert_equal date_time_init(2005, 11, 28, 0, 0, 0), date_time_init(2005, 12, 04, 0, 0, 0).beginning_of_week # sunday end def test_end_of_week assert_equal date_time_init(2008, 1, 6, 23, 59, 59, Rational(999999999, 1000)), date_time_init(2007, 12, 31, 10, 10, 10).end_of_week - assert_equal date_time_init(2007, 9, 2, 23, 59, 59, Rational(999999999, 1000)), date_time_init(2007, 8, 27, 0, 0, 0).end_of_week #monday - assert_equal date_time_init(2007, 9, 2, 23, 59, 59, Rational(999999999, 1000)), date_time_init(2007, 8, 28, 0, 0, 0).end_of_week #tuesday - assert_equal date_time_init(2007, 9, 2, 23, 59, 59, Rational(999999999, 1000)), date_time_init(2007, 8, 29, 0, 0, 0).end_of_week #wednesday - assert_equal date_time_init(2007, 9, 2, 23, 59, 59, Rational(999999999, 1000)), date_time_init(2007, 8, 30, 0, 0, 0).end_of_week #thursday - assert_equal date_time_init(2007, 9, 2, 23, 59, 59, Rational(999999999, 1000)), date_time_init(2007, 8, 31, 0, 0, 0).end_of_week #friday - assert_equal date_time_init(2007, 9, 2, 23, 59, 59, Rational(999999999, 1000)), date_time_init(2007, 9, 01, 0, 0, 0).end_of_week #saturday - assert_equal date_time_init(2007, 9, 2, 23, 59, 59, Rational(999999999, 1000)), date_time_init(2007, 9, 02, 0, 0, 0).end_of_week #sunday + assert_equal date_time_init(2007, 9, 2, 23, 59, 59, Rational(999999999, 1000)), date_time_init(2007, 8, 27, 0, 0, 0).end_of_week # monday + assert_equal date_time_init(2007, 9, 2, 23, 59, 59, Rational(999999999, 1000)), date_time_init(2007, 8, 28, 0, 0, 0).end_of_week # tuesday + assert_equal date_time_init(2007, 9, 2, 23, 59, 59, Rational(999999999, 1000)), date_time_init(2007, 8, 29, 0, 0, 0).end_of_week # wednesday + assert_equal date_time_init(2007, 9, 2, 23, 59, 59, Rational(999999999, 1000)), date_time_init(2007, 8, 30, 0, 0, 0).end_of_week # thursday + assert_equal date_time_init(2007, 9, 2, 23, 59, 59, Rational(999999999, 1000)), date_time_init(2007, 8, 31, 0, 0, 0).end_of_week # friday + assert_equal date_time_init(2007, 9, 2, 23, 59, 59, Rational(999999999, 1000)), date_time_init(2007, 9, 01, 0, 0, 0).end_of_week # saturday + assert_equal date_time_init(2007, 9, 2, 23, 59, 59, Rational(999999999, 1000)), date_time_init(2007, 9, 02, 0, 0, 0).end_of_week # sunday end def test_end_of_month @@ -276,6 +328,26 @@ module DateAndTimeBehavior assert_equal date_time_init(2007, 12, 31, 23, 59, 59, Rational(999999999, 1000)), date_time_init(2007, 12, 31, 10, 10, 10).end_of_year end + def test_next_occurring + assert_equal date_time_init(2017, 12, 18, 3, 14, 15), date_time_init(2017, 12, 14, 3, 14, 15).next_occurring(:monday) + assert_equal date_time_init(2017, 12, 19, 3, 14, 15), date_time_init(2017, 12, 14, 3, 14, 15).next_occurring(:tuesday) + assert_equal date_time_init(2017, 12, 20, 3, 14, 15), date_time_init(2017, 12, 14, 3, 14, 15).next_occurring(:wednesday) + assert_equal date_time_init(2017, 12, 21, 3, 14, 15), date_time_init(2017, 12, 14, 3, 14, 15).next_occurring(:thursday) + assert_equal date_time_init(2017, 12, 15, 3, 14, 15), date_time_init(2017, 12, 14, 3, 14, 15).next_occurring(:friday) + assert_equal date_time_init(2017, 12, 16, 3, 14, 15), date_time_init(2017, 12, 14, 3, 14, 15).next_occurring(:saturday) + assert_equal date_time_init(2017, 12, 17, 3, 14, 15), date_time_init(2017, 12, 14, 3, 14, 15).next_occurring(:sunday) + end + + def test_prev_occurring + assert_equal date_time_init(2017, 12, 11, 3, 14, 15), date_time_init(2017, 12, 14, 3, 14, 15).prev_occurring(:monday) + assert_equal date_time_init(2017, 12, 12, 3, 14, 15), date_time_init(2017, 12, 14, 3, 14, 15).prev_occurring(:tuesday) + assert_equal date_time_init(2017, 12, 13, 3, 14, 15), date_time_init(2017, 12, 14, 3, 14, 15).prev_occurring(:wednesday) + assert_equal date_time_init(2017, 12, 7, 3, 14, 15), date_time_init(2017, 12, 14, 3, 14, 15).prev_occurring(:thursday) + assert_equal date_time_init(2017, 12, 8, 3, 14, 15), date_time_init(2017, 12, 14, 3, 14, 15).prev_occurring(:friday) + assert_equal date_time_init(2017, 12, 9, 3, 14, 15), date_time_init(2017, 12, 14, 3, 14, 15).prev_occurring(:saturday) + assert_equal date_time_init(2017, 12, 10, 3, 14, 15), date_time_init(2017, 12, 14, 3, 14, 15).prev_occurring(:sunday) + end + def test_monday_with_default_beginning_of_week_set with_bw_default(:saturday) do assert_equal date_time_init(2012, 9, 17, 0, 0, 0), date_time_init(2012, 9, 18, 0, 0, 0).monday diff --git a/activesupport/test/core_ext/date_and_time_compatibility_test.rb b/activesupport/test/core_ext/date_and_time_compatibility_test.rb index 6c6205a4d2..266829a452 100644 --- a/activesupport/test/core_ext/date_and_time_compatibility_test.rb +++ b/activesupport/test/core_ext/date_and_time_compatibility_test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "abstract_unit" require "active_support/time" require "time_zone_test_helpers" diff --git a/activesupport/test/core_ext/date_ext_test.rb b/activesupport/test/core_ext/date_ext_test.rb index 50bb1004f7..23d17956df 100644 --- a/activesupport/test/core_ext/date_ext_test.rb +++ b/activesupport/test/core_ext/date_ext_test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "abstract_unit" require "active_support/time" require "core_ext/date_and_time_behavior" @@ -93,11 +95,11 @@ class DateExtCalculationsTest < ActiveSupport::TestCase end def test_beginning_of_week_in_calendar_reform - assert_equal Date.new(1582, 10, 1), Date.new(1582, 10, 15).beginning_of_week #friday + assert_equal Date.new(1582, 10, 1), Date.new(1582, 10, 15).beginning_of_week # friday end def test_end_of_week_in_calendar_reform - assert_equal Date.new(1582, 10, 17), Date.new(1582, 10, 4).end_of_week #thursday + assert_equal Date.new(1582, 10, 17), Date.new(1582, 10, 4).end_of_week # thursday end def test_end_of_year @@ -118,10 +120,6 @@ class DateExtCalculationsTest < ActiveSupport::TestCase assert_equal Date.new(1582, 10, 4), Date.new(1583, 10, 14).prev_year end - def test_last_year - assert_equal Date.new(2004, 6, 5), Date.new(2005, 6, 5).last_year - end - def test_last_year_in_leap_years assert_equal Date.new(1999, 2, 28), Date.new(2000, 2, 29).last_year end @@ -146,7 +144,7 @@ class DateExtCalculationsTest < ActiveSupport::TestCase assert_equal Date.new(2012, 9, 28), Date.new(2005, 2, 28).advance(years: 7, months: 7) assert_equal Date.new(2013, 10, 3), Date.new(2005, 2, 28).advance(years: 7, months: 19, days: 5) assert_equal Date.new(2013, 10, 17), Date.new(2005, 2, 28).advance(years: 7, months: 19, weeks: 2, days: 5) - assert_equal Date.new(2005, 2, 28), Date.new(2004, 2, 29).advance(years: 1) #leap day plus one year + assert_equal Date.new(2005, 2, 28), Date.new(2004, 2, 29).advance(years: 1) # leap day plus one year end def test_advance_does_first_years_and_then_days @@ -183,10 +181,6 @@ class DateExtCalculationsTest < ActiveSupport::TestCase assert_equal Date.new(1582, 10, 18), Date.new(1582, 10, 4).next_week end - def test_last_month_on_31st - assert_equal Date.new(2004, 2, 29), Date.new(2004, 3, 31).last_month - end - def test_last_quarter_on_31st assert_equal Date.new(2004, 2, 29), Date.new(2004, 5, 31).last_quarter end diff --git a/activesupport/test/core_ext/date_time_ext_test.rb b/activesupport/test/core_ext/date_time_ext_test.rb index 276fa2bfd3..f4c9dfcb25 100644 --- a/activesupport/test/core_ext/date_time_ext_test.rb +++ b/activesupport/test/core_ext/date_time_ext_test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "abstract_unit" require "active_support/time" require "core_ext/date_and_time_behavior" @@ -28,28 +30,6 @@ class DateTimeExtCalculationsTest < ActiveSupport::TestCase end end - def test_next_occur - datetime = DateTime.new(2016, 9, 24, 0, 0) # saturday - assert_equal datetime.next_occurring(:monday), datetime.since(2.days) - assert_equal datetime.next_occurring(:tuesday), datetime.since(3.days) - assert_equal datetime.next_occurring(:wednesday), datetime.since(4.days) - assert_equal datetime.next_occurring(:thursday), datetime.since(5.days) - assert_equal datetime.next_occurring(:friday), datetime.since(6.days) - assert_equal datetime.next_occurring(:saturday), datetime.since(1.week) - assert_equal datetime.next_occurring(:sunday), datetime.since(1.day) - end - - def test_prev_occur - datetime = DateTime.new(2016, 9, 24, 0, 0) # saturday - assert_equal datetime.prev_occurring(:monday), datetime.ago(5.days) - assert_equal datetime.prev_occurring(:tuesday), datetime.ago(4.days) - assert_equal datetime.prev_occurring(:wednesday), datetime.ago(3.days) - assert_equal datetime.prev_occurring(:thursday), datetime.ago(2.days) - assert_equal datetime.prev_occurring(:friday), datetime.ago(1.day) - assert_equal datetime.prev_occurring(:saturday), datetime.ago(1.week) - assert_equal datetime.prev_occurring(:sunday), datetime.ago(6.days) - end - def test_readable_inspect datetime = DateTime.new(2005, 2, 21, 14, 30, 0) assert_equal "Mon, 21 Feb 2005 14:30:00 +0000", datetime.readable_inspect @@ -160,10 +140,6 @@ class DateTimeExtCalculationsTest < ActiveSupport::TestCase assert_equal DateTime.civil(2005, 4, 30, 23, 59, Rational(59999999999, 1000000000)), DateTime.civil(2005, 4, 20, 10, 10, 10).end_of_month end - def test_last_year - assert_equal DateTime.civil(2004, 6, 5, 10), DateTime.civil(2005, 6, 5, 10, 0, 0).last_year - end - def test_ago assert_equal DateTime.civil(2005, 2, 22, 10, 10, 9), DateTime.civil(2005, 2, 22, 10, 10, 10).ago(1) assert_equal DateTime.civil(2005, 2, 22, 9, 10, 10), DateTime.civil(2005, 2, 22, 10, 10, 10).ago(3600) @@ -211,7 +187,7 @@ class DateTimeExtCalculationsTest < ActiveSupport::TestCase assert_equal DateTime.civil(2013, 10, 3, 15, 15, 10), DateTime.civil(2005, 2, 28, 15, 15, 10).advance(years: 7, months: 19, days: 5) assert_equal DateTime.civil(2013, 10, 17, 15, 15, 10), DateTime.civil(2005, 2, 28, 15, 15, 10).advance(years: 7, months: 19, weeks: 2, days: 5) assert_equal DateTime.civil(2001, 12, 27, 15, 15, 10), DateTime.civil(2005, 2, 28, 15, 15, 10).advance(years: -3, months: -2, days: -1) - assert_equal DateTime.civil(2005, 2, 28, 15, 15, 10), DateTime.civil(2004, 2, 29, 15, 15, 10).advance(years: 1) #leap day plus one year + assert_equal DateTime.civil(2005, 2, 28, 15, 15, 10), DateTime.civil(2004, 2, 29, 15, 15, 10).advance(years: 1) # leap day plus one year assert_equal DateTime.civil(2005, 2, 28, 20, 15, 10), DateTime.civil(2005, 2, 28, 15, 15, 10).advance(hours: 5) assert_equal DateTime.civil(2005, 2, 28, 15, 22, 10), DateTime.civil(2005, 2, 28, 15, 15, 10).advance(minutes: 7) assert_equal DateTime.civil(2005, 2, 28, 15, 15, 19), DateTime.civil(2005, 2, 28, 15, 15, 10).advance(seconds: 9) @@ -246,10 +222,6 @@ class DateTimeExtCalculationsTest < ActiveSupport::TestCase assert_equal DateTime.civil(2016, 2, 29), DateTime.civil(2016, 3, 7).last_week end - def test_last_month_on_31st - assert_equal DateTime.civil(2004, 2, 29), DateTime.civil(2004, 3, 31).last_month - end - def test_last_quarter_on_31st assert_equal DateTime.civil(2004, 2, 29), DateTime.civil(2004, 5, 31).last_quarter end diff --git a/activesupport/test/core_ext/digest/uuid_test.rb b/activesupport/test/core_ext/digest/uuid_test.rb index 866a03259a..94cb7d9418 100644 --- a/activesupport/test/core_ext/digest/uuid_test.rb +++ b/activesupport/test/core_ext/digest/uuid_test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "abstract_unit" require "active_support/core_ext/digest/uuid" diff --git a/activesupport/test/core_ext/duration_test.rb b/activesupport/test/core_ext/duration_test.rb index cd1b505c34..4a02f27def 100644 --- a/activesupport/test/core_ext/duration_test.rb +++ b/activesupport/test/core_ext/duration_test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "abstract_unit" require "active_support/inflector" require "active_support/time" @@ -69,6 +71,8 @@ class DurationTest < ActiveSupport::TestCase assert_equal "7 days", 7.days.inspect assert_equal "1 week", 1.week.inspect assert_equal "2 weeks", 1.fortnight.inspect + assert_equal "0 seconds", (10 % 5.seconds).inspect + assert_equal "10 minutes", (10.minutes + 0.seconds).inspect end def test_inspect_locale @@ -109,7 +113,44 @@ class DurationTest < ActiveSupport::TestCase def test_divide assert_equal 1.day, 7.days / 7 assert_instance_of ActiveSupport::Duration, 7.days / 7 + + assert_equal 1.hour, 1.day / 24 + assert_instance_of ActiveSupport::Duration, 1.day / 24 + + assert_equal 24, 86400 / 1.hour + assert_kind_of Integer, 86400 / 1.hour + + assert_equal 24, 1.day / 1.hour + assert_kind_of Integer, 1.day / 1.hour + assert_equal 1, 1.day / 1.day + assert_kind_of Integer, 1.day / 1.hour + end + + def test_modulo + assert_equal 1.minute, 5.minutes % 120 + assert_instance_of ActiveSupport::Duration, 5.minutes % 120 + + assert_equal 1.minute, 5.minutes % 2.minutes + assert_instance_of ActiveSupport::Duration, 5.minutes % 2.minutes + + assert_equal 1.minute, 5.minutes % 120.seconds + assert_instance_of ActiveSupport::Duration, 5.minutes % 120.seconds + + assert_equal 5.minutes, 5.minutes % 1.hour + assert_instance_of ActiveSupport::Duration, 5.minutes % 1.hour + + assert_equal 1.day, 36.days % 604800 + assert_instance_of ActiveSupport::Duration, 36.days % 604800 + + assert_equal 1.day, 36.days % 7.days + assert_instance_of ActiveSupport::Duration, 36.days % 7.days + + assert_equal 800.seconds, 8000 % 1.hour + assert_instance_of ActiveSupport::Duration, 8000 % 1.hour + + assert_equal 1.month, 13.months % 1.year + assert_instance_of ActiveSupport::Duration, 13.months % 1.year end def test_date_added_with_multiplied_duration @@ -121,7 +162,7 @@ class DurationTest < ActiveSupport::TestCase end def test_time_plus_duration_returns_same_time_datatype - twz = ActiveSupport::TimeWithZone.new(nil, ActiveSupport::TimeZone["Moscow"] , Time.utc(2016, 4, 28, 00, 45)) + twz = ActiveSupport::TimeWithZone.new(nil, ActiveSupport::TimeZone["Moscow"], Time.utc(2016, 4, 28, 00, 45)) now = Time.now.utc %w( second minute hour day week month year ).each do |unit| assert_equal((now + 1.send(unit)).class, Time, "Time + 1.#{unit} must be Time") @@ -408,9 +449,9 @@ class DurationTest < ActiveSupport::TestCase assert_equal 5, scalar / 2 assert_instance_of ActiveSupport::Duration::Scalar, scalar / 2 assert_equal 10, 100.seconds / scalar - assert_instance_of ActiveSupport::Duration, 2.seconds * scalar + assert_instance_of ActiveSupport::Duration, 100.seconds / scalar assert_equal 5, scalar / 2.seconds - assert_instance_of ActiveSupport::Duration, scalar / 2.seconds + assert_kind_of Integer, scalar / 2.seconds exception = assert_raises(TypeError) do scalar / "foo" @@ -419,13 +460,29 @@ class DurationTest < ActiveSupport::TestCase assert_equal "no implicit conversion of String into ActiveSupport::Duration::Scalar", exception.message end - def test_scalar_divide_parts + def test_scalar_modulo scalar = ActiveSupport::Duration::Scalar.new(10) - assert_equal({ days: 2 }, (scalar / 5.days).parts) - assert_equal(172800, (scalar / 5.days).value) - assert_equal({ days: -2 }, (scalar / -5.days).parts) - assert_equal(-172800, (scalar / -5.days).value) + assert_equal 1, 31 % scalar + assert_instance_of ActiveSupport::Duration::Scalar, 31 % scalar + assert_equal 1, scalar % 3 + assert_instance_of ActiveSupport::Duration::Scalar, scalar % 3 + assert_equal 1, 31.seconds % scalar + assert_instance_of ActiveSupport::Duration, 31.seconds % scalar + assert_equal 1, scalar % 3.seconds + assert_instance_of ActiveSupport::Duration, scalar % 3.seconds + + exception = assert_raises(TypeError) do + scalar % "foo" + end + + assert_equal "no implicit conversion of String into ActiveSupport::Duration::Scalar", exception.message + end + + def test_scalar_modulo_parts + scalar = ActiveSupport::Duration::Scalar.new(82800) + assert_equal({ hours: 1 }, (scalar % 2.hours).parts) + assert_equal(3600, (scalar % 2.hours).value) end def test_twelve_months_equals_one_year diff --git a/activesupport/test/core_ext/enumerable_test.rb b/activesupport/test/core_ext/enumerable_test.rb index 0b345ecf0f..8d71320931 100644 --- a/activesupport/test/core_ext/enumerable_test.rb +++ b/activesupport/test/core_ext/enumerable_test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "abstract_unit" require "active_support/core_ext/array" require "active_support/core_ext/enumerable" diff --git a/activesupport/test/core_ext/file_test.rb b/activesupport/test/core_ext/file_test.rb index df5d09acd0..23e3c277cc 100644 --- a/activesupport/test/core_ext/file_test.rb +++ b/activesupport/test/core_ext/file_test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "abstract_unit" require "active_support/core_ext/file" diff --git a/activesupport/test/core_ext/hash/transform_keys_test.rb b/activesupport/test/core_ext/hash/transform_keys_test.rb index 7a11d827f8..b9e41f7b25 100644 --- a/activesupport/test/core_ext/hash/transform_keys_test.rb +++ b/activesupport/test/core_ext/hash/transform_keys_test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "abstract_unit" require "active_support/core_ext/hash/keys" diff --git a/activesupport/test/core_ext/hash/transform_values_test.rb b/activesupport/test/core_ext/hash/transform_values_test.rb index f2ac4ce6ce..d34b7fa7b9 100644 --- a/activesupport/test/core_ext/hash/transform_values_test.rb +++ b/activesupport/test/core_ext/hash/transform_values_test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "abstract_unit" require "active_support/core_ext/hash/indifferent_access" require "active_support/core_ext/hash/transform_values" diff --git a/activesupport/test/core_ext/hash_ext_test.rb b/activesupport/test/core_ext/hash_ext_test.rb index 18da5fcf5f..17952e9fc7 100644 --- a/activesupport/test/core_ext/hash_ext_test.rb +++ b/activesupport/test/core_ext/hash_ext_test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "abstract_unit" require "active_support/core_ext/hash" require "bigdecimal" @@ -300,9 +302,9 @@ class HashExtTest < ActiveSupport::TestCase end def test_reverse_merge - defaults = { a: "x", b: "y", c: 10 }.freeze + defaults = { d: 0, a: "x", b: "y", c: 10 }.freeze options = { a: 1, b: 2 } - expected = { a: 1, b: 2, c: 10 } + expected = { d: 0, a: 1, b: 2, c: 10 } # Should merge defaults into options, creating a new hash. assert_equal expected, options.reverse_merge(defaults) @@ -313,6 +315,9 @@ class HashExtTest < ActiveSupport::TestCase assert_equal expected, merged.reverse_merge!(defaults) assert_equal expected, merged + # Make the order consistent with the non-overwriting reverse merge. + assert_equal expected.keys, merged.keys + # Should be an alias for reverse_merge! merged = options.dup assert_equal expected, merged.reverse_update(defaults) @@ -441,7 +446,7 @@ class HashExtTest < ActiveSupport::TestCase original.freeze assert_nothing_raised { original.except(:a) } - assert_raise(RuntimeError) { original.except!(:a) } + assert_raise(frozen_error_class) { original.except!(:a) } end def test_except_does_not_delete_values_in_original diff --git a/activesupport/test/core_ext/integer_ext_test.rb b/activesupport/test/core_ext/integer_ext_test.rb index 137e8ce85f..14169b084d 100644 --- a/activesupport/test/core_ext/integer_ext_test.rb +++ b/activesupport/test/core_ext/integer_ext_test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "abstract_unit" require "active_support/core_ext/integer" diff --git a/activesupport/test/core_ext/kernel/concern_test.rb b/activesupport/test/core_ext/kernel/concern_test.rb index e7e4f99d7e..b40ff6a623 100644 --- a/activesupport/test/core_ext/kernel/concern_test.rb +++ b/activesupport/test/core_ext/kernel/concern_test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "abstract_unit" require "active_support/core_ext/kernel/concern" diff --git a/activesupport/test/core_ext/kernel_test.rb b/activesupport/test/core_ext/kernel_test.rb index 26f5088ede..ef11e10af8 100644 --- a/activesupport/test/core_ext/kernel_test.rb +++ b/activesupport/test/core_ext/kernel_test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "abstract_unit" require "active_support/core_ext/kernel" diff --git a/activesupport/test/core_ext/load_error_test.rb b/activesupport/test/core_ext/load_error_test.rb index 44ff6bb051..41b11d0c33 100644 --- a/activesupport/test/core_ext/load_error_test.rb +++ b/activesupport/test/core_ext/load_error_test.rb @@ -1,9 +1,11 @@ +# frozen_string_literal: true + require "abstract_unit" require "active_support/core_ext/load_error" class TestLoadError < ActiveSupport::TestCase def test_with_require - assert_raise(LoadError) { require 'no_this_file_don\'t_exist' } + assert_raise(LoadError) { require "no_this_file_don't_exist" } end def test_with_load assert_raise(LoadError) { load "nor_does_this_one" } diff --git a/activesupport/test/core_ext/marshal_test.rb b/activesupport/test/core_ext/marshal_test.rb index cabeed2fae..7ac051b4b1 100644 --- a/activesupport/test/core_ext/marshal_test.rb +++ b/activesupport/test/core_ext/marshal_test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "abstract_unit" require "active_support/core_ext/marshal" require "dependencies_test_helpers" diff --git a/activesupport/test/core_ext/module/anonymous_test.rb b/activesupport/test/core_ext/module/anonymous_test.rb index f885444284..606f22c9b5 100644 --- a/activesupport/test/core_ext/module/anonymous_test.rb +++ b/activesupport/test/core_ext/module/anonymous_test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "abstract_unit" require "active_support/core_ext/module/anonymous" diff --git a/activesupport/test/core_ext/module/attr_internal_test.rb b/activesupport/test/core_ext/module/attr_internal_test.rb index 8458e278ee..c2a28eced4 100644 --- a/activesupport/test/core_ext/module/attr_internal_test.rb +++ b/activesupport/test/core_ext/module/attr_internal_test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "abstract_unit" require "active_support/core_ext/module/attr_internal" diff --git a/activesupport/test/core_ext/module/attribute_accessor_per_thread_test.rb b/activesupport/test/core_ext/module/attribute_accessor_per_thread_test.rb index af240bc38d..e0fbd1002c 100644 --- a/activesupport/test/core_ext/module/attribute_accessor_per_thread_test.rb +++ b/activesupport/test/core_ext/module/attribute_accessor_per_thread_test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "abstract_unit" require "active_support/core_ext/module/attribute_accessors_per_thread" diff --git a/activesupport/test/core_ext/module/attribute_accessor_test.rb b/activesupport/test/core_ext/module/attribute_accessor_test.rb index 9b185e9381..f1d6859a88 100644 --- a/activesupport/test/core_ext/module/attribute_accessor_test.rb +++ b/activesupport/test/core_ext/module/attribute_accessor_test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "abstract_unit" require "active_support/core_ext/module/attribute_accessors" diff --git a/activesupport/test/core_ext/module/attribute_aliasing_test.rb b/activesupport/test/core_ext/module/attribute_aliasing_test.rb index fdfa868851..187a0f4da2 100644 --- a/activesupport/test/core_ext/module/attribute_aliasing_test.rb +++ b/activesupport/test/core_ext/module/attribute_aliasing_test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "abstract_unit" require "active_support/core_ext/module/aliasing" diff --git a/activesupport/test/core_ext/module/concerning_test.rb b/activesupport/test/core_ext/module/concerning_test.rb index 098036828a..192c3d5a9c 100644 --- a/activesupport/test/core_ext/module/concerning_test.rb +++ b/activesupport/test/core_ext/module/concerning_test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "abstract_unit" require "active_support/core_ext/module/concerning" diff --git a/activesupport/test/core_ext/module/introspection_test.rb b/activesupport/test/core_ext/module/introspection_test.rb index db383850cd..76d3012239 100644 --- a/activesupport/test/core_ext/module/introspection_test.rb +++ b/activesupport/test/core_ext/module/introspection_test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "abstract_unit" require "active_support/core_ext/module/introspection" diff --git a/activesupport/test/core_ext/module/reachable_test.rb b/activesupport/test/core_ext/module/reachable_test.rb index 487c7dee16..097a72fa5b 100644 --- a/activesupport/test/core_ext/module/reachable_test.rb +++ b/activesupport/test/core_ext/module/reachable_test.rb @@ -1,15 +1,21 @@ +# frozen_string_literal: true + require "abstract_unit" require "active_support/core_ext/module/reachable" class AnonymousTest < ActiveSupport::TestCase test "an anonymous class or module is not reachable" do - assert !Module.new.reachable? - assert !Class.new.reachable? + assert_deprecated do + assert !Module.new.reachable? + assert !Class.new.reachable? + end end test "ordinary named classes or modules are reachable" do - assert Kernel.reachable? - assert Object.reachable? + assert_deprecated do + assert Kernel.reachable? + assert Object.reachable? + end end test "a named class or module whose constant has gone is not reachable" do @@ -19,8 +25,10 @@ class AnonymousTest < ActiveSupport::TestCase self.class.send(:remove_const, :C) self.class.send(:remove_const, :M) - assert !c.reachable? - assert !m.reachable? + assert_deprecated do + assert !c.reachable? + assert !m.reachable? + end end test "a named class or module whose constants store different objects are not reachable" do @@ -33,9 +41,11 @@ class AnonymousTest < ActiveSupport::TestCase eval "class C; end" eval "module M; end" - assert C.reachable? - assert M.reachable? - assert !c.reachable? - assert !m.reachable? + assert_deprecated do + assert C.reachable? + assert M.reachable? + assert !c.reachable? + assert !m.reachable? + end end end diff --git a/activesupport/test/core_ext/module/remove_method_test.rb b/activesupport/test/core_ext/module/remove_method_test.rb index 0c627f1e74..8493be8d08 100644 --- a/activesupport/test/core_ext/module/remove_method_test.rb +++ b/activesupport/test/core_ext/module/remove_method_test.rb @@ -1,25 +1,27 @@ +# frozen_string_literal: true + require "abstract_unit" require "active_support/core_ext/module/remove_method" module RemoveMethodTests class A def do_something - return 1 + 1 end def do_something_protected - return 1 + 1 end protected :do_something_protected def do_something_private - return 1 + 1 end private :do_something_private class << self def do_something_else - return 2 + 2 end end end diff --git a/activesupport/test/core_ext/module_test.rb b/activesupport/test/core_ext/module_test.rb index a4d4444d69..e918823074 100644 --- a/activesupport/test/core_ext/module_test.rb +++ b/activesupport/test/core_ext/module_test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "abstract_unit" require "active_support/core_ext/module" @@ -372,6 +374,14 @@ class ModuleTest < ActiveSupport::TestCase assert_match(/undefined method `my_fake_method' for/, e.message) end + def test_delegate_missing_to_raises_delegation_error_if_target_nil + e = assert_raises(Module::DelegationError) do + DecoratedTester.new(nil).name + end + + assert_equal "name delegated to client, but client is nil", e.message + end + def test_delegate_missing_to_affects_respond_to assert DecoratedTester.new(@david).respond_to?(:name) assert_not DecoratedTester.new(@david).respond_to?(:private_name) @@ -392,4 +402,42 @@ class ModuleTest < ActiveSupport::TestCase event = Event.new(Tester.new) assert_equal 1, event.foo end + + def test_private_delegate + location = Class.new do + def initialize(place) + @place = place + end + + private(*delegate(:street, :city, to: :@place)) + end + + place = location.new(Somewhere.new("Such street", "Sad city")) + + assert_not place.respond_to?(:street) + assert_not place.respond_to?(:city) + + assert place.respond_to?(:street, true) # Asking for private method + assert place.respond_to?(:city, true) + end + + def test_private_delegate_prefixed + location = Class.new do + def initialize(place) + @place = place + end + + private(*delegate(:street, :city, to: :@place, prefix: :the)) + end + + place = location.new(Somewhere.new("Such street", "Sad city")) + + assert_not place.respond_to?(:street) + assert_not place.respond_to?(:city) + + assert_not place.respond_to?(:the_street) + assert place.respond_to?(:the_street, true) + assert_not place.respond_to?(:the_city) + assert place.respond_to?(:the_city, true) + end end diff --git a/activesupport/test/core_ext/name_error_test.rb b/activesupport/test/core_ext/name_error_test.rb index fdb9493d3c..d1dace3713 100644 --- a/activesupport/test/core_ext/name_error_test.rb +++ b/activesupport/test/core_ext/name_error_test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "abstract_unit" require "active_support/core_ext/name_error" diff --git a/activesupport/test/core_ext/numeric_ext_test.rb b/activesupport/test/core_ext/numeric_ext_test.rb index 3cfbe6e7e6..4b9073da54 100644 --- a/activesupport/test/core_ext/numeric_ext_test.rb +++ b/activesupport/test/core_ext/numeric_ext_test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "abstract_unit" require "active_support/time" require "active_support/core_ext/numeric" @@ -300,7 +302,7 @@ class NumericExtFormattingTest < ActiveSupport::TestCase assert_equal "40 KB", 41100.to_s(:human_size, precision: 2) assert_equal "1.0 KB", kilobytes(1.0123).to_s(:human_size, precision: 2, strip_insignificant_zeros: false) assert_equal "1.012 KB", kilobytes(1.0123).to_s(:human_size, precision: 3, significant: false) - assert_equal "1 KB", kilobytes(1.0123).to_s(:human_size, precision: 0, significant: true) #ignores significant it precision is 0 + assert_equal "1 KB", kilobytes(1.0123).to_s(:human_size, precision: 0, significant: true) # ignores significant it precision is 0 end def test_to_s__human_size_with_custom_delimiter_and_separator @@ -328,17 +330,17 @@ class NumericExtFormattingTest < ActiveSupport::TestCase assert_equal "489.0 Thousand", 489000.to_s(:human, precision: 4, strip_insignificant_zeros: false) assert_equal "1.2346 Million", 1234567.to_s(:human, precision: 4, significant: false) assert_equal "1,2 Million", 1234567.to_s(:human, precision: 1, significant: false, separator: ",") - assert_equal "1 Million", 1234567.to_s(:human, precision: 0, significant: true, separator: ",") #significant forced to false + assert_equal "1 Million", 1234567.to_s(:human, precision: 0, significant: true, separator: ",") # significant forced to false end def test_number_to_human_with_custom_units - #Only integers + # Only integers volume = { unit: "ml", thousand: "lt", million: "m3" } assert_equal "123 lt", 123456.to_s(:human, units: volume) assert_equal "12 ml", 12.to_s(:human, units: volume) assert_equal "1.23 m3", 1234567.to_s(:human, units: volume) - #Including fractionals + # Including fractionals distance = { mili: "mm", centi: "cm", deci: "dm", unit: "m", ten: "dam", hundred: "hm", thousand: "km" } assert_equal "1.23 mm", 0.00123.to_s(:human, units: distance) assert_equal "1.23 cm", 0.0123.to_s(:human, units: distance) @@ -351,14 +353,14 @@ class NumericExtFormattingTest < ActiveSupport::TestCase assert_equal "1.23 km", 1230.to_s(:human, units: distance) assert_equal "12.3 km", 12300.to_s(:human, units: distance) - #The quantifiers don't need to be a continuous sequence + # The quantifiers don't need to be a continuous sequence gangster = { hundred: "hundred bucks", million: "thousand quids" } assert_equal "1 hundred bucks", 100.to_s(:human, units: gangster) assert_equal "25 hundred bucks", 2500.to_s(:human, units: gangster) assert_equal "25 thousand quids", 25000000.to_s(:human, units: gangster) assert_equal "12300 thousand quids", 12345000000.to_s(:human, units: gangster) - #Spaces are stripped from the resulting string + # Spaces are stripped from the resulting string assert_equal "4", 4.to_s(:human, units: { unit: "", ten: "tens " }) assert_equal "4.5 tens", 45.to_s(:human, units: { unit: "", ten: " tens " }) end diff --git a/activesupport/test/core_ext/object/acts_like_test.rb b/activesupport/test/core_ext/object/acts_like_test.rb index 631f4e63a8..9f7b81f7fc 100644 --- a/activesupport/test/core_ext/object/acts_like_test.rb +++ b/activesupport/test/core_ext/object/acts_like_test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "abstract_unit" require "active_support/core_ext/object" diff --git a/activesupport/test/core_ext/object/blank_test.rb b/activesupport/test/core_ext/object/blank_test.rb index 7fd3fed042..954f415383 100644 --- a/activesupport/test/core_ext/object/blank_test.rb +++ b/activesupport/test/core_ext/object/blank_test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "abstract_unit" require "active_support/core_ext/object/blank" @@ -14,8 +16,8 @@ class BlankTest < ActiveSupport::TestCase end end - BLANK = [ EmptyTrue.new, nil, false, "", " ", " \n\t \r ", " ", "\u00a0", [], {} ] - NOT = [ EmptyFalse.new, Object.new, true, 0, 1, "a", [nil], { nil => 0 }, Time.now ] + BLANK = [ EmptyTrue.new, nil, false, "", " ", " \n\t \r ", " ", "\u00a0", [], {}, " ".encode("UTF-16LE") ] + NOT = [ EmptyFalse.new, Object.new, true, 0, 1, "a", [nil], { nil => 0 }, Time.now, "my value".encode("UTF-16LE") ] def test_blank BLANK.each { |v| assert_equal true, v.blank?, "#{v.inspect} should be blank" } diff --git a/activesupport/test/core_ext/object/deep_dup_test.rb b/activesupport/test/core_ext/object/deep_dup_test.rb index f247ee16de..2486592441 100644 --- a/activesupport/test/core_ext/object/deep_dup_test.rb +++ b/activesupport/test/core_ext/object/deep_dup_test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "abstract_unit" require "active_support/core_ext/object" diff --git a/activesupport/test/core_ext/object/duplicable_test.rb b/activesupport/test/core_ext/object/duplicable_test.rb index 68b0129980..b984becce3 100644 --- a/activesupport/test/core_ext/object/duplicable_test.rb +++ b/activesupport/test/core_ext/object/duplicable_test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "abstract_unit" require "bigdecimal" require "active_support/core_ext/object/duplicable" @@ -6,16 +8,16 @@ require "active_support/core_ext/numeric/time" class DuplicableTest < ActiveSupport::TestCase if RUBY_VERSION >= "2.5.0" RAISE_DUP = [method(:puts)] - ALLOW_DUP = ["1", "symbol_from_string".to_sym, Object.new, /foo/, [], {}, Time.now, Class.new, Module.new, BigDecimal.new("4.56"), nil, false, true, 1, 2.3, Complex(1), Rational(1)] + ALLOW_DUP = ["1", "symbol_from_string".to_sym, Object.new, /foo/, [], {}, Time.now, Class.new, Module.new, BigDecimal("4.56"), nil, false, true, 1, 2.3, Complex(1), Rational(1)] elsif RUBY_VERSION >= "2.4.1" RAISE_DUP = [method(:puts), Complex(1), Rational(1)] - ALLOW_DUP = ["1", "symbol_from_string".to_sym, Object.new, /foo/, [], {}, Time.now, Class.new, Module.new, BigDecimal.new("4.56"), nil, false, true, 1, 2.3] + ALLOW_DUP = ["1", "symbol_from_string".to_sym, Object.new, /foo/, [], {}, Time.now, Class.new, Module.new, BigDecimal("4.56"), nil, false, true, 1, 2.3] elsif RUBY_VERSION >= "2.4.0" # Due to 2.4.0 bug. This elsif cannot be removed unless we drop 2.4.0 support... RAISE_DUP = [method(:puts), Complex(1), Rational(1), "symbol_from_string".to_sym] - ALLOW_DUP = ["1", Object.new, /foo/, [], {}, Time.now, Class.new, Module.new, BigDecimal.new("4.56"), nil, false, true, 1, 2.3] + ALLOW_DUP = ["1", Object.new, /foo/, [], {}, Time.now, Class.new, Module.new, BigDecimal("4.56"), nil, false, true, 1, 2.3] else RAISE_DUP = [nil, false, true, :symbol, 1, 2.3, method(:puts), Complex(1), Rational(1)] - ALLOW_DUP = ["1", Object.new, /foo/, [], {}, Time.now, Class.new, Module.new, BigDecimal.new("4.56")] + ALLOW_DUP = ["1", Object.new, /foo/, [], {}, Time.now, Class.new, Module.new, BigDecimal("4.56")] end def test_duplicable diff --git a/activesupport/test/core_ext/object/inclusion_test.rb b/activesupport/test/core_ext/object/inclusion_test.rb index 955686d6aa..52c21f2e8e 100644 --- a/activesupport/test/core_ext/object/inclusion_test.rb +++ b/activesupport/test/core_ext/object/inclusion_test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "abstract_unit" require "active_support/core_ext/object/inclusion" diff --git a/activesupport/test/core_ext/object/instance_variables_test.rb b/activesupport/test/core_ext/object/instance_variables_test.rb index 5bdb2fbc35..a3d8daab5b 100644 --- a/activesupport/test/core_ext/object/instance_variables_test.rb +++ b/activesupport/test/core_ext/object/instance_variables_test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "abstract_unit" require "active_support/core_ext/object" @@ -17,7 +19,7 @@ class ObjectInstanceVariableTest < ActiveSupport::TestCase end def test_instance_exec_passes_arguments_to_block - assert_equal %w(hello goodbye), "hello".instance_exec("goodbye") { |v| [self, v] } + assert_equal %w(hello goodbye), "hello".dup.instance_exec("goodbye") { |v| [self, v] } end def test_instance_exec_with_frozen_obj @@ -25,7 +27,7 @@ class ObjectInstanceVariableTest < ActiveSupport::TestCase end def test_instance_exec_nested - assert_equal %w(goodbye olleh bar), "hello".instance_exec("goodbye") { |arg| + assert_equal %w(goodbye olleh bar), "hello".dup.instance_exec("goodbye") { |arg| [arg] + instance_exec("bar") { |v| [reverse, v] } } end end diff --git a/activesupport/test/core_ext/object/json_cherry_pick_test.rb b/activesupport/test/core_ext/object/json_cherry_pick_test.rb index dd4e90918e..22659a4050 100644 --- a/activesupport/test/core_ext/object/json_cherry_pick_test.rb +++ b/activesupport/test/core_ext/object/json_cherry_pick_test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "abstract_unit" # These test cases were added to test that cherry-picking the json extensions diff --git a/activesupport/test/core_ext/object/json_gem_encoding_test.rb b/activesupport/test/core_ext/object/json_gem_encoding_test.rb index f5016d0c2a..4cdb6ed09f 100644 --- a/activesupport/test/core_ext/object/json_gem_encoding_test.rb +++ b/activesupport/test/core_ext/object/json_gem_encoding_test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "abstract_unit" require "json" require "json/encoding_test_cases" diff --git a/activesupport/test/core_ext/object/to_param_test.rb b/activesupport/test/core_ext/object/to_param_test.rb index 56246b24f3..612156bd99 100644 --- a/activesupport/test/core_ext/object/to_param_test.rb +++ b/activesupport/test/core_ext/object/to_param_test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "abstract_unit" require "active_support/core_ext/object/to_param" diff --git a/activesupport/test/core_ext/object/to_query_test.rb b/activesupport/test/core_ext/object/to_query_test.rb index 298c8bf373..7593bcfa4d 100644 --- a/activesupport/test/core_ext/object/to_query_test.rb +++ b/activesupport/test/core_ext/object/to_query_test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "abstract_unit" require "active_support/ordered_hash" require "active_support/core_ext/object/to_query" diff --git a/activesupport/test/core_ext/object/try_test.rb b/activesupport/test/core_ext/object/try_test.rb index 5c8bf59952..fe68b24bf5 100644 --- a/activesupport/test/core_ext/object/try_test.rb +++ b/activesupport/test/core_ext/object/try_test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "abstract_unit" require "active_support/core_ext/object" diff --git a/activesupport/test/core_ext/range_ext_test.rb b/activesupport/test/core_ext/range_ext_test.rb index d166c7309c..903c173e59 100644 --- a/activesupport/test/core_ext/range_ext_test.rb +++ b/activesupport/test/core_ext/range_ext_test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "abstract_unit" require "active_support/time" require "active_support/core_ext/numeric" @@ -14,6 +16,11 @@ class RangeTest < ActiveSupport::TestCase assert_equal "BETWEEN '2005-12-10 15:30:00' AND '2005-12-10 17:30:00'", date_range.to_s(:db) end + def test_to_s_with_alphabets + alphabet_range = ("a".."z") + assert_equal "BETWEEN 'a' AND 'z'", alphabet_range.to_s(:db) + end + def test_to_s_with_numeric number_range = (1..100) assert_equal "BETWEEN '1' AND '100'", number_range.to_s(:db) @@ -99,24 +106,27 @@ class RangeTest < ActiveSupport::TestCase end def test_each_on_time_with_zone - twz = ActiveSupport::TimeWithZone.new(nil, ActiveSupport::TimeZone["Eastern Time (US & Canada)"] , Time.utc(2006, 11, 28, 10, 30)) + twz = ActiveSupport::TimeWithZone.new(nil, ActiveSupport::TimeZone["Eastern Time (US & Canada)"], Time.utc(2006, 11, 28, 10, 30)) assert_raises TypeError do ((twz - 1.hour)..twz).each {} end end def test_step_on_time_with_zone - twz = ActiveSupport::TimeWithZone.new(nil, ActiveSupport::TimeZone["Eastern Time (US & Canada)"] , Time.utc(2006, 11, 28, 10, 30)) + twz = ActiveSupport::TimeWithZone.new(nil, ActiveSupport::TimeZone["Eastern Time (US & Canada)"], Time.utc(2006, 11, 28, 10, 30)) assert_raises TypeError do ((twz - 1.hour)..twz).step(1) {} end end def test_include_on_time_with_zone - twz = ActiveSupport::TimeWithZone.new(nil, ActiveSupport::TimeZone["Eastern Time (US & Canada)"] , Time.utc(2006, 11, 28, 10, 30)) - assert_raises TypeError do - ((twz - 1.hour)..twz).include?(twz) - end + twz = ActiveSupport::TimeWithZone.new(nil, ActiveSupport::TimeZone["Eastern Time (US & Canada)"], Time.utc(2006, 11, 28, 10, 30)) + assert ((twz - 1.hour)..twz).include?(twz) + end + + def test_case_equals_on_time_with_zone + twz = ActiveSupport::TimeWithZone.new(nil, ActiveSupport::TimeZone["Eastern Time (US & Canada)"], Time.utc(2006, 11, 28, 10, 30)) + assert ((twz - 1.hour)..twz) === twz end def test_date_time_with_each diff --git a/activesupport/test/core_ext/regexp_ext_test.rb b/activesupport/test/core_ext/regexp_ext_test.rb index e569a9f234..5737bdafda 100644 --- a/activesupport/test/core_ext/regexp_ext_test.rb +++ b/activesupport/test/core_ext/regexp_ext_test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "abstract_unit" require "active_support/core_ext/regexp" diff --git a/activesupport/test/core_ext/secure_random_test.rb b/activesupport/test/core_ext/secure_random_test.rb index fc25f6ab41..7067fb524c 100644 --- a/activesupport/test/core_ext/secure_random_test.rb +++ b/activesupport/test/core_ext/secure_random_test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "abstract_unit" require "active_support/core_ext/securerandom" diff --git a/activesupport/test/core_ext/string_ext_test.rb b/activesupport/test/core_ext/string_ext_test.rb index daa8c3f2ef..5c5abe9fd1 100644 --- a/activesupport/test/core_ext/string_ext_test.rb +++ b/activesupport/test/core_ext/string_ext_test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "date" require "abstract_unit" require "timeout" @@ -106,6 +108,13 @@ class StringInflectionsTest < ActiveSupport::TestCase assert_equal("capital", "Capital".camelize(:lower)) end + def test_camelize_invalid_option + e = assert_raise ArgumentError do + "Capital".camelize(nil) + end + assert_equal("Invalid option, use either :upper or :lower.", e.message) + end + def test_dasherize UnderscoresToDashes.each do |underscored, dasherized| assert_equal(dasherized, underscored.dasherize) @@ -188,7 +197,7 @@ class StringInflectionsTest < ActiveSupport::TestCase end def test_string_parameterized_underscore_preserve_case - StringToParameterizePreserceCaseWithUnderscore.each do |normal, slugged| + StringToParameterizePreserveCaseWithUnderscore.each do |normal, slugged| assert_equal(slugged, normal.parameterize(separator: "_", preserve_case: true)) end end diff --git a/activesupport/test/core_ext/time_ext_test.rb b/activesupport/test/core_ext/time_ext_test.rb index 625a5bffb8..01cf1938be 100644 --- a/activesupport/test/core_ext/time_ext_test.rb +++ b/activesupport/test/core_ext/time_ext_test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "abstract_unit" require "active_support/time" require "core_ext/date_and_time_behavior" @@ -176,10 +178,6 @@ class TimeExtCalculationsTest < ActiveSupport::TestCase assert_equal Time.local(2005, 2, 4, 19, 30, 59, Rational(999999999, 1000)), Time.local(2005, 2, 4, 19, 30, 10).end_of_minute end - def test_last_year - assert_equal Time.local(2004, 6, 5, 10), Time.local(2005, 6, 5, 10, 0, 0).last_year - end - def test_ago assert_equal Time.local(2005, 2, 22, 10, 10, 9), Time.local(2005, 2, 22, 10, 10, 10).ago(1) assert_equal Time.local(2005, 2, 22, 9, 10, 10), Time.local(2005, 2, 22, 10, 10, 10).ago(3600) @@ -453,7 +451,7 @@ class TimeExtCalculationsTest < ActiveSupport::TestCase assert_equal Time.local(2013, 10, 3, 15, 15, 10), Time.local(2005, 2, 28, 15, 15, 10).advance(years: 7, months: 19, days: 5) assert_equal Time.local(2013, 10, 17, 15, 15, 10), Time.local(2005, 2, 28, 15, 15, 10).advance(years: 7, months: 19, weeks: 2, days: 5) assert_equal Time.local(2001, 12, 27, 15, 15, 10), Time.local(2005, 2, 28, 15, 15, 10).advance(years: -3, months: -2, days: -1) - assert_equal Time.local(2005, 2, 28, 15, 15, 10), Time.local(2004, 2, 29, 15, 15, 10).advance(years: 1) #leap day plus one year + assert_equal Time.local(2005, 2, 28, 15, 15, 10), Time.local(2004, 2, 29, 15, 15, 10).advance(years: 1) # leap day plus one year assert_equal Time.local(2005, 2, 28, 20, 15, 10), Time.local(2005, 2, 28, 15, 15, 10).advance(hours: 5) assert_equal Time.local(2005, 2, 28, 15, 22, 10), Time.local(2005, 2, 28, 15, 15, 10).advance(minutes: 7) assert_equal Time.local(2005, 2, 28, 15, 15, 19), Time.local(2005, 2, 28, 15, 15, 10).advance(seconds: 9) @@ -475,7 +473,7 @@ class TimeExtCalculationsTest < ActiveSupport::TestCase assert_equal Time.utc(2013, 10, 3, 15, 15, 10), Time.utc(2005, 2, 22, 15, 15, 10).advance(years: 7, months: 19, days: 11) assert_equal Time.utc(2013, 10, 17, 15, 15, 10), Time.utc(2005, 2, 28, 15, 15, 10).advance(years: 7, months: 19, weeks: 2, days: 5) assert_equal Time.utc(2001, 12, 27, 15, 15, 10), Time.utc(2005, 2, 28, 15, 15, 10).advance(years: -3, months: -2, days: -1) - assert_equal Time.utc(2005, 2, 28, 15, 15, 10), Time.utc(2004, 2, 29, 15, 15, 10).advance(years: 1) #leap day plus one year + assert_equal Time.utc(2005, 2, 28, 15, 15, 10), Time.utc(2004, 2, 29, 15, 15, 10).advance(years: 1) # leap day plus one year assert_equal Time.utc(2005, 2, 28, 20, 15, 10), Time.utc(2005, 2, 28, 15, 15, 10).advance(hours: 5) assert_equal Time.utc(2005, 2, 28, 15, 22, 10), Time.utc(2005, 2, 28, 15, 15, 10).advance(minutes: 7) assert_equal Time.utc(2005, 2, 28, 15, 15, 19), Time.utc(2005, 2, 28, 15, 15, 10).advance(seconds: 9) @@ -497,7 +495,7 @@ class TimeExtCalculationsTest < ActiveSupport::TestCase assert_equal Time.new(2013, 10, 3, 15, 15, 10, "-08:00"), Time.new(2005, 2, 22, 15, 15, 10, "-08:00").advance(years: 7, months: 19, days: 11) assert_equal Time.new(2013, 10, 17, 15, 15, 10, "-08:00"), Time.new(2005, 2, 28, 15, 15, 10, "-08:00").advance(years: 7, months: 19, weeks: 2, days: 5) assert_equal Time.new(2001, 12, 27, 15, 15, 10, "-08:00"), Time.new(2005, 2, 28, 15, 15, 10, "-08:00").advance(years: -3, months: -2, days: -1) - assert_equal Time.new(2005, 2, 28, 15, 15, 10, "-08:00"), Time.new(2004, 2, 29, 15, 15, 10, "-08:00").advance(years: 1) #leap day plus one year + assert_equal Time.new(2005, 2, 28, 15, 15, 10, "-08:00"), Time.new(2004, 2, 29, 15, 15, 10, "-08:00").advance(years: 1) # leap day plus one year assert_equal Time.new(2005, 2, 28, 20, 15, 10, "-08:00"), Time.new(2005, 2, 28, 15, 15, 10, "-08:00").advance(hours: 5) assert_equal Time.new(2005, 2, 28, 15, 22, 10, "-08:00"), Time.new(2005, 2, 28, 15, 15, 10, "-08:00").advance(minutes: 7) assert_equal Time.new(2005, 2, 28, 15, 15, 19, "-08:00"), Time.new(2005, 2, 28, 15, 15, 10, "-08:00").advance(seconds: 9) @@ -662,10 +660,6 @@ class TimeExtCalculationsTest < ActiveSupport::TestCase end end - def test_last_month_on_31st - assert_equal Time.local(2004, 2, 29), Time.local(2004, 3, 31).last_month - end - def test_xmlschema_is_available assert_nothing_raised { Time.now.xmlschema } end diff --git a/activesupport/test/core_ext/time_with_zone_test.rb b/activesupport/test/core_ext/time_with_zone_test.rb index 70ae793cda..b25747eadb 100644 --- a/activesupport/test/core_ext/time_with_zone_test.rb +++ b/activesupport/test/core_ext/time_with_zone_test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "abstract_unit" require "active_support/time" require "time_zone_test_helpers" @@ -48,6 +50,12 @@ class TimeWithZoneTest < ActiveSupport::TestCase assert_raise(ArgumentError) { @twz.in_time_zone(Object.new) } end + def test_in_time_zone_with_ambiguous_time + with_env_tz "Europe/Moscow" do + assert_equal Time.utc(2014, 10, 25, 22, 0, 0), Time.local(2014, 10, 26, 1, 0, 0).in_time_zone("Moscow") + end + end + def test_localtime assert_equal @twz.localtime, @twz.utc.getlocal assert_instance_of Time, @twz.localtime @@ -76,7 +84,7 @@ class TimeWithZoneTest < ActiveSupport::TestCase def test_formatted_offset assert_equal "-05:00", @twz.formatted_offset - assert_equal "-04:00", ActiveSupport::TimeWithZone.new(Time.utc(2000, 6), @time_zone).formatted_offset #dst + assert_equal "-04:00", ActiveSupport::TimeWithZone.new(Time.utc(2000, 6), @time_zone).formatted_offset # dst end def test_dst? @@ -86,7 +94,7 @@ class TimeWithZoneTest < ActiveSupport::TestCase def test_zone assert_equal "EST", @twz.zone - assert_equal "EDT", ActiveSupport::TimeWithZone.new(Time.utc(2000, 6), @time_zone).zone #dst + assert_equal "EDT", ActiveSupport::TimeWithZone.new(Time.utc(2000, 6), @time_zone).zone # dst end def test_nsec @@ -299,13 +307,13 @@ class TimeWithZoneTest < ActiveSupport::TestCase end def test_plus_with_integer - assert_equal Time.utc(1999, 12, 31, 19, 0 , 5), (@twz + 5).time + assert_equal Time.utc(1999, 12, 31, 19, 0, 5), (@twz + 5).time end def test_plus_with_integer_when_self_wraps_datetime datetime = DateTime.civil(2000, 1, 1, 0) twz = ActiveSupport::TimeWithZone.new(datetime, @time_zone) - assert_equal DateTime.civil(1999, 12, 31, 19, 0 , 5), (twz + 5).time + assert_equal DateTime.civil(1999, 12, 31, 19, 0, 5), (twz + 5).time end def test_plus_when_crossing_time_class_limit @@ -314,21 +322,21 @@ class TimeWithZoneTest < ActiveSupport::TestCase end def test_plus_with_duration - assert_equal Time.utc(2000, 1, 5, 19, 0 , 0), (@twz + 5.days).time + assert_equal Time.utc(2000, 1, 5, 19, 0, 0), (@twz + 5.days).time end def test_minus_with_integer - assert_equal Time.utc(1999, 12, 31, 18, 59 , 55), (@twz - 5).time + assert_equal Time.utc(1999, 12, 31, 18, 59, 55), (@twz - 5).time end def test_minus_with_integer_when_self_wraps_datetime datetime = DateTime.civil(2000, 1, 1, 0) twz = ActiveSupport::TimeWithZone.new(datetime, @time_zone) - assert_equal DateTime.civil(1999, 12, 31, 18, 59 , 55), (twz - 5).time + assert_equal DateTime.civil(1999, 12, 31, 18, 59, 55), (twz - 5).time end def test_minus_with_duration - assert_equal Time.utc(1999, 12, 26, 19, 0 , 0), (@twz - 5.days).time + assert_equal Time.utc(1999, 12, 26, 19, 0, 0), (@twz - 5.days).time end def test_minus_with_time @@ -499,7 +507,7 @@ class TimeWithZoneTest < ActiveSupport::TestCase def test_method_missing_with_time_return_value assert_instance_of ActiveSupport::TimeWithZone, @twz.months_since(1) - assert_equal Time.utc(2000, 1, 31, 19, 0 , 0), @twz.months_since(1).time + assert_equal Time.utc(2000, 1, 31, 19, 0, 0), @twz.months_since(1).time end def test_marshal_dump_and_load @@ -1299,4 +1307,10 @@ class TimeWithZoneMethodsForString < ActiveSupport::TestCase assert_raise(ArgumentError) { @u.in_time_zone(Object.new) } assert_raise(ArgumentError) { @z.in_time_zone(Object.new) } end + + def test_in_time_zone_with_ambiguous_time + with_tz_default "Moscow" do + assert_equal Time.utc(2014, 10, 25, 22, 0, 0), "2014-10-26 01:00:00".in_time_zone + end + end end diff --git a/activesupport/test/core_ext/uri_ext_test.rb b/activesupport/test/core_ext/uri_ext_test.rb index 0f13ca9c0e..8816b0d392 100644 --- a/activesupport/test/core_ext/uri_ext_test.rb +++ b/activesupport/test/core_ext/uri_ext_test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "abstract_unit" require "uri" require "active_support/core_ext/uri" diff --git a/activesupport/test/current_attributes_test.rb b/activesupport/test/current_attributes_test.rb index 67ef6ef619..1669f08f68 100644 --- a/activesupport/test/current_attributes_test.rb +++ b/activesupport/test/current_attributes_test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "abstract_unit" class CurrentAttributesTest < ActiveSupport::TestCase @@ -28,7 +30,14 @@ class CurrentAttributesTest < ActiveSupport::TestCase end end - setup { Current.reset } + setup do + @original_time_zone = Time.zone + Current.reset + end + + teardown do + Time.zone = @original_time_zone + end test "read and write attribute" do Current.world = "world/1" diff --git a/activesupport/test/dependencies/check_warnings.rb b/activesupport/test/dependencies/check_warnings.rb index 03c3dca1d6..f7d7d2dbc7 100644 --- a/activesupport/test/dependencies/check_warnings.rb +++ b/activesupport/test/dependencies/check_warnings.rb @@ -1,2 +1,4 @@ +# frozen_string_literal: true + $check_warnings_load_count += 1 $checked_verbose = $VERBOSE diff --git a/activesupport/test/dependencies/conflict.rb b/activesupport/test/dependencies/conflict.rb index 7eff49bbfa..aa22ec0b09 100644 --- a/activesupport/test/dependencies/conflict.rb +++ b/activesupport/test/dependencies/conflict.rb @@ -1 +1,3 @@ +# frozen_string_literal: true + Conflict = 1 diff --git a/activesupport/test/dependencies/cross_site_depender.rb b/activesupport/test/dependencies/cross_site_depender.rb index fbc3b64f56..3ddea7fc4b 100644 --- a/activesupport/test/dependencies/cross_site_depender.rb +++ b/activesupport/test/dependencies/cross_site_depender.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + class CrossSiteDepender CrossSiteDependency end diff --git a/activesupport/test/dependencies/mutual_one.rb b/activesupport/test/dependencies/mutual_one.rb index 05f08f82d3..bb48fddd4d 100644 --- a/activesupport/test/dependencies/mutual_one.rb +++ b/activesupport/test/dependencies/mutual_one.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + $mutual_dependencies_count += 1 require_dependency "mutual_two" require_dependency "mutual_two.rb" diff --git a/activesupport/test/dependencies/mutual_two.rb b/activesupport/test/dependencies/mutual_two.rb index 1d87d334af..ed354ed75e 100644 --- a/activesupport/test/dependencies/mutual_two.rb +++ b/activesupport/test/dependencies/mutual_two.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + $mutual_dependencies_count += 1 require_dependency "mutual_one.rb" require_dependency "mutual_one" diff --git a/activesupport/test/dependencies/raises_exception.rb b/activesupport/test/dependencies/raises_exception.rb index 0a56680fe3..67bfaabb3e 100644 --- a/activesupport/test/dependencies/raises_exception.rb +++ b/activesupport/test/dependencies/raises_exception.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + $raises_exception_load_count += 1 raise Exception, "Loading me failed, so do not add to loaded or history." $raises_exception_load_count += 1 diff --git a/activesupport/test/dependencies/raises_exception_without_blame_file.rb b/activesupport/test/dependencies/raises_exception_without_blame_file.rb index 7c3856b1e6..3a6533cd3a 100644 --- a/activesupport/test/dependencies/raises_exception_without_blame_file.rb +++ b/activesupport/test/dependencies/raises_exception_without_blame_file.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + exception = Exception.new("I am not blamable!") class << exception undef_method(:blame_file!) diff --git a/activesupport/test/dependencies/requires_nonexistent0.rb b/activesupport/test/dependencies/requires_nonexistent0.rb index 7f8a0d8419..d09dbd2485 100644 --- a/activesupport/test/dependencies/requires_nonexistent0.rb +++ b/activesupport/test/dependencies/requires_nonexistent0.rb @@ -1 +1,3 @@ +# frozen_string_literal: true + require "RMagickDontExistDude" diff --git a/activesupport/test/dependencies/requires_nonexistent1.rb b/activesupport/test/dependencies/requires_nonexistent1.rb index 0055177d67..ce96229172 100644 --- a/activesupport/test/dependencies/requires_nonexistent1.rb +++ b/activesupport/test/dependencies/requires_nonexistent1.rb @@ -1 +1,3 @@ +# frozen_string_literal: true + require_dependency "requires_nonexistent0" diff --git a/activesupport/test/dependencies/service_one.rb b/activesupport/test/dependencies/service_one.rb index afc3042269..2a4a39144d 100644 --- a/activesupport/test/dependencies/service_one.rb +++ b/activesupport/test/dependencies/service_one.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + $loaded_service_one ||= 0 $loaded_service_one += 1 diff --git a/activesupport/test/dependencies/service_two.rb b/activesupport/test/dependencies/service_two.rb index aabfc3c553..29cd73cbcd 100644 --- a/activesupport/test/dependencies/service_two.rb +++ b/activesupport/test/dependencies/service_two.rb @@ -1,2 +1,4 @@ +# frozen_string_literal: true + class ServiceTwo end diff --git a/activesupport/test/dependencies_test.rb b/activesupport/test/dependencies_test.rb index 1ea36418ff..d636da46d2 100644 --- a/activesupport/test/dependencies_test.rb +++ b/activesupport/test/dependencies_test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "abstract_unit" require "pp" require "active_support/dependencies" diff --git a/activesupport/test/dependencies_test_helpers.rb b/activesupport/test/dependencies_test_helpers.rb index 451195a143..b54a7e70c8 100644 --- a/activesupport/test/dependencies_test_helpers.rb +++ b/activesupport/test/dependencies_test_helpers.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module DependenciesTestHelpers def with_loading(*from) old_mechanism, ActiveSupport::Dependencies.mechanism = ActiveSupport::Dependencies.mechanism, :load diff --git a/activesupport/test/deprecation/method_wrappers_test.rb b/activesupport/test/deprecation/method_wrappers_test.rb index 85d057bb02..439e117c1d 100644 --- a/activesupport/test/deprecation/method_wrappers_test.rb +++ b/activesupport/test/deprecation/method_wrappers_test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "abstract_unit" require "active_support/deprecation" @@ -6,6 +8,16 @@ class MethodWrappersTest < ActiveSupport::TestCase @klass = Class.new do def new_method; "abc" end alias_method :old_method, :new_method + + protected + + def new_protected_method; "abc" end + alias_method :old_protected_method, :new_protected_method + + private + + def new_private_method; "abc" end + alias_method :old_private_method, :new_private_method end end @@ -31,4 +43,16 @@ class MethodWrappersTest < ActiveSupport::TestCase assert_deprecated(warning, deprecator) { assert_equal "abc", @klass.new.old_method } end + + def test_deprecate_methods_protected_method + ActiveSupport::Deprecation.deprecate_methods(@klass, old_protected_method: :new_protected_method) + + assert(@klass.protected_method_defined?(:old_protected_method)) + end + + def test_deprecate_methods_private_method + ActiveSupport::Deprecation.deprecate_methods(@klass, old_private_method: :new_private_method) + + assert(@klass.private_method_defined?(:old_private_method)) + end end diff --git a/activesupport/test/deprecation/proxy_wrappers_test.rb b/activesupport/test/deprecation/proxy_wrappers_test.rb index 67afd75c44..2f866775f6 100644 --- a/activesupport/test/deprecation/proxy_wrappers_test.rb +++ b/activesupport/test/deprecation/proxy_wrappers_test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "abstract_unit" require "active_support/deprecation" diff --git a/activesupport/test/deprecation_test.rb b/activesupport/test/deprecation_test.rb index 257cb50fb2..f2267a822f 100644 --- a/activesupport/test/deprecation_test.rb +++ b/activesupport/test/deprecation_test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "abstract_unit" require "active_support/testing/stream" diff --git a/activesupport/test/descendants_tracker_test_cases.rb b/activesupport/test/descendants_tracker_test_cases.rb index cf349d53ee..1f8b4a8605 100644 --- a/activesupport/test/descendants_tracker_test_cases.rb +++ b/activesupport/test/descendants_tracker_test_cases.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "set" module DescendantsTrackerTestCases diff --git a/activesupport/test/descendants_tracker_with_autoloading_test.rb b/activesupport/test/descendants_tracker_with_autoloading_test.rb index e202667a8a..7c396b7c8e 100644 --- a/activesupport/test/descendants_tracker_with_autoloading_test.rb +++ b/activesupport/test/descendants_tracker_with_autoloading_test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "abstract_unit" require "active_support/descendants_tracker" require "active_support/dependencies" diff --git a/activesupport/test/descendants_tracker_without_autoloading_test.rb b/activesupport/test/descendants_tracker_without_autoloading_test.rb index 72adc30ace..f5c6a3045d 100644 --- a/activesupport/test/descendants_tracker_without_autoloading_test.rb +++ b/activesupport/test/descendants_tracker_without_autoloading_test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "abstract_unit" require "active_support/descendants_tracker" require "descendants_tracker_test_cases" diff --git a/activesupport/test/digest_test.rb b/activesupport/test/digest_test.rb new file mode 100644 index 0000000000..83ff2a8d83 --- /dev/null +++ b/activesupport/test/digest_test.rb @@ -0,0 +1,27 @@ +# frozen_string_literal: true + +require "abstract_unit" +require "openssl" + +class DigestTest < ActiveSupport::TestCase + class InvalidDigest; end + def test_with_default_hash_digest_class + assert_equal ::Digest::MD5.hexdigest("hello friend"), ActiveSupport::Digest.hexdigest("hello friend") + end + + def test_with_custom_hash_digest_class + original_hash_digest_class = ActiveSupport::Digest.hash_digest_class + + ActiveSupport::Digest.hash_digest_class = ::Digest::SHA1 + digest = ActiveSupport::Digest.hexdigest("hello friend") + + assert_equal 32, digest.length + assert_equal ::Digest::SHA1.hexdigest("hello friend")[0...32], digest + ensure + ActiveSupport::Digest.hash_digest_class = original_hash_digest_class + end + + def test_should_raise_argument_error_if_custom_digest_is_missing_hexdigest_method + assert_raises(ArgumentError) { ActiveSupport::Digest.hash_digest_class = InvalidDigest } + end +end diff --git a/activesupport/test/encrypted_configuration_test.rb b/activesupport/test/encrypted_configuration_test.rb new file mode 100644 index 0000000000..93ccf457de --- /dev/null +++ b/activesupport/test/encrypted_configuration_test.rb @@ -0,0 +1,67 @@ +# frozen_string_literal: true + +require "abstract_unit" +require "active_support/encrypted_configuration" + +class EncryptedConfigurationTest < ActiveSupport::TestCase + setup do + @credentials_config_path = File.join(Dir.tmpdir, "credentials.yml.enc") + + @credentials_key_path = File.join(Dir.tmpdir, "master.key") + File.write(@credentials_key_path, ActiveSupport::EncryptedConfiguration.generate_key) + + @credentials = ActiveSupport::EncryptedConfiguration.new( + config_path: @credentials_config_path, key_path: @credentials_key_path, + env_key: "RAILS_MASTER_KEY", raise_if_missing_key: true + ) + end + + teardown do + FileUtils.rm_rf @credentials_config_path + FileUtils.rm_rf @credentials_key_path + end + + test "reading configuration by env key" do + FileUtils.rm_rf @credentials_key_path + + begin + ENV["RAILS_MASTER_KEY"] = ActiveSupport::EncryptedConfiguration.generate_key + @credentials.write({ something: { good: true, bad: false } }.to_yaml) + + assert @credentials[:something][:good] + assert_not @credentials.dig(:something, :bad) + assert_nil @credentials.fetch(:nothing, nil) + ensure + ENV["RAILS_MASTER_KEY"] = nil + end + end + + test "reading configuration by key file" do + @credentials.write({ something: { good: true } }.to_yaml) + + assert @credentials.something[:good] + end + + test "change configuration by key file" do + @credentials.write({ something: { good: true } }.to_yaml) + @credentials.change do |config_file| + config = YAML.load(config_file.read) + config_file.write config.merge(new: "things").to_yaml + end + + assert @credentials.something[:good] + assert_equal "things", @credentials[:new] + end + + test "raise error when writing an invalid format value" do + assert_raise(Psych::SyntaxError) do + @credentials.change do |config_file| + config_file.write "login: *login\n username: dummy" + end + end + end + + test "raises key error when accessing config via bang method" do + assert_raise(KeyError) { @credentials.something! } + end +end diff --git a/activesupport/test/encrypted_file_test.rb b/activesupport/test/encrypted_file_test.rb new file mode 100644 index 0000000000..ba3bbef903 --- /dev/null +++ b/activesupport/test/encrypted_file_test.rb @@ -0,0 +1,59 @@ +# frozen_string_literal: true + +require "abstract_unit" +require "active_support/encrypted_file" + +class EncryptedFileTest < ActiveSupport::TestCase + setup do + @content = "One little fox jumped over the hedge" + + @content_path = File.join(Dir.tmpdir, "content.txt.enc") + + @key_path = File.join(Dir.tmpdir, "content.txt.key") + File.write(@key_path, ActiveSupport::EncryptedFile.generate_key) + + @encrypted_file = ActiveSupport::EncryptedFile.new( + content_path: @content_path, key_path: @key_path, env_key: "CONTENT_KEY", raise_if_missing_key: true + ) + end + + teardown do + FileUtils.rm_rf @content_path + FileUtils.rm_rf @key_path + end + + test "reading content by env key" do + FileUtils.rm_rf @key_path + + begin + ENV["CONTENT_KEY"] = ActiveSupport::EncryptedFile.generate_key + @encrypted_file.write @content + + assert_equal @content, @encrypted_file.read + ensure + ENV["CONTENT_KEY"] = nil + end + end + + test "reading content by key file" do + @encrypted_file.write(@content) + assert_equal @content, @encrypted_file.read + end + + test "change content by key file" do + @encrypted_file.write(@content) + @encrypted_file.change do |file| + file.write(file.read + " and went by the lake") + end + + assert_equal "#{@content} and went by the lake", @encrypted_file.read + end + + test "raise MissingKeyError when key is missing" do + assert_raise(ActiveSupport::EncryptedFile::MissingKeyError) do + ActiveSupport::EncryptedFile.new( + content_path: @content_path, key_path: "", env_key: "", raise_if_missing_key: true + ).read + end + end +end diff --git a/activesupport/test/evented_file_update_checker_test.rb b/activesupport/test/evented_file_update_checker_test.rb index f33a5f5764..9b560f7f42 100644 --- a/activesupport/test/evented_file_update_checker_test.rb +++ b/activesupport/test/evented_file_update_checker_test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "abstract_unit" require "pathname" require "file_update_checker_shared_tests" diff --git a/activesupport/test/executor_test.rb b/activesupport/test/executor_test.rb index 7fefc066b3..af441064dd 100644 --- a/activesupport/test/executor_test.rb +++ b/activesupport/test/executor_test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "abstract_unit" class ExecutorTest < ActiveSupport::TestCase diff --git a/activesupport/test/file_update_checker_shared_tests.rb b/activesupport/test/file_update_checker_shared_tests.rb index 361e7e2349..f8266dac06 100644 --- a/activesupport/test/file_update_checker_shared_tests.rb +++ b/activesupport/test/file_update_checker_shared_tests.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "fileutils" module FileUpdateCheckerSharedTests diff --git a/activesupport/test/file_update_checker_test.rb b/activesupport/test/file_update_checker_test.rb index 55b0b46644..ec1df0df67 100644 --- a/activesupport/test/file_update_checker_test.rb +++ b/activesupport/test/file_update_checker_test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "abstract_unit" require "file_update_checker_shared_tests" diff --git a/activesupport/test/fixtures/autoload/another_class.rb b/activesupport/test/fixtures/autoload/another_class.rb index ab6e075ab4..cf38336cf8 100644 --- a/activesupport/test/fixtures/autoload/another_class.rb +++ b/activesupport/test/fixtures/autoload/another_class.rb @@ -1,2 +1,4 @@ +# frozen_string_literal: true + class Fixtures::AnotherClass end diff --git a/activesupport/test/fixtures/autoload/some_class.rb b/activesupport/test/fixtures/autoload/some_class.rb index 30d41eb0bf..ff25eb995e 100644 --- a/activesupport/test/fixtures/autoload/some_class.rb +++ b/activesupport/test/fixtures/autoload/some_class.rb @@ -1,2 +1,4 @@ +# frozen_string_literal: true + class Fixtures::Autoload::SomeClass end diff --git a/activesupport/test/gzip_test.rb b/activesupport/test/gzip_test.rb index 33e0cd2a04..05ce12fe86 100644 --- a/activesupport/test/gzip_test.rb +++ b/activesupport/test/gzip_test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "abstract_unit" require "active_support/core_ext/object/blank" diff --git a/activesupport/test/hash_with_indifferent_access_test.rb b/activesupport/test/hash_with_indifferent_access_test.rb index d68add46cd..41d653fa59 100644 --- a/activesupport/test/hash_with_indifferent_access_test.rb +++ b/activesupport/test/hash_with_indifferent_access_test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "abstract_unit" require "active_support/core_ext/hash" require "bigdecimal" @@ -397,6 +399,36 @@ class HashWithIndifferentAccessTest < ActiveSupport::TestCase assert_instance_of ActiveSupport::HashWithIndifferentAccess, indifferent_strings end + def test_indifferent_transform_keys + hash = ActiveSupport::HashWithIndifferentAccess.new(@strings).transform_keys { |k| k * 2 } + + assert_equal({ "aa" => 1, "bb" => 2 }, hash) + assert_instance_of ActiveSupport::HashWithIndifferentAccess, hash + end + + def test_indifferent_transform_keys_bang + indifferent_strings = ActiveSupport::HashWithIndifferentAccess.new(@strings) + indifferent_strings.transform_keys! { |k| k * 2 } + + assert_equal({ "aa" => 1, "bb" => 2 }, indifferent_strings) + assert_instance_of ActiveSupport::HashWithIndifferentAccess, indifferent_strings + end + + def test_indifferent_transform_values + hash = ActiveSupport::HashWithIndifferentAccess.new(@strings).transform_values { |v| v * 2 } + + assert_equal({ "a" => 2, "b" => 4 }, hash) + assert_instance_of ActiveSupport::HashWithIndifferentAccess, hash + end + + def test_indifferent_transform_values_bang + indifferent_strings = ActiveSupport::HashWithIndifferentAccess.new(@strings) + indifferent_strings.transform_values! { |v| v * 2 } + + assert_equal({ "a" => 2, "b" => 4 }, indifferent_strings) + assert_instance_of ActiveSupport::HashWithIndifferentAccess, indifferent_strings + end + def test_indifferent_compact hash_contain_nil_value = @strings.merge("z" => nil) hash = ActiveSupport::HashWithIndifferentAccess.new(hash_contain_nil_value) @@ -535,6 +567,32 @@ class HashWithIndifferentAccessTest < ActiveSupport::TestCase assert_equal 1234, data.dig(:this, :views) end + def test_argless_default_with_existing_nil_key + h = Hash.new(:default).merge(nil => "defined").with_indifferent_access + + assert_equal :default, h.default + end + + def test_default_with_argument + h = Hash.new { 5 }.merge(1 => 2).with_indifferent_access + + assert_equal 5, h.default(1) + end + + def test_default_proc + h = ActiveSupport::HashWithIndifferentAccess.new { |hash, key| key } + + assert_nil h.default + assert_equal "foo", h.default("foo") + assert_equal "foo", h.default(:foo) + end + + def test_double_conversion_with_nil_key + h = { nil => "defined" }.with_indifferent_access.with_indifferent_access + + assert_nil h[:undefined_key] + end + def test_assorted_keys_not_stringified original = { Object.new => 2, 1 => 2, [] => true } indiff = original.with_indifferent_access diff --git a/activesupport/test/i18n_test.rb b/activesupport/test/i18n_test.rb index 7d88d2dc6b..8ad9441f9d 100644 --- a/activesupport/test/i18n_test.rb +++ b/activesupport/test/i18n_test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "abstract_unit" require "active_support/time" require "active_support/core_ext/array/conversions" diff --git a/activesupport/test/inflector_test.rb b/activesupport/test/inflector_test.rb index ef956eda90..0e3e576a70 100644 --- a/activesupport/test/inflector_test.rb +++ b/activesupport/test/inflector_test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "abstract_unit" require "active_support/inflector" @@ -222,6 +224,12 @@ class InflectorTest < ActiveSupport::TestCase assert_equal("json_html_api", ActiveSupport::Inflector.underscore("JSONHTMLAPI")) end + def test_acronym_regexp_is_deprecated + assert_deprecated do + ActiveSupport::Inflector.inflections.acronym_regex + end + end + def test_underscore CamelToUnderscore.each do |camel, underscore| assert_equal(underscore, ActiveSupport::Inflector.underscore(camel)) @@ -354,6 +362,19 @@ class InflectorTest < ActiveSupport::TestCase assert_equal("Col rpted bugs", ActiveSupport::Inflector.humanize("COL_rpted_bugs")) end + def test_humanize_with_acronyms + ActiveSupport::Inflector.inflections do |inflect| + inflect.acronym "LAX" + inflect.acronym "SFO" + end + assert_equal("LAX roundtrip to SFO", ActiveSupport::Inflector.humanize("LAX ROUNDTRIP TO SFO")) + assert_equal("LAX roundtrip to SFO", ActiveSupport::Inflector.humanize("LAX ROUNDTRIP TO SFO", capitalize: false)) + assert_equal("LAX roundtrip to SFO", ActiveSupport::Inflector.humanize("lax roundtrip to sfo")) + assert_equal("LAX roundtrip to SFO", ActiveSupport::Inflector.humanize("lax roundtrip to sfo", capitalize: false)) + assert_equal("LAX roundtrip to SFO", ActiveSupport::Inflector.humanize("Lax Roundtrip To Sfo")) + assert_equal("LAX roundtrip to SFO", ActiveSupport::Inflector.humanize("Lax Roundtrip To Sfo", capitalize: false)) + end + def test_constantize run_constantize_tests_on do |string| ActiveSupport::Inflector.constantize(string) diff --git a/activesupport/test/inflector_test_cases.rb b/activesupport/test/inflector_test_cases.rb index d61ca3fc18..689370cccf 100644 --- a/activesupport/test/inflector_test_cases.rb +++ b/activesupport/test/inflector_test_cases.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module InflectorTestCases SingularToPlural = { "search" => "searches", @@ -219,7 +221,7 @@ module InflectorTestCases "Test with malformed utf8 \251" => "test_with_malformed_utf8" } - StringToParameterizePreserceCaseWithUnderscore = { + StringToParameterizePreserveCaseWithUnderscore = { "Donald E. Knuth" => "Donald_E_Knuth", "Random text with *(bad)* characters" => "Random_text_with_bad_characters", "With-some-dashes" => "With-some-dashes", diff --git a/activesupport/test/json/decoding_test.rb b/activesupport/test/json/decoding_test.rb index 6f5051c312..8d9587f248 100644 --- a/activesupport/test/json/decoding_test.rb +++ b/activesupport/test/json/decoding_test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "abstract_unit" require "active_support/json" require "active_support/time" diff --git a/activesupport/test/json/encoding_test.rb b/activesupport/test/json/encoding_test.rb index 6d8f7cfbd0..340a2abf75 100644 --- a/activesupport/test/json/encoding_test.rb +++ b/activesupport/test/json/encoding_test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "securerandom" require "abstract_unit" require "active_support/core_ext/string/inflections" @@ -98,11 +100,11 @@ class TestJSONEncoding < ActiveSupport::TestCase end def test_hash_should_allow_key_filtering_with_only - assert_equal %({"a":1}), ActiveSupport::JSON.encode({ "a" => 1, :b => 2, :c => 3 }, only: "a") + assert_equal %({"a":1}), ActiveSupport::JSON.encode({ "a" => 1, :b => 2, :c => 3 }, { only: "a" }) end def test_hash_should_allow_key_filtering_with_except - assert_equal %({"b":2}), ActiveSupport::JSON.encode({ "foo" => "bar", :b => 2, :c => 3 }, except: ["foo", :c]) + assert_equal %({"b":2}), ActiveSupport::JSON.encode({ "foo" => "bar", :b => 2, :c => 3 }, { except: ["foo", :c] }) end def test_time_to_json_includes_local_offset @@ -185,7 +187,7 @@ class TestJSONEncoding < ActiveSupport::TestCase def test_array_should_pass_encoding_options_to_children_in_as_json people = [ { name: "John", address: { city: "London", country: "UK" } }, - { name: "Jean", address: { city: "Paris" , country: "France" } } + { name: "Jean", address: { city: "Paris", country: "France" } } ] json = people.as_json only: [:address, :city] expected = [ @@ -199,7 +201,7 @@ class TestJSONEncoding < ActiveSupport::TestCase def test_array_should_pass_encoding_options_to_children_in_to_json people = [ { name: "John", address: { city: "London", country: "UK" } }, - { name: "Jean", address: { city: "Paris" , country: "France" } } + { name: "Jean", address: { city: "Paris", country: "France" } } ] json = people.to_json only: [:address, :city] @@ -208,10 +210,10 @@ class TestJSONEncoding < ActiveSupport::TestCase People = Class.new(BasicObject) do include Enumerable - def initialize() + def initialize @people = [ { name: "John", address: { city: "London", country: "UK" } }, - { name: "Jean", address: { city: "Paris" , country: "France" } } + { name: "Jean", address: { city: "Paris", country: "France" } } ] end def each(*, &blk) @@ -452,6 +454,10 @@ EXPECTED assert_equal '{"number":null}', NaNNumber.new.to_json end + def test_to_json_works_on_io_objects + assert_equal STDOUT.to_s.to_json, STDOUT.to_json + end + private def object_keys(json_object) diff --git a/activesupport/test/json/encoding_test_cases.rb b/activesupport/test/json/encoding_test_cases.rb index 7e4775cec8..5a4700459f 100644 --- a/activesupport/test/json/encoding_test_cases.rb +++ b/activesupport/test/json/encoding_test_cases.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "bigdecimal" require "date" require "time" diff --git a/activesupport/test/key_generator_test.rb b/activesupport/test/key_generator_test.rb index 89db9563ac..a948cfbd8e 100644 --- a/activesupport/test/key_generator_test.rb +++ b/activesupport/test/key_generator_test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "abstract_unit" begin diff --git a/activesupport/test/lazy_load_hooks_test.rb b/activesupport/test/lazy_load_hooks_test.rb index 3b1959a1c9..721d44d0c1 100644 --- a/activesupport/test/lazy_load_hooks_test.rb +++ b/activesupport/test/lazy_load_hooks_test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "abstract_unit" class LazyLoadHooksTest < ActiveSupport::TestCase @@ -18,6 +20,23 @@ class LazyLoadHooksTest < ActiveSupport::TestCase assert_equal 7, i end + def test_basic_hook_with_two_registrations_only_once + i = 0 + block = proc { i += incr } + ActiveSupport.on_load(:basic_hook_with_two_once, run_once: true, &block) + ActiveSupport.on_load(:basic_hook_with_two_once) do + i += incr + end + + ActiveSupport.on_load(:different_hook, run_once: true, &block) + ActiveSupport.run_load_hooks(:different_hook, FakeContext.new(2)) + assert_equal 2, i + ActiveSupport.run_load_hooks(:basic_hook_with_two_once, FakeContext.new(2)) + assert_equal 6, i + ActiveSupport.run_load_hooks(:basic_hook_with_two_once, FakeContext.new(5)) + assert_equal 11, i + end + def test_hook_registered_after_run i = 0 ActiveSupport.run_load_hooks(:registered_after) @@ -35,6 +54,15 @@ class LazyLoadHooksTest < ActiveSupport::TestCase assert_equal 7, i end + def test_hook_registered_after_run_with_two_registrations_only_once + i = 0 + ActiveSupport.run_load_hooks(:registered_after_with_two_once, FakeContext.new(2)) + ActiveSupport.run_load_hooks(:registered_after_with_two_once, FakeContext.new(5)) + assert_equal 0, i + ActiveSupport.on_load(:registered_after_with_two_once, run_once: true) { i += incr } + assert_equal 2, i + end + def test_hook_registered_interleaved_run_with_two_registrations i = 0 ActiveSupport.run_load_hooks(:registered_interleaved_with_two, FakeContext.new(2)) @@ -45,6 +73,22 @@ class LazyLoadHooksTest < ActiveSupport::TestCase assert_equal 7, i end + def test_hook_registered_interleaved_run_with_two_registrations_once + i = 0 + ActiveSupport + .run_load_hooks(:registered_interleaved_with_two_once, FakeContext.new(2)) + assert_equal 0, i + + ActiveSupport.on_load(:registered_interleaved_with_two_once, run_once: true) do + i += incr + end + assert_equal 2, i + + ActiveSupport + .run_load_hooks(:registered_interleaved_with_two_once, FakeContext.new(5)) + assert_equal 2, i + end + def test_hook_receives_a_context i = 0 ActiveSupport.on_load(:contextual) { i += incr } diff --git a/activesupport/test/log_subscriber_test.rb b/activesupport/test/log_subscriber_test.rb index f6496ef7d6..2af9b1de30 100644 --- a/activesupport/test/log_subscriber_test.rb +++ b/activesupport/test/log_subscriber_test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "abstract_unit" require "active_support/log_subscriber/test_helper" diff --git a/activesupport/test/logger_test.rb b/activesupport/test/logger_test.rb index 1bc443ae65..5efbd10a7d 100644 --- a/activesupport/test/logger_test.rb +++ b/activesupport/test/logger_test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "abstract_unit" require "multibyte_test_helpers" require "stringio" diff --git a/activesupport/test/message_encryptor_test.rb b/activesupport/test/message_encryptor_test.rb index 4c3515b5e1..9edf07f762 100644 --- a/activesupport/test/message_encryptor_test.rb +++ b/activesupport/test/message_encryptor_test.rb @@ -1,7 +1,10 @@ +# frozen_string_literal: true + require "abstract_unit" require "openssl" require "active_support/time" require "active_support/json" +require_relative "metadata/shared_metadata_tests" class MessageEncryptorTest < ActiveSupport::TestCase class JSONSerializer @@ -104,8 +107,81 @@ class MessageEncryptorTest < ActiveSupport::TestCase assert_aead_not_decrypted(encryptor, [text, iv, auth_tag[0..-2]] * "--") end - private + def test_backwards_compatibility_decrypt_previously_encrypted_messages_without_metadata + secret = "\xB7\xF0\xBCW\xB1\x18`\xAB\xF0\x81\x10\xA4$\xF44\xEC\xA1\xDC\xC1\xDDD\xAF\xA9\xB8\x14\xCD\x18\x9A\x99 \x80)" + encryptor = ActiveSupport::MessageEncryptor.new(secret, cipher: "aes-256-gcm") + encrypted_message = "9cVnFs2O3lL9SPvIJuxBOLS51nDiBMw=--YNI5HAfHEmZ7VDpl--ddFJ6tXA0iH+XGcCgMINYQ==" + + assert_equal "Ruby on Rails", encryptor.decrypt_and_verify(encrypted_message) + end + + def test_rotating_secret + old_message = ActiveSupport::MessageEncryptor.new(secrets[:old], cipher: "aes-256-gcm").encrypt_and_sign("old") + + encryptor = ActiveSupport::MessageEncryptor.new(@secret, cipher: "aes-256-gcm") + encryptor.rotate secrets[:old] + + assert_equal "old", encryptor.decrypt_and_verify(old_message) + end + + def test_rotating_serializer + old_message = ActiveSupport::MessageEncryptor.new(secrets[:old], cipher: "aes-256-gcm", serializer: JSON). + encrypt_and_sign(ahoy: :hoy) + + encryptor = ActiveSupport::MessageEncryptor.new(@secret, cipher: "aes-256-gcm", serializer: JSON) + encryptor.rotate secrets[:old] + + assert_equal({ "ahoy" => "hoy" }, encryptor.decrypt_and_verify(old_message)) + end + + def test_rotating_aes_cbc_secrets + old_encryptor = ActiveSupport::MessageEncryptor.new(secrets[:old], "old sign", cipher: "aes-256-cbc") + old_message = old_encryptor.encrypt_and_sign("old") + + encryptor = ActiveSupport::MessageEncryptor.new(@secret) + encryptor.rotate secrets[:old], "old sign", cipher: "aes-256-cbc" + + assert_equal "old", encryptor.decrypt_and_verify(old_message) + end + + def test_multiple_rotations + older_message = ActiveSupport::MessageEncryptor.new(secrets[:older], "older sign").encrypt_and_sign("older") + old_message = ActiveSupport::MessageEncryptor.new(secrets[:old], "old sign").encrypt_and_sign("old") + + encryptor = ActiveSupport::MessageEncryptor.new(@secret) + encryptor.rotate secrets[:old], "old sign" + encryptor.rotate secrets[:older], "older sign" + + assert_equal "new", encryptor.decrypt_and_verify(encryptor.encrypt_and_sign("new")) + assert_equal "old", encryptor.decrypt_and_verify(old_message) + assert_equal "older", encryptor.decrypt_and_verify(older_message) + end + + def test_on_rotation_is_called_and_returns_modified_messages + older_message = ActiveSupport::MessageEncryptor.new(secrets[:older], "older sign").encrypt_and_sign(encoded: "message") + + encryptor = ActiveSupport::MessageEncryptor.new(@secret) + encryptor.rotate secrets[:old] + encryptor.rotate secrets[:older], "older sign" + + rotated = false + message = encryptor.decrypt_and_verify(older_message, on_rotation: proc { rotated = true }) + + assert_equal({ encoded: "message" }, message) + assert rotated + end + + def test_with_rotated_metadata + old_message = ActiveSupport::MessageEncryptor.new(secrets[:old], cipher: "aes-256-gcm"). + encrypt_and_sign("metadata", purpose: :rotation) + encryptor = ActiveSupport::MessageEncryptor.new(@secret, cipher: "aes-256-gcm") + encryptor.rotate secrets[:old] + + assert_equal "metadata", encryptor.decrypt_and_verify(old_message, purpose: :rotation) + end + + private def assert_aead_not_decrypted(encryptor, value) assert_raise(ActiveSupport::MessageEncryptor::InvalidMessage) do encryptor.decrypt_and_verify(value) @@ -124,9 +200,47 @@ class MessageEncryptorTest < ActiveSupport::TestCase end end + def secrets + @secrets ||= Hash.new { |h, k| h[k] = SecureRandom.random_bytes(32) } + end + def munge(base64_string) bits = ::Base64.strict_decode64(base64_string) bits.reverse! ::Base64.strict_encode64(bits) end end + +class MessageEncryptorMetadataTest < ActiveSupport::TestCase + include SharedMessageMetadataTests + + setup do + @secret = SecureRandom.random_bytes(32) + @encryptor = ActiveSupport::MessageEncryptor.new(@secret, encryptor_options) + end + + private + def generate(message, **options) + @encryptor.encrypt_and_sign(message, options) + end + + def parse(data, **options) + @encryptor.decrypt_and_verify(data, options) + end + + def encryptor_options; end +end + +class MessageEncryptorMetadataMarshalTest < MessageEncryptorMetadataTest + private + def encryptor_options + { serializer: Marshal } + end +end + +class MessageEncryptorMetadataJSONTest < MessageEncryptorMetadataTest + private + def encryptor_options + { serializer: MessageEncryptorTest::JSONSerializer.new } + end +end diff --git a/activesupport/test/message_verifier_test.rb b/activesupport/test/message_verifier_test.rb index d6109c761d..05d5c1cbc3 100644 --- a/activesupport/test/message_verifier_test.rb +++ b/activesupport/test/message_verifier_test.rb @@ -1,7 +1,10 @@ +# frozen_string_literal: true + require "abstract_unit" require "openssl" require "active_support/time" require "active_support/json" +require_relative "metadata/shared_metadata_tests" class MessageVerifierTest < ActiveSupport::TestCase class JSONSerializer @@ -16,7 +19,8 @@ class MessageVerifierTest < ActiveSupport::TestCase def setup @verifier = ActiveSupport::MessageVerifier.new("Hey, I'm a secret!") - @data = { some: "data", now: Time.local(2010) } + @data = { some: "data", now: Time.utc(2010) } + @secret = SecureRandom.random_bytes(32) end def test_valid_message @@ -82,4 +86,119 @@ class MessageVerifierTest < ActiveSupport::TestCase end assert_equal "Secret should not be nil.", exception.message end + + def test_backward_compatibility_messages_signed_without_metadata + signed_message = "BAh7BzoJc29tZUkiCWRhdGEGOgZFVDoIbm93SXU6CVRpbWUNIIAbgAAAAAAHOgtvZmZzZXRpADoJem9uZUkiCFVUQwY7BkY=--d03c52c91dfe4ccc5159417c660461bcce005e96" + assert_equal @data, @verifier.verify(signed_message) + end + + def test_rotating_secret + old_message = ActiveSupport::MessageVerifier.new("old", digest: "SHA1").generate("old") + + verifier = ActiveSupport::MessageVerifier.new(@secret, digest: "SHA1") + verifier.rotate "old" + + assert_equal "old", verifier.verified(old_message) + end + + def test_multiple_rotations + old_message = ActiveSupport::MessageVerifier.new("old", digest: "SHA256").generate("old") + older_message = ActiveSupport::MessageVerifier.new("older", digest: "SHA1").generate("older") + + verifier = ActiveSupport::MessageVerifier.new(@secret, digest: "SHA512") + verifier.rotate "old", digest: "SHA256" + verifier.rotate "older", digest: "SHA1" + + assert_equal "new", verifier.verified(verifier.generate("new")) + assert_equal "old", verifier.verified(old_message) + assert_equal "older", verifier.verified(older_message) + end + + def test_on_rotation_is_called_and_verified_returns_message + older_message = ActiveSupport::MessageVerifier.new("older", digest: "SHA1").generate(encoded: "message") + + verifier = ActiveSupport::MessageVerifier.new(@secret, digest: "SHA512") + verifier.rotate "old", digest: "SHA256" + verifier.rotate "older", digest: "SHA1" + + rotated = false + message = verifier.verified(older_message, on_rotation: proc { rotated = true }) + + assert_equal({ encoded: "message" }, message) + assert rotated + end + + def test_rotations_with_metadata + old_message = ActiveSupport::MessageVerifier.new("old").generate("old", purpose: :rotation) + + verifier = ActiveSupport::MessageVerifier.new(@secret) + verifier.rotate "old" + + assert_equal "old", verifier.verified(old_message, purpose: :rotation) + end +end + +class MessageVerifierMetadataTest < ActiveSupport::TestCase + include SharedMessageMetadataTests + + setup do + @verifier = ActiveSupport::MessageVerifier.new("Hey, I'm a secret!", verifier_options) + end + + def test_verify_raises_when_purpose_differs + assert_raise(ActiveSupport::MessageVerifier::InvalidSignature) do + @verifier.verify(generate(data, purpose: "payment"), purpose: "shipping") + end + end + + def test_verify_raises_when_expired + signed_message = generate(data, expires_in: 1.month) + + travel 2.months + assert_raise(ActiveSupport::MessageVerifier::InvalidSignature) do + @verifier.verify(signed_message) + end + end + + private + def generate(message, **options) + @verifier.generate(message, options) + end + + def parse(message, **options) + @verifier.verified(message, options) + end + + def verifier_options + Hash.new + end +end + +class MessageVerifierMetadataMarshalTest < MessageVerifierMetadataTest + private + def verifier_options + { serializer: Marshal } + end +end + +class MessageVerifierMetadataJSONTest < MessageVerifierMetadataTest + private + def verifier_options + { serializer: MessageVerifierTest::JSONSerializer.new } + end +end + +class MessageEncryptorMetadataNullSerializerTest < MessageVerifierMetadataTest + private + def data + "string message" + end + + def null_serializing? + true + end + + def verifier_options + { serializer: ActiveSupport::MessageEncryptor::NullSerializer } + end end diff --git a/activesupport/test/messages/rotation_configuration_test.rb b/activesupport/test/messages/rotation_configuration_test.rb new file mode 100644 index 0000000000..2f6824ed21 --- /dev/null +++ b/activesupport/test/messages/rotation_configuration_test.rb @@ -0,0 +1,25 @@ +# frozen_string_literal: true + +require "abstract_unit" +require "active_support/messages/rotation_configuration" + +class MessagesRotationConfiguration < ActiveSupport::TestCase + def setup + @config = ActiveSupport::Messages::RotationConfiguration.new + end + + def test_signed_configurations + @config.rotate :signed, "older secret", salt: "salt", digest: "SHA1" + @config.rotate :signed, "old secret", salt: "salt", digest: "SHA256" + + assert_equal [ + [ "older secret", salt: "salt", digest: "SHA1" ], + [ "old secret", salt: "salt", digest: "SHA256" ] ], @config.signed + end + + def test_encrypted_configurations + @config.rotate :encrypted, "old raw key", cipher: "aes-256-gcm" + + assert_equal [ [ "old raw key", cipher: "aes-256-gcm" ] ], @config.encrypted + end +end diff --git a/activesupport/test/metadata/shared_metadata_tests.rb b/activesupport/test/metadata/shared_metadata_tests.rb new file mode 100644 index 0000000000..08bb0c648e --- /dev/null +++ b/activesupport/test/metadata/shared_metadata_tests.rb @@ -0,0 +1,93 @@ +# frozen_string_literal: true + +module SharedMessageMetadataTests + def teardown + travel_back + super + end + + def null_serializing? + false + end + + def test_encryption_and_decryption_with_same_purpose + assert_equal data, parse(generate(data, purpose: "checkout"), purpose: "checkout") + assert_equal data, parse(generate(data)) + + string_message = "address: #23, main street" + assert_equal string_message, parse(generate(string_message, purpose: "shipping"), purpose: "shipping") + end + + def test_verifies_array_when_purpose_matches + unless null_serializing? + data = [ "credit_card_no: 5012-6748-9087-5678", { "card_holder" => "Donald", "issued_on" => Time.local(2017) }, 12345 ] + assert_equal data, parse(generate(data, purpose: :registration), purpose: :registration) + end + end + + def test_encryption_and_decryption_with_different_purposes_returns_nil + assert_nil parse(generate(data, purpose: "payment"), purpose: "sign up") + assert_nil parse(generate(data, purpose: "payment")) + assert_nil parse(generate(data), purpose: "sign up") + end + + def test_purpose_using_symbols + assert_equal data, parse(generate(data, purpose: :checkout), purpose: :checkout) + assert_equal data, parse(generate(data, purpose: :checkout), purpose: "checkout") + assert_equal data, parse(generate(data, purpose: "checkout"), purpose: :checkout) + end + + def test_passing_expires_at_sets_expiration_date + encrypted_message = generate(data, expires_at: 1.hour.from_now) + + travel 59.minutes + assert_equal data, parse(encrypted_message) + + travel 2.minutes + assert_nil parse(encrypted_message) + end + + def test_set_relative_expiration_date_by_passing_expires_in + encrypted_message = generate(data, expires_in: 2.hours) + + travel 1.hour + assert_equal data, parse(encrypted_message) + + travel 1.hour + 1.second + assert_nil parse(encrypted_message) + end + + def test_passing_expires_in_less_than_a_second_is_not_expired + freeze_time do + encrypted_message = generate(data, expires_in: 1.second) + + travel 0.5.seconds + assert_equal data, parse(encrypted_message) + + travel 1.second + assert_nil parse(encrypted_message) + end + end + + def test_favor_expires_at_over_expires_in + payment_related_message = generate(data, purpose: "payment", expires_at: 2.year.from_now, expires_in: 1.second) + + travel 1.year + assert_equal data, parse(payment_related_message, purpose: :payment) + + travel 1.year + 1.day + assert_nil parse(payment_related_message, purpose: "payment") + end + + def test_skip_expires_at_and_expires_in_to_disable_expiration_check + payment_related_message = generate(data, purpose: "payment") + + travel 100.years + assert_equal data, parse(payment_related_message, purpose: "payment") + end + + private + def data + { "credit_card_no" => "5012-6784-9087-5678", "card_holder" => { "name" => "Donald" } } + end +end diff --git a/activesupport/test/multibyte_chars_test.rb b/activesupport/test/multibyte_chars_test.rb index 16a7d488c7..f51fbe2671 100644 --- a/activesupport/test/multibyte_chars_test.rb +++ b/activesupport/test/multibyte_chars_test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "abstract_unit" require "multibyte_test_helpers" require "active_support/core_ext/string/multibyte" diff --git a/activesupport/test/multibyte_conformance_test.rb b/activesupport/test/multibyte_conformance_test.rb index ef1a26135f..748e8d16e1 100644 --- a/activesupport/test/multibyte_conformance_test.rb +++ b/activesupport/test/multibyte_conformance_test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "abstract_unit" require "multibyte_test_helpers" diff --git a/activesupport/test/multibyte_grapheme_break_conformance_test.rb b/activesupport/test/multibyte_grapheme_break_conformance_test.rb index b3328987ae..fac74cd80f 100644 --- a/activesupport/test/multibyte_grapheme_break_conformance_test.rb +++ b/activesupport/test/multibyte_grapheme_break_conformance_test.rb @@ -1,4 +1,4 @@ -# encoding: utf-8 +# frozen_string_literal: true require "abstract_unit" require "multibyte_test_helpers" diff --git a/activesupport/test/multibyte_normalization_conformance_test.rb b/activesupport/test/multibyte_normalization_conformance_test.rb index ebc9f92d23..1173a94e81 100644 --- a/activesupport/test/multibyte_normalization_conformance_test.rb +++ b/activesupport/test/multibyte_normalization_conformance_test.rb @@ -1,4 +1,4 @@ -# encoding: utf-8 +# frozen_string_literal: true require "abstract_unit" require "multibyte_test_helpers" diff --git a/activesupport/test/multibyte_proxy_test.rb b/activesupport/test/multibyte_proxy_test.rb index c303097f80..ecedab2569 100644 --- a/activesupport/test/multibyte_proxy_test.rb +++ b/activesupport/test/multibyte_proxy_test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "abstract_unit" class MultibyteProxyText < ActiveSupport::TestCase diff --git a/activesupport/test/multibyte_test_helpers.rb b/activesupport/test/multibyte_test_helpers.rb index e1e0ae86d9..f7cf993100 100644 --- a/activesupport/test/multibyte_test_helpers.rb +++ b/activesupport/test/multibyte_test_helpers.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module MultibyteTestHelpers class Downloader def self.download(from, to) diff --git a/activesupport/test/multibyte_unicode_database_test.rb b/activesupport/test/multibyte_unicode_database_test.rb index 3724782930..540a34493d 100644 --- a/activesupport/test/multibyte_unicode_database_test.rb +++ b/activesupport/test/multibyte_unicode_database_test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "abstract_unit" class MultibyteUnicodeDatabaseTest < ActiveSupport::TestCase diff --git a/activesupport/test/notifications/evented_notification_test.rb b/activesupport/test/notifications/evented_notification_test.rb index 24c5befec3..4beb8194b9 100644 --- a/activesupport/test/notifications/evented_notification_test.rb +++ b/activesupport/test/notifications/evented_notification_test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "abstract_unit" module ActiveSupport diff --git a/activesupport/test/notifications/instrumenter_test.rb b/activesupport/test/notifications/instrumenter_test.rb index 7eacc5cbe7..1d76c91d30 100644 --- a/activesupport/test/notifications/instrumenter_test.rb +++ b/activesupport/test/notifications/instrumenter_test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "abstract_unit" require "active_support/notifications/instrumenter" diff --git a/activesupport/test/notifications_test.rb b/activesupport/test/notifications_test.rb index 11f743519f..5cfbd60131 100644 --- a/activesupport/test/notifications_test.rb +++ b/activesupport/test/notifications_test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "abstract_unit" require "active_support/core_ext/module/delegation" diff --git a/activesupport/test/number_helper_i18n_test.rb b/activesupport/test/number_helper_i18n_test.rb index a1d1c41dc2..365fa96f4d 100644 --- a/activesupport/test/number_helper_i18n_test.rb +++ b/activesupport/test/number_helper_i18n_test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "abstract_unit" require "active_support/number_helper" require "active_support/core_ext/hash/keys" @@ -33,7 +35,7 @@ module ActiveSupport thousand: "t", million: "m", billion: "b", - trillion: "t" , + trillion: "t", quadrillion: "q" } } @@ -75,10 +77,10 @@ module ActiveSupport end def test_number_with_i18n_precision - #Delimiter was set to "" + # Delimiter was set to "" assert_equal("10000", number_to_rounded(10000, locale: "ts")) - #Precision inherited and significant was set + # Precision inherited and significant was set assert_equal("1.00", number_to_rounded(1.0, locale: "ts")) end @@ -88,7 +90,7 @@ module ActiveSupport end def test_number_with_i18n_delimiter - #Delimiter "," and separator "." + # Delimiter "," and separator "." assert_equal("1,000,000.234", number_to_delimited(1000000.234, locale: "ts")) end @@ -112,7 +114,7 @@ module ActiveSupport end def test_number_to_i18n_human_size - #b for bytes and k for kbytes + # b for bytes and k for kbytes assert_equal("2 k", number_to_human_size(2048, locale: "ts")) assert_equal("42 b", number_to_human_size(42, locale: "ts")) end @@ -123,11 +125,11 @@ module ActiveSupport end def test_number_to_human_with_default_translation_scope - #Using t for thousand + # Using t for thousand assert_equal "2 t", number_to_human(2000, locale: "ts") - #Significant was set to true with precision 2, using b for billion + # Significant was set to true with precision 2, using b for billion assert_equal "1.2 b", number_to_human(1234567890, locale: "ts") - #Using pluralization (Ten/Tens and Tenth/Tenths) + # Using pluralization (Ten/Tens and Tenth/Tenths) assert_equal "1 Tenth", number_to_human(0.1, locale: "ts") assert_equal "1.3 Tenth", number_to_human(0.134, locale: "ts") assert_equal "2 Tenths", number_to_human(0.2, locale: "ts") @@ -142,7 +144,7 @@ module ActiveSupport end def test_number_to_human_with_custom_translation_scope - #Significant was set to true with precision 2, with custom translated units + # Significant was set to true with precision 2, with custom translated units assert_equal "4.3 cm", number_to_human(0.0432, locale: "ts", units: :custom_units_for_number_to_human) end end diff --git a/activesupport/test/number_helper_test.rb b/activesupport/test/number_helper_test.rb index 4caf1428ea..16ccc5572c 100644 --- a/activesupport/test/number_helper_test.rb +++ b/activesupport/test/number_helper_test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "abstract_unit" require "active_support/number_helper" require "active_support/core_ext/string/output_safety" @@ -258,7 +260,7 @@ module ActiveSupport assert_equal "40 KB", number_helper.number_to_human_size(41100, precision: 2) assert_equal "1.0 KB", number_helper.number_to_human_size(kilobytes(1.0123), precision: 2, strip_insignificant_zeros: false) assert_equal "1.012 KB", number_helper.number_to_human_size(kilobytes(1.0123), precision: 3, significant: false) - assert_equal "1 KB", number_helper.number_to_human_size(kilobytes(1.0123), precision: 0, significant: true) #ignores significant it precision is 0 + assert_equal "1 KB", number_helper.number_to_human_size(kilobytes(1.0123), precision: 0, significant: true) # ignores significant it precision is 0 end end @@ -290,7 +292,7 @@ module ActiveSupport assert_equal "489.0 Thousand", number_helper.number_to_human(489000, precision: 4, strip_insignificant_zeros: false) assert_equal "1.2346 Million", number_helper.number_to_human(1234567, precision: 4, significant: false) assert_equal "1,2 Million", number_helper.number_to_human(1234567, precision: 1, significant: false, separator: ",") - assert_equal "1 Million", number_helper.number_to_human(1234567, precision: 0, significant: true, separator: ",") #significant forced to false + assert_equal "1 Million", number_helper.number_to_human(1234567, precision: 0, significant: true, separator: ",") # significant forced to false assert_equal "1 Million", number_helper.number_to_human(999999) assert_equal "1 Billion", number_helper.number_to_human(999999999) end @@ -298,13 +300,13 @@ module ActiveSupport def test_number_to_human_with_custom_units [@instance_with_helpers, TestClassWithClassNumberHelpers, ActiveSupport::NumberHelper].each do |number_helper| - #Only integers + # Only integers volume = { unit: "ml", thousand: "lt", million: "m3" } assert_equal "123 lt", number_helper.number_to_human(123456, units: volume) assert_equal "12 ml", number_helper.number_to_human(12, units: volume) assert_equal "1.23 m3", number_helper.number_to_human(1234567, units: volume) - #Including fractionals + # Including fractionals distance = { mili: "mm", centi: "cm", deci: "dm", unit: "m", ten: "dam", hundred: "hm", thousand: "km" } assert_equal "1.23 mm", number_helper.number_to_human(0.00123, units: distance) assert_equal "1.23 cm", number_helper.number_to_human(0.0123, units: distance) @@ -317,7 +319,7 @@ module ActiveSupport assert_equal "1.23 km", number_helper.number_to_human(1230, units: distance) assert_equal "12.3 km", number_helper.number_to_human(12300, units: distance) - #The quantifiers don't need to be a continuous sequence + # The quantifiers don't need to be a continuous sequence gangster = { hundred: "hundred bucks", million: "thousand quids" } assert_equal "1 hundred bucks", number_helper.number_to_human(100, units: gangster) assert_equal "25 hundred bucks", number_helper.number_to_human(2500, units: gangster) @@ -327,11 +329,11 @@ module ActiveSupport assert_equal "25 thousand quids", number_helper.number_to_human(25000000, units: gangster) assert_equal "12300 thousand quids", number_helper.number_to_human(12345000000, units: gangster) - #Spaces are stripped from the resulting string + # Spaces are stripped from the resulting string assert_equal "4", number_helper.number_to_human(4, units: { unit: "", ten: "tens " }) assert_equal "4.5 tens", number_helper.number_to_human(45, units: { unit: "", ten: " tens " }) - #Uses only the provided units and does not try to use larger ones + # Uses only the provided units and does not try to use larger ones assert_equal "1000 kilometers", number_helper.number_to_human(1_000_000, units: { unit: "meter", thousand: "kilometers" }) end end diff --git a/activesupport/test/option_merger_test.rb b/activesupport/test/option_merger_test.rb index c5a6d304ee..935e2aee63 100644 --- a/activesupport/test/option_merger_test.rb +++ b/activesupport/test/option_merger_test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "abstract_unit" require "active_support/core_ext/object/with_options" diff --git a/activesupport/test/ordered_hash_test.rb b/activesupport/test/ordered_hash_test.rb index 2cefab3832..c70d3b4c37 100644 --- a/activesupport/test/ordered_hash_test.rb +++ b/activesupport/test/ordered_hash_test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "abstract_unit" require "active_support/json" require "active_support/core_ext/object/json" diff --git a/activesupport/test/ordered_options_test.rb b/activesupport/test/ordered_options_test.rb index 0417911289..2c67bb02ac 100644 --- a/activesupport/test/ordered_options_test.rb +++ b/activesupport/test/ordered_options_test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "abstract_unit" require "active_support/ordered_options" @@ -100,4 +102,17 @@ class OrderedOptionsTest < ActiveSupport::TestCase end assert_raises(KeyError) { a.non_existing_key! } end + + def test_inheritable_options_with_bang + a = ActiveSupport::InheritableOptions.new(foo: :bar) + + assert_nothing_raised { a.foo! } + assert_equal a.foo, a.foo! + + assert_raises(KeyError) do + a.foo = nil + a.foo! + end + assert_raises(KeyError) { a.non_existing_key! } + end end diff --git a/activesupport/test/reloader_test.rb b/activesupport/test/reloader_test.rb index bdd80307c7..3e4229eaf7 100644 --- a/activesupport/test/reloader_test.rb +++ b/activesupport/test/reloader_test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "abstract_unit" class ReloaderTest < ActiveSupport::TestCase diff --git a/activesupport/test/rescuable_test.rb b/activesupport/test/rescuable_test.rb index 3bdd1651e7..b1b8a25c5b 100644 --- a/activesupport/test/rescuable_test.rb +++ b/activesupport/test/rescuable_test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "abstract_unit" class WraithAttack < StandardError diff --git a/activesupport/test/safe_buffer_test.rb b/activesupport/test/safe_buffer_test.rb index 36c068b91f..05c2fb59be 100644 --- a/activesupport/test/safe_buffer_test.rb +++ b/activesupport/test/safe_buffer_test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "abstract_unit" require "active_support/core_ext/string/inflections" require "yaml" diff --git a/activesupport/test/security_utils_test.rb b/activesupport/test/security_utils_test.rb index e8f762da22..0a607594a2 100644 --- a/activesupport/test/security_utils_test.rb +++ b/activesupport/test/security_utils_test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "abstract_unit" require "active_support/security_utils" @@ -7,8 +9,14 @@ class SecurityUtilsTest < ActiveSupport::TestCase assert_not ActiveSupport::SecurityUtils.secure_compare("a", "b") end - def test_variable_size_secure_compare_should_perform_string_comparison - assert ActiveSupport::SecurityUtils.variable_size_secure_compare("a", "a") - assert_not ActiveSupport::SecurityUtils.variable_size_secure_compare("a", "b") + def test_fixed_length_secure_compare_should_perform_string_comparison + assert ActiveSupport::SecurityUtils.fixed_length_secure_compare("a", "a") + assert !ActiveSupport::SecurityUtils.fixed_length_secure_compare("a", "b") + end + + def test_fixed_length_secure_compare_raise_on_length_mismatch + assert_raises(ArgumentError, "string length mismatch.") do + ActiveSupport::SecurityUtils.fixed_length_secure_compare("a", "ab") + end end end diff --git a/activesupport/test/share_lock_test.rb b/activesupport/test/share_lock_test.rb index a5970591fa..42fd5eefc1 100644 --- a/activesupport/test/share_lock_test.rb +++ b/activesupport/test/share_lock_test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "abstract_unit" require "concurrent/atomic/count_down_latch" require "active_support/concurrency/share_lock" diff --git a/activesupport/test/string_inquirer_test.rb b/activesupport/test/string_inquirer_test.rb index 79a715349c..bf8f878a32 100644 --- a/activesupport/test/string_inquirer_test.rb +++ b/activesupport/test/string_inquirer_test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "abstract_unit" class StringInquirerTest < ActiveSupport::TestCase diff --git a/activesupport/test/subscriber_test.rb b/activesupport/test/subscriber_test.rb index 9127da35d4..6b012e43af 100644 --- a/activesupport/test/subscriber_test.rb +++ b/activesupport/test/subscriber_test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "abstract_unit" require "active_support/subscriber" diff --git a/activesupport/test/tagged_logging_test.rb b/activesupport/test/tagged_logging_test.rb index 2469e827d4..5fd6a6b316 100644 --- a/activesupport/test/tagged_logging_test.rb +++ b/activesupport/test/tagged_logging_test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "abstract_unit" require "active_support/logger" require "active_support/tagged_logging" diff --git a/activesupport/test/test_case_test.rb b/activesupport/test/test_case_test.rb index 40dfbe2542..79b75a001a 100644 --- a/activesupport/test/test_case_test.rb +++ b/activesupport/test/test_case_test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "abstract_unit" class AssertDifferenceTest < ActiveSupport::TestCase @@ -85,7 +87,8 @@ class AssertDifferenceTest < ActiveSupport::TestCase def test_expression_is_evaluated_in_the_appropriate_scope silence_warnings do - local_scope = local_scope = "foo" + local_scope = "foo" + local_scope = local_scope # to suppress unused variable warning assert_difference("local_scope; @object.num") { @object.increment } end end @@ -153,6 +156,16 @@ class AssertDifferenceTest < ActiveSupport::TestCase end end + def test_assert_changes_with_to_option_but_no_change_has_special_message + error = assert_raises Minitest::Assertion do + assert_changes "@object.num", to: 0 do + # no changes + end + end + + assert_equal "\"@object.num\" didn't change. It was already 0", error.message + end + def test_assert_changes_with_wrong_to_option assert_raises Minitest::Assertion do assert_changes "@object.num", to: 2 do @@ -176,6 +189,7 @@ class AssertDifferenceTest < ActiveSupport::TestCase end def test_assert_changes_works_with_any_object + # Silences: instance variable @new_object not initialized. retval = silence_warnings do assert_changes :@new_object, from: nil, to: 42 do @new_object = 42 @@ -198,7 +212,7 @@ class AssertDifferenceTest < ActiveSupport::TestCase def test_assert_changes_with_to_and_case_operator token = nil - assert_changes "token", to: /\w{32}/ do + assert_changes -> { token }, to: /\w{32}/ do token = SecureRandom.hex end end @@ -206,7 +220,7 @@ class AssertDifferenceTest < ActiveSupport::TestCase def test_assert_changes_with_to_and_from_and_case_operator token = SecureRandom.hex - assert_changes "token", from: /\w{32}/, to: /\w{32}/ do + assert_changes -> { token }, from: /\w{32}/, to: /\w{32}/ do token = SecureRandom.hex end end @@ -214,6 +228,7 @@ class AssertDifferenceTest < ActiveSupport::TestCase def test_assert_changes_with_message error = assert_raises Minitest::Assertion do assert_changes "@object.num", "@object.num should 1", to: 1 do + @object.decrement end end @@ -233,7 +248,7 @@ class AssertDifferenceTest < ActiveSupport::TestCase end end - assert_equal "@object.num should not change.\n\"@object.num\" did change to 1.\nExpected: 0\n Actual: 1", error.message + assert_equal "@object.num should not change.\n\"@object.num\" did change to 1", error.message end end diff --git a/activesupport/test/testing/constant_lookup_test.rb b/activesupport/test/testing/constant_lookup_test.rb index 00e69fcdb5..37b7822950 100644 --- a/activesupport/test/testing/constant_lookup_test.rb +++ b/activesupport/test/testing/constant_lookup_test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "abstract_unit" require "dependencies_test_helpers" diff --git a/activesupport/test/testing/file_fixtures_test.rb b/activesupport/test/testing/file_fixtures_test.rb index 9f28252c31..35be8f5206 100644 --- a/activesupport/test/testing/file_fixtures_test.rb +++ b/activesupport/test/testing/file_fixtures_test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "abstract_unit" require "pathname" diff --git a/activesupport/test/testing/method_call_assertions_test.rb b/activesupport/test/testing/method_call_assertions_test.rb index 7887933b15..4af000bb7e 100644 --- a/activesupport/test/testing/method_call_assertions_test.rb +++ b/activesupport/test/testing/method_call_assertions_test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "abstract_unit" require "active_support/testing/method_call_assertions" diff --git a/activesupport/test/time_travel_test.rb b/activesupport/test/time_travel_test.rb index 9d354f14f4..9c2c635f43 100644 --- a/activesupport/test/time_travel_test.rb +++ b/activesupport/test/time_travel_test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "abstract_unit" require "active_support/core_ext/date_time" require "active_support/core_ext/numeric/time" @@ -96,7 +98,7 @@ class TimeTravelTest < ActiveSupport::TestCase travel_to outer_expected_time do e = assert_raises(RuntimeError) do travel_to(inner_expected_time) do - #noop + # noop end end assert_match(/Calling `travel_to` with a block, when we have previously already made a call to `travel_to`, can lead to confusing time stubbing\./, e.message) @@ -162,4 +164,26 @@ class TimeTravelTest < ActiveSupport::TestCase assert_equal DateTime.now.to_s, DateTimeSubclass.now.to_s end end + + def test_time_helper_freeze_time + expected_time = Time.now + freeze_time + sleep(1) + + assert_equal expected_time.to_s(:db), Time.now.to_s(:db) + ensure + travel_back + end + + def test_time_helper_freeze_time_with_block + expected_time = Time.now + + freeze_time do + sleep(1) + + assert_equal expected_time.to_s(:db), Time.now.to_s(:db) + end + + assert_operator expected_time.to_s(:db), :<, Time.now.to_s(:db) + end end diff --git a/activesupport/test/time_zone_test.rb b/activesupport/test/time_zone_test.rb index de111cc40e..405c8f315b 100644 --- a/activesupport/test/time_zone_test.rb +++ b/activesupport/test/time_zone_test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "abstract_unit" require "active_support/time" require "time_zone_test_helpers" @@ -30,6 +32,12 @@ class TimeZoneTest < ActiveSupport::TestCase end end + def test_period_for_local_with_ambigiuous_time + zone = ActiveSupport::TimeZone["Moscow"] + period = zone.period_for_local(Time.utc(2015, 1, 1)) + assert_equal period, zone.period_for_local(Time.utc(2014, 10, 26, 1, 0, 0)) + end + def test_from_integer_to_map assert_instance_of ActiveSupport::TimeZone, ActiveSupport::TimeZone[-28800] # PST end @@ -101,7 +109,6 @@ class TimeZoneTest < ActiveSupport::TestCase assert_equal Date.new(2000, 1, 1), ActiveSupport::TimeZone["Eastern Time (US & Canada)"].today travel_to(Time.utc(2000, 1, 2, 5)) # midnight Jan 2 EST assert_equal Date.new(2000, 1, 2), ActiveSupport::TimeZone["Eastern Time (US & Canada)"].today - travel_back end def test_tomorrow @@ -113,7 +120,6 @@ class TimeZoneTest < ActiveSupport::TestCase assert_equal Date.new(2000, 1, 2), ActiveSupport::TimeZone["Eastern Time (US & Canada)"].tomorrow travel_to(Time.utc(2000, 1, 2, 5)) # midnight Jan 2 EST assert_equal Date.new(2000, 1, 3), ActiveSupport::TimeZone["Eastern Time (US & Canada)"].tomorrow - travel_back end def test_yesterday @@ -125,7 +131,6 @@ class TimeZoneTest < ActiveSupport::TestCase assert_equal Date.new(1999, 12, 31), ActiveSupport::TimeZone["Eastern Time (US & Canada)"].yesterday travel_to(Time.utc(2000, 1, 2, 5)) # midnight Jan 2 EST assert_equal Date.new(2000, 1, 1), ActiveSupport::TimeZone["Eastern Time (US & Canada)"].yesterday - travel_back end def test_travel_to_a_date @@ -196,6 +201,11 @@ class TimeZoneTest < ActiveSupport::TestCase assert_equal "EDT", twz.zone end + def test_local_with_ambiguous_time + zone = ActiveSupport::TimeZone["Moscow"] + assert_equal Time.utc(2014, 10, 25, 22, 0, 0), zone.local(2014, 10, 26, 1, 0, 0) + end + def test_at zone = ActiveSupport::TimeZone["Eastern Time (US & Canada)"] secs = 946684800.0 @@ -304,6 +314,11 @@ class TimeZoneTest < ActiveSupport::TestCase end end + def test_iso8601_with_ambiguous_time + zone = ActiveSupport::TimeZone["Moscow"] + assert_equal Time.utc(2014, 10, 25, 22, 0, 0), zone.parse("2014-10-26T01:00:00") + end + def test_parse zone = ActiveSupport::TimeZone["Eastern Time (US & Canada)"] twz = zone.parse("1999-12-31 19:00:00") @@ -403,6 +418,21 @@ class TimeZoneTest < ActiveSupport::TestCase end end + def test_parse_with_invalid_date + zone = ActiveSupport::TimeZone["UTC"] + + exception = assert_raises(ArgumentError) do + zone.parse("9000") + end + + assert_equal "argument out of range", exception.message + end + + def test_parse_with_ambiguous_time + zone = ActiveSupport::TimeZone["Moscow"] + assert_equal Time.utc(2014, 10, 25, 22, 0, 0), zone.parse("2014-10-26 01:00:00") + end + def test_rfc3339 zone = ActiveSupport::TimeZone["Eastern Time (US & Canada)"] twz = zone.rfc3339("1999-12-31T14:00:00-10:00") @@ -595,6 +625,11 @@ class TimeZoneTest < ActiveSupport::TestCase end end + def test_strptime_with_ambiguous_time + zone = ActiveSupport::TimeZone["Moscow"] + assert_equal Time.utc(2014, 10, 25, 22, 0, 0), zone.strptime("2014-10-26 01:00:00", "%Y-%m-%d %H:%M:%S") + end + def test_utc_offset_lazy_loaded_from_tzinfo_when_not_passed_in_to_initialize tzinfo = TZInfo::Timezone.get("America/New_York") zone = ActiveSupport::TimeZone.create(tzinfo.name, nil, tzinfo) @@ -683,6 +718,13 @@ class TimeZoneTest < ActiveSupport::TestCase end end + def test_all_uninfluenced_by_time_zone_lookups_delegated_to_tzinfo + ActiveSupport::TimeZone.clear + galapagos = ActiveSupport::TimeZone["Pacific/Galapagos"] + all_zones = ActiveSupport::TimeZone.all + assert_not_includes all_zones, galapagos + end + def test_index assert_nil ActiveSupport::TimeZone["bogus"] assert_instance_of ActiveSupport::TimeZone, ActiveSupport::TimeZone["Central Time (US & Canada)"] diff --git a/activesupport/test/time_zone_test_helpers.rb b/activesupport/test/time_zone_test_helpers.rb index e1d615d154..051703a781 100644 --- a/activesupport/test/time_zone_test_helpers.rb +++ b/activesupport/test/time_zone_test_helpers.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + module TimeZoneTestHelpers def with_tz_default(tz = nil) old_tz = Time.zone diff --git a/activesupport/test/transliterate_test.rb b/activesupport/test/transliterate_test.rb index 466b69bcef..7d19447598 100644 --- a/activesupport/test/transliterate_test.rb +++ b/activesupport/test/transliterate_test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "abstract_unit" require "active_support/inflector/transliterate" diff --git a/activesupport/test/xml_mini/jdom_engine_test.rb b/activesupport/test/xml_mini/jdom_engine_test.rb index fc35ac113b..97a533aafb 100644 --- a/activesupport/test/xml_mini/jdom_engine_test.rb +++ b/activesupport/test/xml_mini/jdom_engine_test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require_relative "xml_mini_engine_test" XMLMiniEngineTest.run_with_platform("java") do diff --git a/activesupport/test/xml_mini/libxml_engine_test.rb b/activesupport/test/xml_mini/libxml_engine_test.rb index f3394ad7f2..3eef3946a3 100644 --- a/activesupport/test/xml_mini/libxml_engine_test.rb +++ b/activesupport/test/xml_mini/libxml_engine_test.rb @@ -1,10 +1,12 @@ +# frozen_string_literal: true + require_relative "xml_mini_engine_test" XMLMiniEngineTest.run_with_gem("libxml") do class LibxmlEngineTest < XMLMiniEngineTest def setup super - LibXML::XML::Error.set_handler(&lambda { |error| }) #silence libxml, exceptions will do + LibXML::XML::Error.set_handler(&lambda { |error| }) # silence libxml, exceptions will do end private diff --git a/activesupport/test/xml_mini/libxmlsax_engine_test.rb b/activesupport/test/xml_mini/libxmlsax_engine_test.rb index f457e160d6..8e4a30a48e 100644 --- a/activesupport/test/xml_mini/libxmlsax_engine_test.rb +++ b/activesupport/test/xml_mini/libxmlsax_engine_test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require_relative "xml_mini_engine_test" XMLMiniEngineTest.run_with_gem("libxml") do diff --git a/activesupport/test/xml_mini/nokogiri_engine_test.rb b/activesupport/test/xml_mini/nokogiri_engine_test.rb index 3151e75fc0..f1584bcedf 100644 --- a/activesupport/test/xml_mini/nokogiri_engine_test.rb +++ b/activesupport/test/xml_mini/nokogiri_engine_test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require_relative "xml_mini_engine_test" XMLMiniEngineTest.run_with_gem("nokogiri") do diff --git a/activesupport/test/xml_mini/nokogirisax_engine_test.rb b/activesupport/test/xml_mini/nokogirisax_engine_test.rb index 7dafbdaf48..f38a56e83b 100644 --- a/activesupport/test/xml_mini/nokogirisax_engine_test.rb +++ b/activesupport/test/xml_mini/nokogirisax_engine_test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require_relative "xml_mini_engine_test" XMLMiniEngineTest.run_with_gem("nokogiri") do diff --git a/activesupport/test/xml_mini/rexml_engine_test.rb b/activesupport/test/xml_mini/rexml_engine_test.rb index c51f0d3c20..34bf81fa75 100644 --- a/activesupport/test/xml_mini/rexml_engine_test.rb +++ b/activesupport/test/xml_mini/rexml_engine_test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require_relative "xml_mini_engine_test" class REXMLEngineTest < XMLMiniEngineTest diff --git a/activesupport/test/xml_mini/xml_mini_engine_test.rb b/activesupport/test/xml_mini/xml_mini_engine_test.rb index 244e0b0d3a..5c4c28d9b7 100644 --- a/activesupport/test/xml_mini/xml_mini_engine_test.rb +++ b/activesupport/test/xml_mini/xml_mini_engine_test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "abstract_unit" require "active_support/xml_mini" require "active_support/core_ext/hash/conversions" diff --git a/activesupport/test/xml_mini_test.rb b/activesupport/test/xml_mini_test.rb index b8caa1d74c..18a3f2ca66 100644 --- a/activesupport/test/xml_mini_test.rb +++ b/activesupport/test/xml_mini_test.rb @@ -1,3 +1,5 @@ +# frozen_string_literal: true + require "abstract_unit" require "active_support/xml_mini" require "active_support/builder" @@ -112,7 +114,7 @@ module XmlMiniTest end test "#to_tag accepts decimal types" do - @xml.to_tag(:b, ::BigDecimal.new("1.2"), @options) + @xml.to_tag(:b, BigDecimal("1.2"), @options) assert_xml("<b type=\"decimal\">1.2</b>") end |