activesupport 6.0.0 → 6.1.3

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of activesupport might be problematic. Click here for more details.

Files changed (152) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +381 -349
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +2 -2
  5. data/lib/active_support.rb +13 -1
  6. data/lib/active_support/array_inquirer.rb +4 -2
  7. data/lib/active_support/backtrace_cleaner.rb +3 -4
  8. data/lib/active_support/benchmarkable.rb +1 -1
  9. data/lib/active_support/cache.rb +101 -59
  10. data/lib/active_support/cache/file_store.rb +11 -11
  11. data/lib/active_support/cache/mem_cache_store.rb +34 -33
  12. data/lib/active_support/cache/memory_store.rb +52 -31
  13. data/lib/active_support/cache/null_store.rb +3 -3
  14. data/lib/active_support/cache/redis_cache_store.rb +38 -33
  15. data/lib/active_support/cache/strategy/local_cache.rb +41 -26
  16. data/lib/active_support/callbacks.rb +65 -59
  17. data/lib/active_support/concern.rb +46 -2
  18. data/lib/active_support/concurrency/load_interlock_aware_monitor.rb +18 -0
  19. data/lib/active_support/concurrency/share_lock.rb +0 -1
  20. data/lib/active_support/configurable.rb +3 -3
  21. data/lib/active_support/configuration_file.rb +46 -0
  22. data/lib/active_support/core_ext.rb +1 -1
  23. data/lib/active_support/core_ext/array/conversions.rb +5 -5
  24. data/lib/active_support/core_ext/benchmark.rb +2 -2
  25. data/lib/active_support/core_ext/class/attribute.rb +34 -44
  26. data/lib/active_support/core_ext/class/subclasses.rb +17 -38
  27. data/lib/active_support/core_ext/date/conversions.rb +2 -1
  28. data/lib/active_support/core_ext/date_and_time/calculations.rb +13 -0
  29. data/lib/active_support/core_ext/date_and_time/compatibility.rb +15 -0
  30. data/lib/active_support/core_ext/date_and_time/zones.rb +0 -1
  31. data/lib/active_support/core_ext/date_time/conversions.rb +0 -1
  32. data/lib/active_support/core_ext/enumerable.rb +76 -4
  33. data/lib/active_support/core_ext/hash/conversions.rb +3 -3
  34. data/lib/active_support/core_ext/hash/deep_transform_values.rb +1 -1
  35. data/lib/active_support/core_ext/hash/except.rb +1 -1
  36. data/lib/active_support/core_ext/hash/keys.rb +1 -1
  37. data/lib/active_support/core_ext/hash/slice.rb +3 -2
  38. data/lib/active_support/core_ext/load_error.rb +1 -1
  39. data/lib/active_support/core_ext/marshal.rb +2 -0
  40. data/lib/active_support/core_ext/module/attr_internal.rb +2 -2
  41. data/lib/active_support/core_ext/module/attribute_accessors.rb +23 -29
  42. data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +8 -4
  43. data/lib/active_support/core_ext/module/concerning.rb +8 -2
  44. data/lib/active_support/core_ext/module/delegation.rb +46 -29
  45. data/lib/active_support/core_ext/module/introspection.rb +2 -25
  46. data/lib/active_support/core_ext/name_error.rb +29 -2
  47. data/lib/active_support/core_ext/numeric/conversions.rb +22 -18
  48. data/lib/active_support/core_ext/object/deep_dup.rb +1 -1
  49. data/lib/active_support/core_ext/object/json.rb +13 -2
  50. data/lib/active_support/core_ext/object/try.rb +4 -2
  51. data/lib/active_support/core_ext/range/compare_range.rb +15 -3
  52. data/lib/active_support/core_ext/range/each.rb +0 -1
  53. data/lib/active_support/core_ext/range/include_time_with_zone.rb +8 -3
  54. data/lib/active_support/core_ext/regexp.rb +8 -1
  55. data/lib/active_support/core_ext/string/access.rb +5 -24
  56. data/lib/active_support/core_ext/string/conversions.rb +1 -0
  57. data/lib/active_support/core_ext/string/inflections.rb +38 -4
  58. data/lib/active_support/core_ext/string/inquiry.rb +1 -0
  59. data/lib/active_support/core_ext/string/multibyte.rb +2 -2
  60. data/lib/active_support/core_ext/string/output_safety.rb +12 -11
  61. data/lib/active_support/core_ext/string/starts_ends_with.rb +2 -2
  62. data/lib/active_support/core_ext/symbol.rb +3 -0
  63. data/lib/active_support/core_ext/symbol/starts_ends_with.rb +14 -0
  64. data/lib/active_support/core_ext/time/calculations.rb +27 -3
  65. data/lib/active_support/core_ext/time/conversions.rb +2 -0
  66. data/lib/active_support/core_ext/uri.rb +5 -1
  67. data/lib/active_support/current_attributes.rb +7 -2
  68. data/lib/active_support/current_attributes/test_helper.rb +13 -0
  69. data/lib/active_support/dependencies.rb +42 -20
  70. data/lib/active_support/dependencies/zeitwerk_integration.rb +9 -2
  71. data/lib/active_support/deprecation.rb +6 -1
  72. data/lib/active_support/deprecation/behaviors.rb +15 -2
  73. data/lib/active_support/deprecation/disallowed.rb +56 -0
  74. data/lib/active_support/deprecation/instance_delegator.rb +0 -1
  75. data/lib/active_support/deprecation/method_wrappers.rb +13 -6
  76. data/lib/active_support/deprecation/proxy_wrappers.rb +6 -2
  77. data/lib/active_support/deprecation/reporting.rb +50 -7
  78. data/lib/active_support/descendants_tracker.rb +6 -3
  79. data/lib/active_support/duration.rb +86 -35
  80. data/lib/active_support/duration/iso8601_parser.rb +0 -1
  81. data/lib/active_support/duration/iso8601_serializer.rb +15 -10
  82. data/lib/active_support/encrypted_file.rb +20 -3
  83. data/lib/active_support/environment_inquirer.rb +20 -0
  84. data/lib/active_support/evented_file_update_checker.rb +69 -134
  85. data/lib/active_support/file_update_checker.rb +0 -1
  86. data/lib/active_support/fork_tracker.rb +62 -0
  87. data/lib/active_support/gem_version.rb +2 -2
  88. data/lib/active_support/hash_with_indifferent_access.rb +43 -24
  89. data/lib/active_support/i18n_railtie.rb +15 -16
  90. data/lib/active_support/inflector/inflections.rb +1 -3
  91. data/lib/active_support/inflector/methods.rb +36 -33
  92. data/lib/active_support/inflector/transliterate.rb +4 -4
  93. data/lib/active_support/json/decoding.rb +4 -5
  94. data/lib/active_support/json/encoding.rb +5 -1
  95. data/lib/active_support/key_generator.rb +1 -1
  96. data/lib/active_support/lazy_load_hooks.rb +0 -1
  97. data/lib/active_support/locale/en.rb +4 -2
  98. data/lib/active_support/locale/en.yml +7 -3
  99. data/lib/active_support/log_subscriber.rb +8 -1
  100. data/lib/active_support/logger.rb +2 -2
  101. data/lib/active_support/logger_silence.rb +2 -26
  102. data/lib/active_support/logger_thread_safe_level.rb +34 -12
  103. data/lib/active_support/message_encryptor.rb +5 -8
  104. data/lib/active_support/message_verifier.rb +7 -7
  105. data/lib/active_support/messages/metadata.rb +11 -2
  106. data/lib/active_support/messages/rotation_configuration.rb +2 -1
  107. data/lib/active_support/messages/rotator.rb +10 -9
  108. data/lib/active_support/multibyte/chars.rb +5 -44
  109. data/lib/active_support/multibyte/unicode.rb +9 -84
  110. data/lib/active_support/notifications.rb +32 -5
  111. data/lib/active_support/notifications/fanout.rb +23 -8
  112. data/lib/active_support/notifications/instrumenter.rb +7 -16
  113. data/lib/active_support/number_helper.rb +33 -14
  114. data/lib/active_support/number_helper/number_converter.rb +5 -6
  115. data/lib/active_support/number_helper/number_to_currency_converter.rb +2 -7
  116. data/lib/active_support/number_helper/number_to_delimited_converter.rb +0 -1
  117. data/lib/active_support/number_helper/number_to_human_converter.rb +1 -2
  118. data/lib/active_support/number_helper/number_to_human_size_converter.rb +1 -2
  119. data/lib/active_support/number_helper/number_to_phone_converter.rb +0 -1
  120. data/lib/active_support/number_helper/number_to_rounded_converter.rb +3 -4
  121. data/lib/active_support/number_helper/rounding_helper.rb +12 -28
  122. data/lib/active_support/option_merger.rb +22 -3
  123. data/lib/active_support/ordered_hash.rb +1 -1
  124. data/lib/active_support/ordered_options.rb +13 -3
  125. data/lib/active_support/parameter_filter.rb +17 -13
  126. data/lib/active_support/per_thread_registry.rb +1 -1
  127. data/lib/active_support/rails.rb +1 -4
  128. data/lib/active_support/railtie.rb +23 -1
  129. data/lib/active_support/rescuable.rb +4 -4
  130. data/lib/active_support/secure_compare_rotator.rb +51 -0
  131. data/lib/active_support/security_utils.rb +19 -12
  132. data/lib/active_support/string_inquirer.rb +4 -3
  133. data/lib/active_support/subscriber.rb +12 -7
  134. data/lib/active_support/tagged_logging.rb +29 -4
  135. data/lib/active_support/testing/assertions.rb +18 -11
  136. data/lib/active_support/testing/parallelization.rb +12 -89
  137. data/lib/active_support/testing/parallelization/server.rb +78 -0
  138. data/lib/active_support/testing/parallelization/worker.rb +100 -0
  139. data/lib/active_support/testing/stream.rb +0 -1
  140. data/lib/active_support/testing/time_helpers.rb +40 -5
  141. data/lib/active_support/time_with_zone.rb +67 -43
  142. data/lib/active_support/values/time_zone.rb +20 -10
  143. data/lib/active_support/xml_mini.rb +0 -1
  144. data/lib/active_support/xml_mini/jdom.rb +0 -1
  145. data/lib/active_support/xml_mini/rexml.rb +8 -1
  146. metadata +39 -38
  147. data/lib/active_support/core_ext/array/prepend_and_append.rb +0 -5
  148. data/lib/active_support/core_ext/hash/compact.rb +0 -5
  149. data/lib/active_support/core_ext/hash/transform_values.rb +0 -5
  150. data/lib/active_support/core_ext/module/reachable.rb +0 -6
  151. data/lib/active_support/core_ext/numeric/inquiry.rb +0 -5
  152. data/lib/active_support/core_ext/range/include_range.rb +0 -9
