activesupport 6.0.4.4 → 7.0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of activesupport might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/CHANGELOG.md +257 -532
- data/MIT-LICENSE +1 -1
- data/lib/active_support/actionable_error.rb +1 -1
- data/lib/active_support/array_inquirer.rb +2 -2
- data/lib/active_support/backtrace_cleaner.rb +5 -5
- data/lib/active_support/benchmarkable.rb +3 -3
- data/lib/active_support/cache/file_store.rb +16 -10
- data/lib/active_support/cache/mem_cache_store.rb +163 -42
- data/lib/active_support/cache/memory_store.rb +57 -29
- data/lib/active_support/cache/null_store.rb +10 -2
- data/lib/active_support/cache/redis_cache_store.rb +79 -98
- data/lib/active_support/cache/strategy/local_cache.rb +49 -57
- data/lib/active_support/cache.rb +378 -179
- data/lib/active_support/callbacks.rb +230 -122
- data/lib/active_support/code_generator.rb +65 -0
- data/lib/active_support/concern.rb +49 -5
- data/lib/active_support/concurrency/load_interlock_aware_monitor.rb +2 -4
- data/lib/active_support/concurrency/share_lock.rb +2 -2
- data/lib/active_support/configurable.rb +9 -6
- data/lib/active_support/configuration_file.rb +51 -0
- data/lib/active_support/core_ext/array/access.rb +1 -5
- data/lib/active_support/core_ext/array/conversions.rb +13 -12
- data/lib/active_support/core_ext/array/deprecated_conversions.rb +25 -0
- data/lib/active_support/core_ext/array/grouping.rb +6 -6
- data/lib/active_support/core_ext/array/inquiry.rb +2 -2
- data/lib/active_support/core_ext/array.rb +1 -0
- data/lib/active_support/core_ext/benchmark.rb +2 -2
- data/lib/active_support/core_ext/big_decimal/conversions.rb +1 -1
- data/lib/active_support/core_ext/class/attribute.rb +34 -44
- data/lib/active_support/core_ext/class/subclasses.rb +9 -22
- data/lib/active_support/core_ext/date/blank.rb +1 -1
- data/lib/active_support/core_ext/date/calculations.rb +9 -9
- data/lib/active_support/core_ext/date/conversions.rb +16 -15
- data/lib/active_support/core_ext/date/deprecated_conversions.rb +26 -0
- data/lib/active_support/core_ext/date.rb +1 -0
- data/lib/active_support/core_ext/date_and_time/calculations.rb +17 -4
- data/lib/active_support/core_ext/date_and_time/compatibility.rb +15 -0
- data/lib/active_support/core_ext/date_time/blank.rb +1 -1
- data/lib/active_support/core_ext/date_time/conversions.rb +13 -13
- data/lib/active_support/core_ext/date_time/deprecated_conversions.rb +22 -0
- data/lib/active_support/core_ext/date_time.rb +1 -0
- data/lib/active_support/core_ext/digest/uuid.rb +39 -13
- data/lib/active_support/core_ext/enumerable.rb +164 -23
- data/lib/active_support/core_ext/file/atomic.rb +3 -1
- data/lib/active_support/core_ext/hash/conversions.rb +2 -3
- data/lib/active_support/core_ext/hash/deep_transform_values.rb +1 -1
- data/lib/active_support/core_ext/hash/indifferent_access.rb +3 -3
- data/lib/active_support/core_ext/hash/keys.rb +2 -2
- data/lib/active_support/core_ext/hash/slice.rb +3 -2
- data/lib/active_support/core_ext/kernel/reporting.rb +4 -4
- data/lib/active_support/core_ext/kernel/singleton_class.rb +1 -1
- data/lib/active_support/core_ext/load_error.rb +1 -1
- data/lib/active_support/core_ext/module/attr_internal.rb +2 -2
- data/lib/active_support/core_ext/module/attribute_accessors.rb +25 -29
- data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +26 -13
- data/lib/active_support/core_ext/module/concerning.rb +8 -2
- data/lib/active_support/core_ext/module/delegation.rb +40 -36
- data/lib/active_support/core_ext/module/introspection.rb +1 -25
- data/lib/active_support/core_ext/name_error.rb +23 -2
- data/lib/active_support/core_ext/numeric/conversions.rb +80 -73
- data/lib/active_support/core_ext/numeric/deprecated_conversions.rb +60 -0
- data/lib/active_support/core_ext/numeric.rb +1 -0
- data/lib/active_support/core_ext/object/acts_like.rb +29 -5
- data/lib/active_support/core_ext/object/blank.rb +2 -2
- data/lib/active_support/core_ext/object/deep_dup.rb +1 -1
- data/lib/active_support/core_ext/object/duplicable.rb +11 -0
- data/lib/active_support/core_ext/object/json.rb +42 -26
- data/lib/active_support/core_ext/object/to_query.rb +2 -2
- data/lib/active_support/core_ext/object/try.rb +20 -20
- data/lib/active_support/core_ext/object/with_options.rb +20 -1
- data/lib/active_support/core_ext/pathname/existence.rb +21 -0
- data/lib/active_support/core_ext/pathname.rb +3 -0
- data/lib/active_support/core_ext/range/compare_range.rb +6 -25
- data/lib/active_support/core_ext/range/conversions.rb +8 -8
- data/lib/active_support/core_ext/range/deprecated_conversions.rb +26 -0
- data/lib/active_support/core_ext/range/each.rb +1 -1
- data/lib/active_support/core_ext/range/include_time_with_zone.rb +4 -20
- data/lib/active_support/core_ext/range/overlaps.rb +1 -1
- data/lib/active_support/core_ext/range.rb +1 -1
- data/lib/active_support/core_ext/regexp.rb +8 -1
- data/lib/active_support/core_ext/securerandom.rb +1 -1
- data/lib/active_support/core_ext/string/access.rb +5 -24
- data/lib/active_support/core_ext/string/conversions.rb +3 -2
- data/lib/active_support/core_ext/string/filters.rb +1 -1
- data/lib/active_support/core_ext/string/inflections.rb +39 -5
- data/lib/active_support/core_ext/string/inquiry.rb +2 -1
- data/lib/active_support/core_ext/string/multibyte.rb +2 -2
- data/lib/active_support/core_ext/string/output_safety.rb +92 -41
- data/lib/active_support/core_ext/string/starts_ends_with.rb +2 -2
- data/lib/active_support/core_ext/symbol/starts_ends_with.rb +6 -0
- data/lib/active_support/core_ext/symbol.rb +3 -0
- data/lib/active_support/core_ext/time/calculations.rb +25 -7
- data/lib/active_support/core_ext/time/conversions.rb +15 -12
- data/lib/active_support/core_ext/time/deprecated_conversions.rb +22 -0
- data/lib/active_support/core_ext/time/zones.rb +7 -22
- data/lib/active_support/core_ext/time.rb +1 -0
- data/lib/active_support/core_ext/uri.rb +3 -23
- data/lib/active_support/core_ext.rb +2 -1
- data/lib/active_support/current_attributes/test_helper.rb +13 -0
- data/lib/active_support/current_attributes.rb +39 -16
- data/lib/active_support/dependencies/interlock.rb +10 -18
- data/lib/active_support/dependencies/require_dependency.rb +28 -0
- data/lib/active_support/dependencies.rb +58 -769
- data/lib/active_support/deprecation/behaviors.rb +23 -7
- data/lib/active_support/deprecation/disallowed.rb +56 -0
- data/lib/active_support/deprecation/instance_delegator.rb +0 -1
- data/lib/active_support/deprecation/method_wrappers.rb +6 -5
- data/lib/active_support/deprecation/proxy_wrappers.rb +4 -4
- data/lib/active_support/deprecation/reporting.rb +50 -7
- data/lib/active_support/deprecation.rb +7 -2
- data/lib/active_support/descendants_tracker.rb +174 -64
- data/lib/active_support/digest.rb +5 -3
- data/lib/active_support/duration/iso8601_parser.rb +3 -3
- data/lib/active_support/duration/iso8601_serializer.rb +24 -10
- data/lib/active_support/duration.rb +134 -55
- data/lib/active_support/encrypted_configuration.rb +13 -2
- data/lib/active_support/encrypted_file.rb +32 -3
- data/lib/active_support/environment_inquirer.rb +20 -0
- data/lib/active_support/error_reporter.rb +117 -0
- data/lib/active_support/evented_file_update_checker.rb +72 -138
- data/lib/active_support/execution_context/test_helper.rb +13 -0
- data/lib/active_support/execution_context.rb +53 -0
- data/lib/active_support/execution_wrapper.rb +43 -21
- data/lib/active_support/executor/test_helper.rb +7 -0
- data/lib/active_support/fork_tracker.rb +71 -0
- data/lib/active_support/gem_version.rb +3 -3
- data/lib/active_support/hash_with_indifferent_access.rb +51 -25
- data/lib/active_support/html_safe_translation.rb +43 -0
- data/lib/active_support/i18n.rb +1 -0
- data/lib/active_support/i18n_railtie.rb +14 -19
- data/lib/active_support/inflector/inflections.rb +24 -9
- data/lib/active_support/inflector/methods.rb +29 -49
- data/lib/active_support/inflector/transliterate.rb +5 -5
- data/lib/active_support/isolated_execution_state.rb +72 -0
- data/lib/active_support/json/decoding.rb +4 -4
- data/lib/active_support/json/encoding.rb +8 -4
- data/lib/active_support/key_generator.rb +23 -6
- data/lib/active_support/lazy_load_hooks.rb +28 -4
- data/lib/active_support/locale/en.yml +8 -4
- data/lib/active_support/log_subscriber/test_helper.rb +2 -2
- data/lib/active_support/log_subscriber.rb +23 -5
- data/lib/active_support/logger.rb +1 -1
- data/lib/active_support/logger_silence.rb +2 -26
- data/lib/active_support/logger_thread_safe_level.rb +34 -21
- data/lib/active_support/message_encryptor.rb +16 -13
- data/lib/active_support/message_verifier.rb +50 -18
- data/lib/active_support/messages/metadata.rb +2 -2
- data/lib/active_support/messages/rotation_configuration.rb +2 -1
- data/lib/active_support/messages/rotator.rb +6 -5
- data/lib/active_support/multibyte/chars.rb +13 -52
- data/lib/active_support/multibyte/unicode.rb +1 -87
- data/lib/active_support/multibyte.rb +1 -1
- data/lib/active_support/notifications/fanout.rb +110 -69
- data/lib/active_support/notifications/instrumenter.rb +37 -29
- data/lib/active_support/notifications.rb +55 -28
- data/lib/active_support/number_helper/number_converter.rb +2 -4
- data/lib/active_support/number_helper/number_to_currency_converter.rb +11 -6
- data/lib/active_support/number_helper/number_to_delimited_converter.rb +1 -1
- data/lib/active_support/number_helper/number_to_human_converter.rb +1 -1
- data/lib/active_support/number_helper/number_to_human_size_converter.rb +2 -2
- data/lib/active_support/number_helper/number_to_phone_converter.rb +1 -1
- data/lib/active_support/number_helper/number_to_rounded_converter.rb +9 -5
- data/lib/active_support/number_helper/rounding_helper.rb +12 -32
- data/lib/active_support/number_helper.rb +29 -16
- data/lib/active_support/option_merger.rb +11 -18
- data/lib/active_support/ordered_hash.rb +1 -1
- data/lib/active_support/ordered_options.rb +9 -3
- data/lib/active_support/parameter_filter.rb +21 -11
- data/lib/active_support/per_thread_registry.rb +6 -1
- data/lib/active_support/rails.rb +1 -4
- data/lib/active_support/railtie.rb +77 -5
- data/lib/active_support/reloader.rb +1 -1
- data/lib/active_support/rescuable.rb +16 -16
- data/lib/active_support/ruby_features.rb +7 -0
- data/lib/active_support/secure_compare_rotator.rb +51 -0
- data/lib/active_support/security_utils.rb +19 -12
- data/lib/active_support/string_inquirer.rb +2 -2
- data/lib/active_support/subscriber.rb +19 -25
- data/lib/active_support/tagged_logging.rb +31 -6
- data/lib/active_support/test_case.rb +13 -21
- data/lib/active_support/testing/assertions.rb +50 -13
- data/lib/active_support/testing/deprecation.rb +52 -1
- data/lib/active_support/testing/isolation.rb +2 -2
- data/lib/active_support/testing/method_call_assertions.rb +5 -5
- data/lib/active_support/testing/parallelization/server.rb +82 -0
- data/lib/active_support/testing/parallelization/worker.rb +103 -0
- data/lib/active_support/testing/parallelization.rb +16 -95
- data/lib/active_support/testing/parallelize_executor.rb +76 -0
- data/lib/active_support/testing/stream.rb +3 -5
- data/lib/active_support/testing/tagged_logging.rb +1 -1
- data/lib/active_support/testing/time_helpers.rb +53 -5
- data/lib/active_support/time_with_zone.rb +126 -62
- data/lib/active_support/values/time_zone.rb +54 -23
- data/lib/active_support/version.rb +1 -1
- data/lib/active_support/xml_mini/jdom.rb +1 -1
- data/lib/active_support/xml_mini/libxml.rb +5 -5
- data/lib/active_support/xml_mini/libxmlsax.rb +1 -1
- data/lib/active_support/xml_mini/nokogiri.rb +4 -4
- data/lib/active_support/xml_mini/nokogirisax.rb +1 -1
- data/lib/active_support/xml_mini/rexml.rb +9 -2
- data/lib/active_support/xml_mini.rb +5 -4
- data/lib/active_support.rb +29 -1
- metadata +46 -45
- data/lib/active_support/core_ext/array/prepend_and_append.rb +0 -5
- data/lib/active_support/core_ext/hash/compact.rb +0 -5
- data/lib/active_support/core_ext/hash/transform_values.rb +0 -5
- data/lib/active_support/core_ext/marshal.rb +0 -24
- data/lib/active_support/core_ext/module/reachable.rb +0 -6
- data/lib/active_support/core_ext/numeric/inquiry.rb +0 -5
- data/lib/active_support/core_ext/range/include_range.rb +0 -9
- data/lib/active_support/dependencies/zeitwerk_integration.rb +0 -117
@@ -1,10 +1,9 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require "active_support/xml_mini"
|
4
|
-
require "active_support/time"
|
5
3
|
require "active_support/core_ext/object/blank"
|
6
4
|
require "active_support/core_ext/object/to_param"
|
7
5
|
require "active_support/core_ext/object/to_query"
|
6
|
+
require "active_support/core_ext/object/try"
|
8
7
|
require "active_support/core_ext/array/wrap"
|
9
8
|
require "active_support/core_ext/hash/reverse_merge"
|
10
9
|
require "active_support/core_ext/string/inflections"
|
@@ -208,7 +207,7 @@ module ActiveSupport
|
|
208
207
|
elsif become_empty_string?(value)
|
209
208
|
""
|
210
209
|
elsif become_hash?(value)
|
211
|
-
xml_value =
|
210
|
+
xml_value = value.transform_values { |v| deep_to_h(v) }
|
212
211
|
|
213
212
|
# Turn { files: { file: #<StringIO> } } into { files: #<StringIO> } so it is compatible with
|
214
213
|
# how multipart uploaded files from HTML appear
|
@@ -3,7 +3,7 @@
|
|
3
3
|
require "active_support/hash_with_indifferent_access"
|
4
4
|
|
5
5
|
class Hash
|
6
|
-
# Returns an
|
6
|
+
# Returns an ActiveSupport::HashWithIndifferentAccess out of its receiver:
|
7
7
|
#
|
8
8
|
# { a: 1 }.with_indifferent_access['a'] # => 1
|
9
9
|
def with_indifferent_access
|
@@ -13,8 +13,8 @@ class Hash
|
|
13
13
|
# Called when object is nested under an object that receives
|
14
14
|
# #with_indifferent_access. This method will be called on the current object
|
15
15
|
# by the enclosing object and is aliased to #with_indifferent_access by
|
16
|
-
# default. Subclasses of Hash may
|
17
|
-
# converting to an
|
16
|
+
# default. Subclasses of Hash may override this method to return +self+ if
|
17
|
+
# converting to an ActiveSupport::HashWithIndifferentAccess would not be
|
18
18
|
# desirable.
|
19
19
|
#
|
20
20
|
# b = { b: 1 }
|
@@ -112,11 +112,11 @@ class Hash
|
|
112
112
|
end
|
113
113
|
|
114
114
|
private
|
115
|
-
#
|
115
|
+
# Support methods for deep transforming nested hashes and arrays.
|
116
116
|
def _deep_transform_keys_in_object(object, &block)
|
117
117
|
case object
|
118
118
|
when Hash
|
119
|
-
object.each_with_object(
|
119
|
+
object.each_with_object(self.class.new) do |(key, value), result|
|
120
120
|
result[yield(key)] = _deep_transform_keys_in_object(value, &block)
|
121
121
|
end
|
122
122
|
when Array
|
@@ -18,8 +18,9 @@ class Hash
|
|
18
18
|
|
19
19
|
# Removes and returns the key/value pairs matching the given keys.
|
20
20
|
#
|
21
|
-
# { a: 1, b: 2, c: 3, d: 4 }
|
22
|
-
#
|
21
|
+
# hash = { a: 1, b: 2, c: 3, d: 4 }
|
22
|
+
# hash.extract!(:a, :b) # => {:a=>1, :b=>2}
|
23
|
+
# hash # => {:c=>3, :d=>4}
|
23
24
|
def extract!(*keys)
|
24
25
|
keys.each_with_object(self.class.new) { |key, result| result[key] = delete(key) if has_key?(key) }
|
25
26
|
end
|
@@ -11,14 +11,14 @@ module Kernel
|
|
11
11
|
# end
|
12
12
|
#
|
13
13
|
# noisy_call # warning voiced
|
14
|
-
def silence_warnings
|
15
|
-
with_warnings(nil)
|
14
|
+
def silence_warnings(&block)
|
15
|
+
with_warnings(nil, &block)
|
16
16
|
end
|
17
17
|
|
18
18
|
# Sets $VERBOSE to +true+ for the duration of the block and back to its
|
19
19
|
# original value afterwards.
|
20
|
-
def enable_warnings
|
21
|
-
with_warnings(true)
|
20
|
+
def enable_warnings(&block)
|
21
|
+
with_warnings(true, &block)
|
22
22
|
end
|
23
23
|
|
24
24
|
# Sets $VERBOSE for the duration of the block and back to its original
|
@@ -4,6 +4,6 @@ class LoadError
|
|
4
4
|
# Returns true if the given path name (except perhaps for the ".rb"
|
5
5
|
# extension) is the missing file which caused the exception to be raised.
|
6
6
|
def is_missing?(location)
|
7
|
-
location.
|
7
|
+
location.delete_suffix(".rb") == path.to_s.delete_suffix(".rb")
|
8
8
|
end
|
9
9
|
end
|
@@ -28,9 +28,9 @@ class Module
|
|
28
28
|
end
|
29
29
|
|
30
30
|
def attr_internal_define(attr_name, type)
|
31
|
-
internal_name = attr_internal_ivar_name(attr_name).
|
31
|
+
internal_name = attr_internal_ivar_name(attr_name).delete_prefix("@")
|
32
32
|
# use native attr_* methods as they are faster on some Ruby implementations
|
33
|
-
|
33
|
+
public_send("attr_#{type}", internal_name)
|
34
34
|
attr_name, internal_name = "#{attr_name}=", "#{internal_name}=" if type == :writer
|
35
35
|
alias_method attr_name, internal_name
|
36
36
|
remove_method internal_name
|
@@ -1,5 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
# == Attribute Accessors
|
4
|
+
#
|
3
5
|
# Extends the module object with class/module and instance accessors for
|
4
6
|
# class/module attributes, just like the native attr* accessors for instance
|
5
7
|
# attributes.
|
@@ -48,28 +50,25 @@ class Module
|
|
48
50
|
# end
|
49
51
|
#
|
50
52
|
# Person.new.hair_colors # => [:brown, :black, :blonde, :red]
|
51
|
-
def mattr_reader(*syms, instance_reader: true, instance_accessor: true, default: nil)
|
53
|
+
def mattr_reader(*syms, instance_reader: true, instance_accessor: true, default: nil, location: nil)
|
54
|
+
raise TypeError, "module attributes should be defined directly on class, not singleton" if singleton_class?
|
55
|
+
location ||= caller_locations(1, 1).first
|
56
|
+
|
57
|
+
definition = []
|
52
58
|
syms.each do |sym|
|
53
59
|
raise NameError.new("invalid attribute name: #{sym}") unless /\A[_A-Za-z]\w*\z/.match?(sym)
|
54
|
-
class_eval(<<-EOS, __FILE__, __LINE__ + 1)
|
55
|
-
@@#{sym} = nil unless defined? @@#{sym}
|
56
60
|
|
57
|
-
|
58
|
-
@@#{sym}
|
59
|
-
end
|
60
|
-
EOS
|
61
|
+
definition << "def self.#{sym}; @@#{sym}; end"
|
61
62
|
|
62
63
|
if instance_reader && instance_accessor
|
63
|
-
|
64
|
-
def #{sym}
|
65
|
-
@@#{sym}
|
66
|
-
end
|
67
|
-
EOS
|
64
|
+
definition << "def #{sym}; @@#{sym}; end"
|
68
65
|
end
|
69
66
|
|
70
67
|
sym_default_value = (block_given? && default.nil?) ? yield : default
|
71
|
-
class_variable_set("@@#{sym}", sym_default_value) unless sym_default_value.nil?
|
68
|
+
class_variable_set("@@#{sym}", sym_default_value) unless sym_default_value.nil? && class_variable_defined?("@@#{sym}")
|
72
69
|
end
|
70
|
+
|
71
|
+
module_eval(definition.join(";"), location.path, location.lineno)
|
73
72
|
end
|
74
73
|
alias :cattr_reader :mattr_reader
|
75
74
|
|
@@ -115,28 +114,24 @@ class Module
|
|
115
114
|
# end
|
116
115
|
#
|
117
116
|
# Person.class_variable_get("@@hair_colors") # => [:brown, :black, :blonde, :red]
|
118
|
-
def mattr_writer(*syms, instance_writer: true, instance_accessor: true, default: nil)
|
117
|
+
def mattr_writer(*syms, instance_writer: true, instance_accessor: true, default: nil, location: nil)
|
118
|
+
raise TypeError, "module attributes should be defined directly on class, not singleton" if singleton_class?
|
119
|
+
location ||= caller_locations(1, 1).first
|
120
|
+
|
121
|
+
definition = []
|
119
122
|
syms.each do |sym|
|
120
123
|
raise NameError.new("invalid attribute name: #{sym}") unless /\A[_A-Za-z]\w*\z/.match?(sym)
|
121
|
-
|
122
|
-
@@#{sym} = nil unless defined? @@#{sym}
|
123
|
-
|
124
|
-
def self.#{sym}=(obj)
|
125
|
-
@@#{sym} = obj
|
126
|
-
end
|
127
|
-
EOS
|
124
|
+
definition << "def self.#{sym}=(val); @@#{sym} = val; end"
|
128
125
|
|
129
126
|
if instance_writer && instance_accessor
|
130
|
-
|
131
|
-
def #{sym}=(obj)
|
132
|
-
@@#{sym} = obj
|
133
|
-
end
|
134
|
-
EOS
|
127
|
+
definition << "def #{sym}=(val); @@#{sym} = val; end"
|
135
128
|
end
|
136
129
|
|
137
130
|
sym_default_value = (block_given? && default.nil?) ? yield : default
|
138
|
-
|
131
|
+
class_variable_set("@@#{sym}", sym_default_value) unless sym_default_value.nil? && class_variable_defined?("@@#{sym}")
|
139
132
|
end
|
133
|
+
|
134
|
+
module_eval(definition.join(";"), location.path, location.lineno)
|
140
135
|
end
|
141
136
|
alias :cattr_writer :mattr_writer
|
142
137
|
|
@@ -205,8 +200,9 @@ class Module
|
|
205
200
|
#
|
206
201
|
# Person.class_variable_get("@@hair_colors") # => [:brown, :black, :blonde, :red]
|
207
202
|
def mattr_accessor(*syms, instance_reader: true, instance_writer: true, instance_accessor: true, default: nil, &blk)
|
208
|
-
|
209
|
-
|
203
|
+
location = caller_locations(1, 1).first
|
204
|
+
mattr_reader(*syms, instance_reader: instance_reader, instance_accessor: instance_accessor, default: default, location: location, &blk)
|
205
|
+
mattr_writer(*syms, instance_writer: instance_writer, instance_accessor: instance_accessor, default: default, location: location)
|
210
206
|
end
|
211
207
|
alias :cattr_accessor :mattr_accessor
|
212
208
|
end
|
@@ -1,11 +1,16 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
# == Attribute Accessors per Thread
|
4
|
+
#
|
3
5
|
# Extends the module object with class/module and instance accessors for
|
4
6
|
# class/module attributes, just like the native attr* accessors for instance
|
5
7
|
# attributes, but does so on a per-thread basis.
|
6
8
|
#
|
7
9
|
# So the values are scoped within the Thread.current space under the class name
|
8
10
|
# of the module.
|
11
|
+
#
|
12
|
+
# Note that it can also be scoped per-fiber if +Rails.application.config.active_support.isolation_level+
|
13
|
+
# is set to +:fiber+.
|
9
14
|
class Module
|
10
15
|
# Defines a per-thread class attribute and creates class and instance reader methods.
|
11
16
|
# The underlying per-thread class variable is set to +nil+, if it is not previously defined.
|
@@ -14,9 +19,9 @@ class Module
|
|
14
19
|
# thread_mattr_reader :user
|
15
20
|
# end
|
16
21
|
#
|
17
|
-
# Current.user
|
18
|
-
# Thread.current[:attr_Current_user] = "DHH"
|
22
|
+
# Current.user = "DHH"
|
19
23
|
# Current.user # => "DHH"
|
24
|
+
# Thread.new { Current.user }.value # => nil
|
20
25
|
#
|
21
26
|
# The attribute name must be a valid method name in Ruby.
|
22
27
|
#
|
@@ -33,7 +38,7 @@ class Module
|
|
33
38
|
# end
|
34
39
|
#
|
35
40
|
# Current.new.user # => NoMethodError
|
36
|
-
def thread_mattr_reader(*syms, instance_reader: true, instance_accessor: true) # :nodoc:
|
41
|
+
def thread_mattr_reader(*syms, instance_reader: true, instance_accessor: true, default: nil) # :nodoc:
|
37
42
|
syms.each do |sym|
|
38
43
|
raise NameError.new("invalid attribute name: #{sym}") unless /^[_A-Za-z]\w*$/.match?(sym)
|
39
44
|
|
@@ -41,7 +46,8 @@ class Module
|
|
41
46
|
# to work with inheritance via polymorphism.
|
42
47
|
class_eval(<<-EOS, __FILE__, __LINE__ + 1)
|
43
48
|
def self.#{sym}
|
44
|
-
|
49
|
+
@__thread_mattr_#{sym} ||= "attr_\#{name}_#{sym}"
|
50
|
+
::ActiveSupport::IsolatedExecutionState[@__thread_mattr_#{sym}]
|
45
51
|
end
|
46
52
|
EOS
|
47
53
|
|
@@ -52,6 +58,8 @@ class Module
|
|
52
58
|
end
|
53
59
|
EOS
|
54
60
|
end
|
61
|
+
|
62
|
+
::ActiveSupport::IsolatedExecutionState["attr_#{name}_#{sym}"] = default unless default.nil?
|
55
63
|
end
|
56
64
|
end
|
57
65
|
alias :thread_cattr_reader :thread_mattr_reader
|
@@ -74,7 +82,7 @@ class Module
|
|
74
82
|
# end
|
75
83
|
#
|
76
84
|
# Current.new.user = "DHH" # => NoMethodError
|
77
|
-
def thread_mattr_writer(*syms, instance_writer: true, instance_accessor: true) # :nodoc:
|
85
|
+
def thread_mattr_writer(*syms, instance_writer: true, instance_accessor: true, default: nil) # :nodoc:
|
78
86
|
syms.each do |sym|
|
79
87
|
raise NameError.new("invalid attribute name: #{sym}") unless /^[_A-Za-z]\w*$/.match?(sym)
|
80
88
|
|
@@ -82,7 +90,8 @@ class Module
|
|
82
90
|
# to work with inheritance via polymorphism.
|
83
91
|
class_eval(<<-EOS, __FILE__, __LINE__ + 1)
|
84
92
|
def self.#{sym}=(obj)
|
85
|
-
|
93
|
+
@__thread_mattr_#{sym} ||= "attr_\#{name}_#{sym}"
|
94
|
+
::ActiveSupport::IsolatedExecutionState[@__thread_mattr_#{sym}] = obj
|
86
95
|
end
|
87
96
|
EOS
|
88
97
|
|
@@ -93,6 +102,8 @@ class Module
|
|
93
102
|
end
|
94
103
|
EOS
|
95
104
|
end
|
105
|
+
|
106
|
+
public_send("#{sym}=", default) unless default.nil?
|
96
107
|
end
|
97
108
|
end
|
98
109
|
alias :thread_cattr_writer :thread_mattr_writer
|
@@ -107,16 +118,18 @@ class Module
|
|
107
118
|
# Account.user # => "DHH"
|
108
119
|
# Account.new.user # => "DHH"
|
109
120
|
#
|
121
|
+
# Unlike +mattr_accessor+, values are *not* shared with subclasses or parent classes.
|
110
122
|
# If a subclass changes the value, the parent class' value is not changed.
|
111
|
-
#
|
112
|
-
# is not changed.
|
123
|
+
# If the parent class changes the value, the value of subclasses is not changed.
|
113
124
|
#
|
114
125
|
# class Customer < Account
|
115
126
|
# end
|
116
127
|
#
|
117
|
-
#
|
118
|
-
# Customer.user
|
119
|
-
#
|
128
|
+
# Account.user # => "DHH"
|
129
|
+
# Customer.user # => nil
|
130
|
+
# Customer.user = "Rafael"
|
131
|
+
# Customer.user # => "Rafael"
|
132
|
+
# Account.user # => "DHH"
|
120
133
|
#
|
121
134
|
# To omit the instance writer method, pass <tt>instance_writer: false</tt>.
|
122
135
|
# To omit the instance reader method, pass <tt>instance_reader: false</tt>.
|
@@ -136,8 +149,8 @@ class Module
|
|
136
149
|
#
|
137
150
|
# Current.new.user = "DHH" # => NoMethodError
|
138
151
|
# Current.new.user # => NoMethodError
|
139
|
-
def thread_mattr_accessor(*syms, instance_reader: true, instance_writer: true, instance_accessor: true)
|
140
|
-
thread_mattr_reader(*syms, instance_reader: instance_reader, instance_accessor: instance_accessor)
|
152
|
+
def thread_mattr_accessor(*syms, instance_reader: true, instance_writer: true, instance_accessor: true, default: nil)
|
153
|
+
thread_mattr_reader(*syms, instance_reader: instance_reader, instance_accessor: instance_accessor, default: default)
|
141
154
|
thread_mattr_writer(*syms, instance_writer: instance_writer, instance_accessor: instance_accessor)
|
142
155
|
end
|
143
156
|
alias :thread_cattr_accessor :thread_mattr_accessor
|
@@ -104,10 +104,16 @@ class Module
|
|
104
104
|
# * grok the behavior of our class in one glance,
|
105
105
|
# * clean up monolithic junk-drawer classes by separating their concerns, and
|
106
106
|
# * stop leaning on protected/private for crude "this is internal stuff" modularity.
|
107
|
+
#
|
108
|
+
# === Prepending concerning
|
109
|
+
#
|
110
|
+
# <tt>concerning</tt> supports a <tt>prepend: true</tt> argument which will <tt>prepend</tt> the
|
111
|
+
# concern instead of using <tt>include</tt> for it.
|
107
112
|
module Concerning
|
108
113
|
# Define a new concern and mix it in.
|
109
|
-
def concerning(topic, &block)
|
110
|
-
|
114
|
+
def concerning(topic, prepend: false, &block)
|
115
|
+
method = prepend ? :prepend : :include
|
116
|
+
__send__(method, concern(topic, &block))
|
111
117
|
end
|
112
118
|
|
113
119
|
# A low-cruft shortcut to define a concern.
|
@@ -170,7 +170,7 @@ class Module
|
|
170
170
|
# The target method must be public, otherwise it will raise +NoMethodError+.
|
171
171
|
def delegate(*methods, to: nil, prefix: nil, allow_nil: nil, private: nil)
|
172
172
|
unless to
|
173
|
-
raise ArgumentError, "Delegation needs a target. Supply
|
173
|
+
raise ArgumentError, "Delegation needs a target. Supply a keyword argument 'to' (e.g. delegate :hello, to: :greeter)."
|
174
174
|
end
|
175
175
|
|
176
176
|
if prefix == true && /^[^a-z_]/.match?(to)
|
@@ -190,16 +190,16 @@ class Module
|
|
190
190
|
to = to.to_s
|
191
191
|
to = "self.#{to}" if DELEGATION_RESERVED_METHOD_NAMES.include?(to)
|
192
192
|
|
193
|
-
|
193
|
+
method_def = []
|
194
|
+
method_names = []
|
195
|
+
|
196
|
+
methods.map do |method|
|
197
|
+
method_name = prefix ? "#{method_prefix}#{method}" : method
|
198
|
+
method_names << method_name.to_sym
|
199
|
+
|
194
200
|
# Attribute writer methods only accept one argument. Makes sure []=
|
195
201
|
# methods still accept two arguments.
|
196
|
-
definition =
|
197
|
-
"arg"
|
198
|
-
elsif RUBY_VERSION >= "2.7"
|
199
|
-
"..."
|
200
|
-
else
|
201
|
-
"*args, &block"
|
202
|
-
end
|
202
|
+
definition = /[^\]]=\z/.match?(method) ? "arg" : "..."
|
203
203
|
|
204
204
|
# The following generated method calls the target exactly once, storing
|
205
205
|
# the returned value in a dummy variable.
|
@@ -209,34 +209,33 @@ class Module
|
|
209
209
|
# whereas conceptually, from the user point of view, the delegator should
|
210
210
|
# be doing one call.
|
211
211
|
if allow_nil
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
"
|
216
|
-
" _
|
217
|
-
"
|
218
|
-
|
219
|
-
|
212
|
+
method = method.to_s
|
213
|
+
|
214
|
+
method_def <<
|
215
|
+
"def #{method_name}(#{definition})" <<
|
216
|
+
" _ = #{to}" <<
|
217
|
+
" if !_.nil? || nil.respond_to?(:#{method})" <<
|
218
|
+
" _.#{method}(#{definition})" <<
|
219
|
+
" end" <<
|
220
|
+
"end"
|
220
221
|
else
|
221
|
-
|
222
|
+
method = method.to_s
|
223
|
+
method_name = method_name.to_s
|
222
224
|
|
223
|
-
method_def
|
224
|
-
"def #{
|
225
|
-
"
|
226
|
-
" _.#{method}(#{definition})"
|
227
|
-
"rescue NoMethodError => e"
|
228
|
-
" if _.nil? && e.name == :#{method}"
|
229
|
-
"
|
230
|
-
" else"
|
231
|
-
" raise"
|
232
|
-
" end"
|
225
|
+
method_def <<
|
226
|
+
"def #{method_name}(#{definition})" <<
|
227
|
+
" _ = #{to}" <<
|
228
|
+
" _.#{method}(#{definition})" <<
|
229
|
+
"rescue NoMethodError => e" <<
|
230
|
+
" if _.nil? && e.name == :#{method}" <<
|
231
|
+
%( raise DelegationError, "#{self}##{method_name} delegated to #{to}.#{method}, but #{to} is nil: \#{self.inspect}") <<
|
232
|
+
" else" <<
|
233
|
+
" raise" <<
|
234
|
+
" end" <<
|
233
235
|
"end"
|
234
|
-
].join ";"
|
235
236
|
end
|
236
|
-
|
237
|
-
module_eval(method_def, file, line)
|
238
237
|
end
|
239
|
-
|
238
|
+
module_eval(method_def.join(";"), file, line)
|
240
239
|
private(*method_names) if private
|
241
240
|
method_names
|
242
241
|
end
|
@@ -280,13 +279,14 @@ class Module
|
|
280
279
|
# variables, methods, constants, etc.
|
281
280
|
#
|
282
281
|
# The delegated method must be public on the target, otherwise it will
|
283
|
-
# raise +
|
282
|
+
# raise +DelegationError+. If you wish to instead return +nil+,
|
283
|
+
# use the <tt>:allow_nil</tt> option.
|
284
284
|
#
|
285
285
|
# The <tt>marshal_dump</tt> and <tt>_dump</tt> methods are exempt from
|
286
286
|
# delegation due to possible interference when calling
|
287
287
|
# <tt>Marshal.dump(object)</tt>, should the delegation target method
|
288
288
|
# of <tt>object</tt> add or remove instance variables.
|
289
|
-
def delegate_missing_to(target)
|
289
|
+
def delegate_missing_to(target, allow_nil: nil)
|
290
290
|
target = target.to_s
|
291
291
|
target = "self.#{target}" if DELEGATION_RESERVED_METHOD_NAMES.include?(target)
|
292
292
|
|
@@ -307,14 +307,18 @@ class Module
|
|
307
307
|
super
|
308
308
|
rescue NoMethodError
|
309
309
|
if #{target}.nil?
|
310
|
-
|
310
|
+
if #{allow_nil == true}
|
311
|
+
nil
|
312
|
+
else
|
313
|
+
raise DelegationError, "\#{method} delegated to #{target}, but #{target} is nil"
|
314
|
+
end
|
311
315
|
else
|
312
316
|
raise
|
313
317
|
end
|
314
318
|
end
|
315
319
|
end
|
316
320
|
end
|
317
|
-
ruby2_keywords(:method_missing)
|
321
|
+
ruby2_keywords(:method_missing)
|
318
322
|
RUBY
|
319
323
|
end
|
320
324
|
end
|
@@ -11,20 +11,12 @@ class Module
|
|
11
11
|
if defined?(@parent_name)
|
12
12
|
@parent_name
|
13
13
|
else
|
14
|
-
parent_name = name =~ /::[^:]+\
|
14
|
+
parent_name = name =~ /::[^:]+\z/ ? -$` : nil
|
15
15
|
@parent_name = parent_name unless frozen?
|
16
16
|
parent_name
|
17
17
|
end
|
18
18
|
end
|
19
19
|
|
20
|
-
def parent_name
|
21
|
-
ActiveSupport::Deprecation.warn(<<-MSG.squish)
|
22
|
-
`Module#parent_name` has been renamed to `module_parent_name`.
|
23
|
-
`parent_name` is deprecated and will be removed in Rails 6.1.
|
24
|
-
MSG
|
25
|
-
module_parent_name
|
26
|
-
end
|
27
|
-
|
28
20
|
# Returns the module which contains this one according to its name.
|
29
21
|
#
|
30
22
|
# module M
|
@@ -44,14 +36,6 @@ class Module
|
|
44
36
|
module_parent_name ? ActiveSupport::Inflector.constantize(module_parent_name) : Object
|
45
37
|
end
|
46
38
|
|
47
|
-
def parent
|
48
|
-
ActiveSupport::Deprecation.warn(<<-MSG.squish)
|
49
|
-
`Module#parent` has been renamed to `module_parent`.
|
50
|
-
`parent` is deprecated and will be removed in Rails 6.1.
|
51
|
-
MSG
|
52
|
-
module_parent
|
53
|
-
end
|
54
|
-
|
55
39
|
# Returns all the parents of this module according to its name, ordered from
|
56
40
|
# nested outwards. The receiver is not contained within the result.
|
57
41
|
#
|
@@ -76,12 +60,4 @@ class Module
|
|
76
60
|
parents << Object unless parents.include? Object
|
77
61
|
parents
|
78
62
|
end
|
79
|
-
|
80
|
-
def parents
|
81
|
-
ActiveSupport::Deprecation.warn(<<-MSG.squish)
|
82
|
-
`Module#parents` has been renamed to `module_parents`.
|
83
|
-
`parents` is deprecated and will be removed in Rails 6.1.
|
84
|
-
MSG
|
85
|
-
module_parents
|
86
|
-
end
|
87
63
|
end
|
@@ -14,9 +14,22 @@ class NameError
|
|
14
14
|
# It extends NameError#message with spell corrections which are SLOW.
|
15
15
|
# We should use original_message message instead.
|
16
16
|
message = respond_to?(:original_message) ? original_message : self.message
|
17
|
+
return unless message.start_with?("uninitialized constant ")
|
17
18
|
|
18
|
-
|
19
|
-
|
19
|
+
receiver = begin
|
20
|
+
self.receiver
|
21
|
+
rescue ArgumentError
|
22
|
+
nil
|
23
|
+
end
|
24
|
+
|
25
|
+
if receiver == Object
|
26
|
+
name.to_s
|
27
|
+
elsif receiver
|
28
|
+
"#{real_mod_name(receiver)}::#{self.name}"
|
29
|
+
else
|
30
|
+
if match = message.match(/((::)?([A-Z]\w*)(::[A-Z]\w*)*)$/)
|
31
|
+
match[1]
|
32
|
+
end
|
20
33
|
end
|
21
34
|
end
|
22
35
|
|
@@ -35,4 +48,12 @@ class NameError
|
|
35
48
|
missing_name == name.to_s
|
36
49
|
end
|
37
50
|
end
|
51
|
+
|
52
|
+
private
|
53
|
+
UNBOUND_METHOD_MODULE_NAME = Module.instance_method(:name)
|
54
|
+
private_constant :UNBOUND_METHOD_MODULE_NAME
|
55
|
+
|
56
|
+
def real_mod_name(mod)
|
57
|
+
UNBOUND_METHOD_MODULE_NAME.bind_call(mod)
|
58
|
+
end
|
38
59
|
end
|