@@ -1,10 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "active_support/xml_mini"
4
- require "active_support/time"
5
4
  require "active_support/core_ext/object/blank"
6
5
  require "active_support/core_ext/object/to_param"
7
6
  require "active_support/core_ext/object/to_query"
7
+ require "active_support/core_ext/object/try"
8
8
  require "active_support/core_ext/array/wrap"
9
9
  require "active_support/core_ext/hash/reverse_merge"
10
10
  require "active_support/core_ext/string/inflections"
@@ -73,7 +73,7 @@ class Hash
73
73
  # configure your own builder with the <tt>:builder</tt> option. The method also accepts
74
74
  # options like <tt>:dasherize</tt> and friends, they are forwarded to the builder.
75
75
  def to_xml(options = {})
76
- require "active_support/builder" unless defined?(Builder)
76
+ require "active_support/builder" unless defined?(Builder::XmlMarkup)
77
77
 
78
78
  options = options.dup
79
79
  options[:indent] ||= 2
@@ -208,7 +208,7 @@ module ActiveSupport
208
208
  elsif become_empty_string?(value)
209
209
  ""
210
210
  elsif become_hash?(value)
211
- xml_value = Hash[value.map { |k, v| [k, deep_to_h(v)] }]
211
+ xml_value = value.transform_values { |v| deep_to_h(v) }
212
212
 
213
213
  # Turn { files: { file: #<StringIO> } } into { files: #<StringIO> } so it is compatible with
214
214
  # how multipart uploaded files from HTML appear
@@ -21,7 +21,7 @@ class Hash
21
21
  end
22
22
 
23
23
  private
24
- # support methods for deep transforming nested hashes and arrays
24
+ # Support methods for deep transforming nested hashes and arrays.
25
25
  def _deep_transform_values_in_object(object, &block)
26
26
  case object
27
27
  when Hash
@@ -11,7 +11,7 @@ class Hash
11
11
  # @person.update(params[:person].except(:admin))
12
12
  def except(*keys)
13
13
  slice(*self.keys - keys)
14
- end
14
+ end unless method_defined?(:except)
15
15
 
16
16
  # Removes the given keys from hash and returns it.
17
17
  # hash = { a: true, b: false, c: nil }
@@ -112,7 +112,7 @@ class Hash
112
112
  end
113
113
 
114
114
  private
115
- # support methods for deep transforming nested hashes and arrays
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
@@ -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 }.extract!(:a, :b) # => {:a=>1, :b=>2}
22
- # { a: 1, b: 2 }.extract!(:a, :x) # => {:a=>1}
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
@@ -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.sub(/\.rb$/, "") == path.to_s.sub(/\.rb$/, "")
7
+ location.delete_suffix(".rb") == path.to_s.delete_suffix(".rb")
8
8
  end
9
9
  end
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "active_support/core_ext/string/inflections"
4
+
3
5
  module ActiveSupport
4
6
  module MarshalWithAutoloading # :nodoc:
5
7
  def load(source, proc = nil)
@@ -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).sub(/\A@/, "")
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
- send("attr_#{type}", internal_name)
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
@@ -48,28 +48,25 @@ class Module
48
48
  # end
49
49
  #
50
50
  # Person.new.hair_colors # => [:brown, :black, :blonde, :red]
51
- def mattr_reader(*syms, instance_reader: true, instance_accessor: true, default: nil)
51
+ def mattr_reader(*syms, instance_reader: true, instance_accessor: true, default: nil, location: nil)
52
+ raise TypeError, "module attributes should be defined directly on class, not singleton" if singleton_class?
53
+ location ||= caller_locations(1, 1).first
54
+
55
+ definition = []
52
56
  syms.each do |sym|
53
57
  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
58
 
57
- def self.#{sym}
58
- @@#{sym}
59
- end
60
- EOS
59
+ definition << "def self.#{sym}; @@#{sym}; end"
61
60
 
62
61
  if instance_reader && instance_accessor
63
- class_eval(<<-EOS, __FILE__, __LINE__ + 1)
64
- def #{sym}
65
- @@#{sym}
66
- end
67
- EOS
62
+ definition << "def #{sym}; @@#{sym}; end"
68
63
  end
69
64
 
70
65
  sym_default_value = (block_given? && default.nil?) ? yield : default
71
- class_variable_set("@@#{sym}", sym_default_value) unless sym_default_value.nil?
66
+ class_variable_set("@@#{sym}", sym_default_value) unless sym_default_value.nil? && class_variable_defined?("@@#{sym}")
72
67
  end
68
+
69
+ module_eval(definition.join(";"), location.path, location.lineno)
73
70
  end
74
71
  alias :cattr_reader :mattr_reader
75
72
 
@@ -115,28 +112,24 @@ class Module
115
112
  # end
116
113
  #
117
114
  # Person.class_variable_get("@@hair_colors") # => [:brown, :black, :blonde, :red]
118
- def mattr_writer(*syms, instance_writer: true, instance_accessor: true, default: nil)
115
+ def mattr_writer(*syms, instance_writer: true, instance_accessor: true, default: nil, location: nil)
116
+ raise TypeError, "module attributes should be defined directly on class, not singleton" if singleton_class?
117
+ location ||= caller_locations(1, 1).first
118
+
119
+ definition = []
119
120
  syms.each do |sym|
120
121
  raise NameError.new("invalid attribute name: #{sym}") unless /\A[_A-Za-z]\w*\z/.match?(sym)
121
- class_eval(<<-EOS, __FILE__, __LINE__ + 1)
122
- @@#{sym} = nil unless defined? @@#{sym}
123
-
124
- def self.#{sym}=(obj)
125
- @@#{sym} = obj
126
- end
127
- EOS
122
+ definition << "def self.#{sym}=(val); @@#{sym} = val; end"
128
123
 
129
124
  if instance_writer && instance_accessor
130
- class_eval(<<-EOS, __FILE__, __LINE__ + 1)
131
- def #{sym}=(obj)
132
- @@#{sym} = obj
133
- end
134
- EOS
125
+ definition << "def #{sym}=(val); @@#{sym} = val; end"
135
126
  end
136
127
 
137
128
  sym_default_value = (block_given? && default.nil?) ? yield : default
138
- send("#{sym}=", sym_default_value) unless sym_default_value.nil?
129
+ class_variable_set("@@#{sym}", sym_default_value) unless sym_default_value.nil? && class_variable_defined?("@@#{sym}")
139
130
  end
131
+
132
+ module_eval(definition.join(";"), location.path, location.lineno)
140
133
  end
141
134
  alias :cattr_writer :mattr_writer
142
135
 
@@ -205,8 +198,9 @@ class Module
205
198
  #
206
199
  # Person.class_variable_get("@@hair_colors") # => [:brown, :black, :blonde, :red]
207
200
  def mattr_accessor(*syms, instance_reader: true, instance_writer: true, instance_accessor: true, default: nil, &blk)
208
- mattr_reader(*syms, instance_reader: instance_reader, instance_accessor: instance_accessor, default: default, &blk)
209
- mattr_writer(*syms, instance_writer: instance_writer, instance_accessor: instance_accessor, default: default)
201
+ location = caller_locations(1, 1).first
202
+ mattr_reader(*syms, instance_reader: instance_reader, instance_accessor: instance_accessor, default: default, location: location, &blk)
203
+ mattr_writer(*syms, instance_writer: instance_writer, instance_accessor: instance_accessor, default: default, location: location)
210
204
  end
211
205
  alias :cattr_accessor :mattr_accessor
212
206
  end
@@ -33,7 +33,7 @@ class Module
33
33
  # end
34
34
  #
35
35
  # Current.new.user # => NoMethodError
36
- def thread_mattr_reader(*syms, instance_reader: true, instance_accessor: true) # :nodoc:
36
+ def thread_mattr_reader(*syms, instance_reader: true, instance_accessor: true, default: nil) # :nodoc:
37
37
  syms.each do |sym|
38
38
  raise NameError.new("invalid attribute name: #{sym}") unless /^[_A-Za-z]\w*$/.match?(sym)
39
39
 
@@ -52,6 +52,8 @@ class Module
52
52
  end
53
53
  EOS
54
54
  end
55
+
56
+ Thread.current["attr_" + name + "_#{sym}"] = default unless default.nil?
55
57
  end
56
58
  end
57
59
  alias :thread_cattr_reader :thread_mattr_reader
@@ -74,7 +76,7 @@ class Module
74
76
  # end
75
77
  #
76
78
  # Current.new.user = "DHH" # => NoMethodError
77
- def thread_mattr_writer(*syms, instance_writer: true, instance_accessor: true) # :nodoc:
79
+ def thread_mattr_writer(*syms, instance_writer: true, instance_accessor: true, default: nil) # :nodoc:
78
80
  syms.each do |sym|
79
81
  raise NameError.new("invalid attribute name: #{sym}") unless /^[_A-Za-z]\w*$/.match?(sym)
80
82
 
@@ -93,6 +95,8 @@ class Module
93
95
  end
94
96
  EOS
95
97
  end
98
+
99
+ public_send("#{sym}=", default) unless default.nil?
96
100
  end
97
101
  end
98
102
  alias :thread_cattr_writer :thread_mattr_writer
@@ -136,8 +140,8 @@ class Module
136
140
  #
137
141
  # Current.new.user = "DHH" # => NoMethodError
138
142
  # 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)
143
+ def thread_mattr_accessor(*syms, instance_reader: true, instance_writer: true, instance_accessor: true, default: nil)
144
+ thread_mattr_reader(*syms, instance_reader: instance_reader, instance_accessor: instance_accessor, default: default)
141
145
  thread_mattr_writer(*syms, instance_writer: instance_writer, instance_accessor: instance_accessor)
142
146
  end
143
147
  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
- include concern(topic, &block)
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 an options hash with a :to key as the last argument (e.g. delegate :hello, to: :greeter)."
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,10 +190,22 @@ class Module
190
190
  to = to.to_s
191
191
  to = "self.#{to}" if DELEGATION_RESERVED_METHOD_NAMES.include?(to)
192
192
 
193
- method_names = methods.map do |method|
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 = /[^\]]=$/.match?(method) ? "arg" : "*args, &block"
202
+ definition = if /[^\]]=$/.match?(method)
203
+ "arg"
204
+ elsif RUBY_VERSION >= "2.7"
205
+ "..."
206
+ else
207
+ "*args, &block"
208
+ end
197
209
 
198
210
  # The following generated method calls the target exactly once, storing
199
211
  # the returned value in a dummy variable.
@@ -203,34 +215,33 @@ class Module
203
215
  # whereas conceptually, from the user point of view, the delegator should
204
216
  # be doing one call.
205
217
  if allow_nil
206
- method_def = [
207
- "def #{method_prefix}#{method}(#{definition})",
208
- "_ = #{to}",
209
- "if !_.nil? || nil.respond_to?(:#{method})",
210
- " _.#{method}(#{definition})",
211
- "end",
212
- "end"
213
- ].join ";"
218
+ method = method.to_s
219
+
220
+ method_def <<
221
+ "def #{method_name}(#{definition})" <<
222
+ " _ = #{to}" <<
223
+ " if !_.nil? || nil.respond_to?(:#{method})" <<
224
+ " _.#{method}(#{definition})" <<
225
+ " end" <<
226
+ "end"
214
227
  else
215
- exception = %(raise DelegationError, "#{self}##{method_prefix}#{method} delegated to #{to}.#{method}, but #{to} is nil: \#{self.inspect}")
228
+ method = method.to_s
229
+ method_name = method_name.to_s
216
230
 
217
- method_def = [
218
- "def #{method_prefix}#{method}(#{definition})",
219
- " _ = #{to}",
220
- " _.#{method}(#{definition})",
221
- "rescue NoMethodError => e",
222
- " if _.nil? && e.name == :#{method}",
223
- " #{exception}",
224
- " else",
225
- " raise",
226
- " end",
231
+ method_def <<
232
+ "def #{method_name}(#{definition})" <<
233
+ " _ = #{to}" <<
234
+ " _.#{method}(#{definition})" <<
235
+ "rescue NoMethodError => e" <<
236
+ " if _.nil? && e.name == :#{method}" <<
237
+ %( raise DelegationError, "#{self}##{method_name} delegated to #{to}.#{method}, but #{to} is nil: \#{self.inspect}") <<
238
+ " else" <<
239
+ " raise" <<
240
+ " end" <<
227
241
  "end"
228
- ].join ";"
229
242
  end
230
-
231
- module_eval(method_def, file, line)
232
243
  end
233
-
244
+ module_eval(method_def.join(";"), file, line)
234
245
  private(*method_names) if private
235
246
  method_names
236
247
  end
@@ -274,13 +285,14 @@ class Module
274
285
  # variables, methods, constants, etc.
275
286
  #
276
287
  # The delegated method must be public on the target, otherwise it will
277
- # raise +NoMethodError+.
288
+ # raise +DelegationError+. If you wish to instead return +nil+,
289
+ # use the <tt>:allow_nil</tt> option.
278
290
  #
279
291
  # The <tt>marshal_dump</tt> and <tt>_dump</tt> methods are exempt from
280
292
  # delegation due to possible interference when calling
281
293
  # <tt>Marshal.dump(object)</tt>, should the delegation target method
282
294
  # of <tt>object</tt> add or remove instance variables.
283
- def delegate_missing_to(target)
295
+ def delegate_missing_to(target, allow_nil: nil)
284
296
  target = target.to_s
285
297
  target = "self.#{target}" if DELEGATION_RESERVED_METHOD_NAMES.include?(target)
286
298
 
@@ -301,13 +313,18 @@ class Module
301
313
  super
302
314
  rescue NoMethodError
303
315
  if #{target}.nil?
304
- raise DelegationError, "\#{method} delegated to #{target}, but #{target} is nil"
316
+ if #{allow_nil == true}
317
+ nil
318
+ else
319
+ raise DelegationError, "\#{method} delegated to #{target}, but #{target} is nil"
320
+ end
305
321
  else
306
322
  raise
307
323
  end
308
324
  end
309
325
  end
310
326
  end
327
+ ruby2_keywords(:method_missing) if respond_to?(:ruby2_keywords, true)
311
328
  RUBY
312
329
  end
313
330
  end
@@ -1,5 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "active_support/core_ext/string/filters"
3
4
  require "active_support/inflector"
4
5
 
5
6
  class Module
@@ -10,20 +11,12 @@ class Module
10
11
  if defined?(@parent_name)
11
12
  @parent_name
12
13
  else
13
- parent_name = name =~ /::[^:]+\Z/ ? $`.freeze : nil
14
+ parent_name = name =~ /::[^:]+\z/ ? -$` : nil
14
15
  @parent_name = parent_name unless frozen?
15
16
  parent_name
16
17
  end
17
18
  end
18
19
 
19
- def parent_name
20
- ActiveSupport::Deprecation.warn(<<-MSG.squish)
21
- `Module#parent_name` has been renamed to `module_parent_name`.
22
- `parent_name` is deprecated and will be removed in Rails 6.1.
23
- MSG
24
- module_parent_name
25
- end
26
-
27
20
  # Returns the module which contains this one according to its name.
28
21
  #
29
22
  # module M
@@ -43,14 +36,6 @@ class Module
43
36
  module_parent_name ? ActiveSupport::Inflector.constantize(module_parent_name) : Object
44
37
  end
45
38
 
46
- def parent
47
- ActiveSupport::Deprecation.warn(<<-MSG.squish)
48
- `Module#parent` has been renamed to `module_parent`.
49
- `parent` is deprecated and will be removed in Rails 6.1.
50
- MSG
51
- module_parent
52
- end
53
-
54
39
  # Returns all the parents of this module according to its name, ordered from
55
40
  # nested outwards. The receiver is not contained within the result.
56
41
  #
@@ -75,12 +60,4 @@ class Module
75
60
  parents << Object unless parents.include? Object
76
61
  parents
77
62
  end
78
-
79
- def parents
80
- ActiveSupport::Deprecation.warn(<<-MSG.squish)
81
- `Module#parents` has been renamed to `module_parents`.
82
- `parents` is deprecated and will be removed in Rails 6.1.
83
- MSG
84
- module_parents
85
- end
86
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
- if /undefined local variable or method/ !~ message
19
- $1 if /((::)?([A-Z]\w*)(::[A-Z]\w*)*)$/ =~ message
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,18 @@ 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
+ if UnboundMethod.method_defined?(:bind_call)
57
+ def real_mod_name(mod)
58
+ UNBOUND_METHOD_MODULE_NAME.bind_call(mod)
59
+ end
60
+ else
61
+ def real_mod_name(mod)
62
+ UNBOUND_METHOD_MODULE_NAME.bind(mod).call
63
+ end
64
+ end
38
65
  end