activesupport 5.2.0 → 6.0.3.2

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.

Files changed (160) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +479 -330
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +4 -3
  5. data/lib/active_support.rb +2 -1
  6. data/lib/active_support/actionable_error.rb +48 -0
  7. data/lib/active_support/backtrace_cleaner.rb +27 -1
  8. data/lib/active_support/cache.rb +104 -84
  9. data/lib/active_support/cache/file_store.rb +29 -30
  10. data/lib/active_support/cache/mem_cache_store.rb +14 -19
  11. data/lib/active_support/cache/memory_store.rb +15 -9
  12. data/lib/active_support/cache/null_store.rb +8 -3
  13. data/lib/active_support/cache/redis_cache_store.rb +73 -34
  14. data/lib/active_support/cache/strategy/local_cache.rb +23 -23
  15. data/lib/active_support/callbacks.rb +16 -8
  16. data/lib/active_support/concern.rb +31 -4
  17. data/lib/active_support/concurrency/load_interlock_aware_monitor.rb +18 -0
  18. data/lib/active_support/concurrency/share_lock.rb +0 -1
  19. data/lib/active_support/configurable.rb +7 -11
  20. data/lib/active_support/core_ext/array.rb +1 -1
  21. data/lib/active_support/core_ext/array/access.rb +18 -6
  22. data/lib/active_support/core_ext/array/conversions.rb +5 -5
  23. data/lib/active_support/core_ext/array/extract.rb +21 -0
  24. data/lib/active_support/core_ext/array/prepend_and_append.rb +2 -6
  25. data/lib/active_support/core_ext/class/attribute.rb +11 -16
  26. data/lib/active_support/core_ext/class/subclasses.rb +1 -1
  27. data/lib/active_support/core_ext/date/calculations.rb +6 -5
  28. data/lib/active_support/core_ext/date_and_time/calculations.rb +24 -47
  29. data/lib/active_support/core_ext/date_and_time/zones.rb +0 -1
  30. data/lib/active_support/core_ext/date_time/calculations.rb +1 -1
  31. data/lib/active_support/core_ext/date_time/conversions.rb +0 -1
  32. data/lib/active_support/core_ext/digest.rb +3 -0
  33. data/lib/active_support/core_ext/enumerable.rb +97 -68
  34. data/lib/active_support/core_ext/file/atomic.rb +1 -1
  35. data/lib/active_support/core_ext/hash.rb +1 -2
  36. data/lib/active_support/core_ext/hash/compact.rb +2 -26
  37. data/lib/active_support/core_ext/hash/conversions.rb +1 -1
  38. data/lib/active_support/core_ext/hash/deep_transform_values.rb +46 -0
  39. data/lib/active_support/core_ext/hash/except.rb +1 -1
  40. data/lib/active_support/core_ext/hash/keys.rb +0 -29
  41. data/lib/active_support/core_ext/hash/slice.rb +3 -25
  42. data/lib/active_support/core_ext/hash/transform_values.rb +2 -29
  43. data/lib/active_support/core_ext/integer/multiple.rb +1 -1
  44. data/lib/active_support/core_ext/kernel.rb +0 -1
  45. data/lib/active_support/core_ext/load_error.rb +1 -1
  46. data/lib/active_support/core_ext/module.rb +0 -1
  47. data/lib/active_support/core_ext/module/attribute_accessors.rb +7 -10
  48. data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +13 -19
  49. data/lib/active_support/core_ext/module/delegation.rb +41 -8
  50. data/lib/active_support/core_ext/module/introspection.rb +38 -13
  51. data/lib/active_support/core_ext/module/reachable.rb +1 -6
  52. data/lib/active_support/core_ext/module/redefine_method.rb +8 -17
  53. data/lib/active_support/core_ext/numeric.rb +0 -1
  54. data/lib/active_support/core_ext/numeric/conversions.rb +124 -128
  55. data/lib/active_support/core_ext/numeric/inquiry.rb +2 -25
  56. data/lib/active_support/core_ext/object/blank.rb +1 -2
  57. data/lib/active_support/core_ext/object/duplicable.rb +7 -114
  58. data/lib/active_support/core_ext/object/json.rb +1 -0
  59. data/lib/active_support/core_ext/object/to_query.rb +5 -2
  60. data/lib/active_support/core_ext/object/try.rb +17 -7
  61. data/lib/active_support/core_ext/object/with_options.rb +1 -1
  62. data/lib/active_support/core_ext/range.rb +1 -1
  63. data/lib/active_support/core_ext/range/compare_range.rb +76 -0
  64. data/lib/active_support/core_ext/range/conversions.rb +31 -29
  65. data/lib/active_support/core_ext/range/each.rb +0 -1
  66. data/lib/active_support/core_ext/range/include_range.rb +6 -22
  67. data/lib/active_support/core_ext/range/include_time_with_zone.rb +2 -2
  68. data/lib/active_support/core_ext/regexp.rb +0 -4
  69. data/lib/active_support/core_ext/securerandom.rb +23 -3
  70. data/lib/active_support/core_ext/string/access.rb +8 -0
  71. data/lib/active_support/core_ext/string/filters.rb +42 -1
  72. data/lib/active_support/core_ext/string/inflections.rb +7 -2
  73. data/lib/active_support/core_ext/string/multibyte.rb +4 -3
  74. data/lib/active_support/core_ext/string/output_safety.rb +63 -6
  75. data/lib/active_support/core_ext/string/strip.rb +3 -1
  76. data/lib/active_support/core_ext/time/calculations.rb +31 -2
  77. data/lib/active_support/core_ext/uri.rb +2 -4
  78. data/lib/active_support/current_attributes.rb +8 -0
  79. data/lib/active_support/dependencies.rb +77 -18
  80. data/lib/active_support/dependencies/zeitwerk_integration.rb +117 -0
  81. data/lib/active_support/deprecation.rb +1 -1
  82. data/lib/active_support/deprecation/behaviors.rb +5 -1
  83. data/lib/active_support/deprecation/method_wrappers.rb +20 -13
  84. data/lib/active_support/deprecation/proxy_wrappers.rb +28 -5
  85. data/lib/active_support/deprecation/reporting.rb +1 -1
  86. data/lib/active_support/descendants_tracker.rb +55 -9
  87. data/lib/active_support/duration.rb +19 -16
  88. data/lib/active_support/duration/iso8601_parser.rb +2 -4
  89. data/lib/active_support/duration/iso8601_serializer.rb +3 -5
  90. data/lib/active_support/encrypted_configuration.rb +1 -5
  91. data/lib/active_support/encrypted_file.rb +4 -3
  92. data/lib/active_support/evented_file_update_checker.rb +39 -10
  93. data/lib/active_support/execution_wrapper.rb +1 -0
  94. data/lib/active_support/file_update_checker.rb +0 -1
  95. data/lib/active_support/gem_version.rb +4 -4
  96. data/lib/active_support/hash_with_indifferent_access.rb +36 -18
  97. data/lib/active_support/i18n.rb +1 -0
  98. data/lib/active_support/i18n_railtie.rb +18 -2
  99. data/lib/active_support/inflector/inflections.rb +1 -5
  100. data/lib/active_support/inflector/methods.rb +18 -29
  101. data/lib/active_support/inflector/transliterate.rb +47 -18
  102. data/lib/active_support/json/decoding.rb +23 -24
  103. data/lib/active_support/json/encoding.rb +6 -2
  104. data/lib/active_support/key_generator.rb +0 -32
  105. data/lib/active_support/lazy_load_hooks.rb +5 -2
  106. data/lib/active_support/locale/en.rb +33 -0
  107. data/lib/active_support/log_subscriber.rb +31 -9
  108. data/lib/active_support/logger.rb +1 -16
  109. data/lib/active_support/logger_silence.rb +28 -12
  110. data/lib/active_support/logger_thread_safe_level.rb +28 -5
  111. data/lib/active_support/message_encryptor.rb +4 -6
  112. data/lib/active_support/message_verifier.rb +5 -5
  113. data/lib/active_support/messages/metadata.rb +3 -2
  114. data/lib/active_support/messages/rotator.rb +4 -4
  115. data/lib/active_support/multibyte/chars.rb +29 -49
  116. data/lib/active_support/multibyte/unicode.rb +44 -282
  117. data/lib/active_support/notifications.rb +41 -4
  118. data/lib/active_support/notifications/fanout.rb +100 -15
  119. data/lib/active_support/notifications/instrumenter.rb +80 -9
  120. data/lib/active_support/number_helper.rb +11 -0
  121. data/lib/active_support/number_helper/number_converter.rb +4 -5
  122. data/lib/active_support/number_helper/number_to_currency_converter.rb +9 -10
  123. data/lib/active_support/number_helper/number_to_delimited_converter.rb +3 -2
  124. data/lib/active_support/number_helper/number_to_human_converter.rb +3 -2
  125. data/lib/active_support/number_helper/number_to_human_size_converter.rb +3 -2
  126. data/lib/active_support/number_helper/number_to_percentage_converter.rb +3 -1
  127. data/lib/active_support/number_helper/number_to_phone_converter.rb +2 -1
  128. data/lib/active_support/number_helper/number_to_rounded_converter.rb +5 -4
  129. data/lib/active_support/option_merger.rb +21 -3
  130. data/lib/active_support/ordered_hash.rb +1 -1
  131. data/lib/active_support/ordered_options.rb +5 -1
  132. data/lib/active_support/parameter_filter.rb +128 -0
  133. data/lib/active_support/rails.rb +0 -6
  134. data/lib/active_support/reloader.rb +4 -5
  135. data/lib/active_support/security_utils.rb +1 -1
  136. data/lib/active_support/string_inquirer.rb +0 -1
  137. data/lib/active_support/subscriber.rb +65 -22
  138. data/lib/active_support/tagged_logging.rb +13 -4
  139. data/lib/active_support/test_case.rb +92 -1
  140. data/lib/active_support/testing/assertions.rb +15 -1
  141. data/lib/active_support/testing/deprecation.rb +0 -1
  142. data/lib/active_support/testing/file_fixtures.rb +2 -0
  143. data/lib/active_support/testing/isolation.rb +2 -2
  144. data/lib/active_support/testing/method_call_assertions.rb +28 -1
  145. data/lib/active_support/testing/parallelization.rb +134 -0
  146. data/lib/active_support/testing/setup_and_teardown.rb +5 -9
  147. data/lib/active_support/testing/stream.rb +1 -2
  148. data/lib/active_support/testing/time_helpers.rb +7 -9
  149. data/lib/active_support/time_with_zone.rb +15 -5
  150. data/lib/active_support/values/time_zone.rb +14 -8
  151. data/lib/active_support/xml_mini.rb +2 -10
  152. data/lib/active_support/xml_mini/jdom.rb +2 -3
  153. data/lib/active_support/xml_mini/libxml.rb +2 -2
  154. data/lib/active_support/xml_mini/libxmlsax.rb +4 -4
  155. data/lib/active_support/xml_mini/nokogiri.rb +2 -2
  156. data/lib/active_support/xml_mini/nokogirisax.rb +3 -3
  157. data/lib/active_support/xml_mini/rexml.rb +2 -2
  158. metadata +42 -13
  159. data/lib/active_support/core_ext/kernel/agnostics.rb +0 -13
  160. data/lib/active_support/values/unicode_tables.dat +0 -0
@@ -11,12 +11,13 @@ class String
11
11
  # encapsulates the original string. A Unicode safe version of all the String methods are defined on this proxy
12
12
  # class. If the proxy class doesn't respond to a certain method, it's forwarded to the encapsulated string.
13
13
  #
14
- # >> "lj".upcase
15
- # => "lj"
16
14
  # >> "lj".mb_chars.upcase.to_s
17
15
  # => "LJ"
18
16
  #
19
- # NOTE: An above example is useful for pre Ruby 2.4. Ruby 2.4 supports Unicode case mappings.
17
+ # NOTE: Ruby 2.4 and later support native Unicode case mappings:
18
+ #
19
+ # >> "lj".upcase
20
+ # => "LJ"
20
21
  #
21
22
  # == Method chaining
22
23
  #
@@ -134,10 +134,13 @@ end
134
134
  module ActiveSupport #:nodoc:
135
135
  class SafeBuffer < String
136
136
  UNSAFE_STRING_METHODS = %w(
137
- capitalize chomp chop delete downcase gsub lstrip next reverse rstrip
138
- slice squeeze strip sub succ swapcase tr tr_s upcase
137
+ capitalize chomp chop delete delete_prefix delete_suffix
138
+ downcase lstrip next reverse rstrip slice squeeze strip
139
+ succ swapcase tr tr_s unicode_normalize upcase
139
140
  )
140
141
 
142
+ UNSAFE_STRING_METHODS_WITH_BACKREF = %w(gsub sub)
143
+
141
144
  alias_method :original_concat, :concat
142
145
  private :original_concat
143
146
 
@@ -149,9 +152,7 @@ module ActiveSupport #:nodoc:
149
152
  end
150
153
 
151
154
  def [](*args)
152
- if args.size < 2
153
- super
154
- elsif html_safe?
155
+ if html_safe?
155
156
  new_safe_buffer = super
156
157
 
157
158
  if new_safe_buffer
@@ -188,14 +189,36 @@ module ActiveSupport #:nodoc:
188
189
  end
189
190
  alias << concat
190
191
 
192
+ def insert(index, value)
193
+ super(index, html_escape_interpolated_argument(value))
194
+ end
195
+
191
196
  def prepend(value)
192
197
  super(html_escape_interpolated_argument(value))
193
198
  end
194
199
 
200
+ def replace(value)
201
+ super(html_escape_interpolated_argument(value))
202
+ end
203
+
204
+ def []=(*args)
205
+ if args.count == 3
206
+ super(args[0], args[1], html_escape_interpolated_argument(args[2]))
207
+ else
208
+ super(args[0], html_escape_interpolated_argument(args[1]))
209
+ end
210
+ end
211
+
195
212
  def +(other)
196
213
  dup.concat(other)
197
214
  end
198
215
 
216
+ def *(*)
217
+ new_safe_buffer = super
218
+ new_safe_buffer.instance_variable_set(:@html_safe, @html_safe)
219
+ new_safe_buffer
220
+ end
221
+
199
222
  def %(args)
200
223
  case args
201
224
  when Hash
@@ -238,11 +261,45 @@ module ActiveSupport #:nodoc:
238
261
  end
239
262
  end
240
263
 
241
- private
264
+ UNSAFE_STRING_METHODS_WITH_BACKREF.each do |unsafe_method|
265
+ if unsafe_method.respond_to?(unsafe_method)
266
+ class_eval <<-EOT, __FILE__, __LINE__ + 1
267
+ def #{unsafe_method}(*args, &block) # def gsub(*args, &block)
268
+ if block # if block
269
+ to_str.#{unsafe_method}(*args) { |*params| # to_str.gsub(*args) { |*params|
270
+ set_block_back_references(block, $~) # set_block_back_references(block, $~)
271
+ block.call(*params) # block.call(*params)
272
+ } # }
273
+ else # else
274
+ to_str.#{unsafe_method}(*args) # to_str.gsub(*args)
275
+ end # end
276
+ end # end
277
+
278
+ def #{unsafe_method}!(*args, &block) # def gsub!(*args, &block)
279
+ @html_safe = false # @html_safe = false
280
+ if block # if block
281
+ super(*args) { |*params| # super(*args) { |*params|
282
+ set_block_back_references(block, $~) # set_block_back_references(block, $~)
283
+ block.call(*params) # block.call(*params)
284
+ } # }
285
+ else # else
286
+ super # super
287
+ end # end
288
+ end # end
289
+ EOT
290
+ end
291
+ end
242
292
 
293
+ private
243
294
  def html_escape_interpolated_argument(arg)
244
295
  (!html_safe? || arg.html_safe?) ? arg : CGI.escapeHTML(arg.to_s)
245
296
  end
297
+
298
+ def set_block_back_references(block, match_data)
299
+ block.binding.eval("proc { |m| $~ = m }").call(match_data)
300
+ rescue ArgumentError
301
+ # Can't create binding from C level Proc
302
+ end
246
303
  end
247
304
  end
248
305
 
@@ -20,6 +20,8 @@ class String
20
20
  # Technically, it looks for the least indented non-empty line
21
21
  # in the whole string, and removes that amount of leading whitespace.
22
22
  def strip_heredoc
23
- gsub(/^#{scan(/^[ \t]*(?=\S)/).min}/, "".freeze)
23
+ gsub(/^#{scan(/^[ \t]*(?=\S)/).min}/, "").tap do |stripped|
24
+ stripped.freeze if frozen?
25
+ end
24
26
  end
25
27
  end
@@ -170,8 +170,7 @@ class Time
170
170
  options[:hours] = options.fetch(:hours, 0) + 24 * partial_days
171
171
  end
172
172
 
173
- d = to_date.advance(options)
174
- d = d.gregorian if d.julian?
173
+ d = to_date.gregorian.advance(options)
175
174
  time_advanced_by_date = change(year: d.year, month: d.month, day: d.day)
176
175
  seconds_to_advance = \
177
176
  options.fetch(:seconds, 0) +
@@ -312,4 +311,34 @@ class Time
312
311
  end
313
312
  alias_method :eql_without_coercion, :eql?
314
313
  alias_method :eql?, :eql_with_coercion
314
+
315
+ # Returns a new time the specified number of days ago.
316
+ def prev_day(days = 1)
317
+ advance(days: -days)
318
+ end
319
+
320
+ # Returns a new time the specified number of days in the future.
321
+ def next_day(days = 1)
322
+ advance(days: days)
323
+ end
324
+
325
+ # Returns a new time the specified number of months ago.
326
+ def prev_month(months = 1)
327
+ advance(months: -months)
328
+ end
329
+
330
+ # Returns a new time the specified number of months in the future.
331
+ def next_month(months = 1)
332
+ advance(months: months)
333
+ end
334
+
335
+ # Returns a new time the specified number of years ago.
336
+ def prev_year(years = 1)
337
+ advance(years: -years)
338
+ end
339
+
340
+ # Returns a new time the specified number of years in the future.
341
+ def next_year(years = 1)
342
+ advance(years: years)
343
+ end
315
344
  end
@@ -1,10 +1,8 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "uri"
4
- str = "\xE6\x97\xA5\xE6\x9C\xAC\xE8\xAA\x9E" # Ni-ho-nn-go in UTF-8, means Japanese.
5
- parser = URI::Parser.new
6
4
 
7
- unless str == parser.unescape(parser.escape(str))
5
+ if RUBY_VERSION < "2.6.0"
8
6
  require "active_support/core_ext/module/redefine_method"
9
7
  URI::Parser.class_eval do
10
8
  silence_redefinition_of_method :unescape
@@ -13,7 +11,7 @@ unless str == parser.unescape(parser.escape(str))
13
11
  # YK: My initial experiments say yes, but let's be sure please
14
12
  enc = str.encoding
15
13
  enc = Encoding::UTF_8 if enc == Encoding::US_ASCII
16
- str.gsub(escaped) { |match| [match[1, 2].hex].pack("C") }.force_encoding(enc)
14
+ str.dup.force_encoding(Encoding::ASCII_8BIT).gsub(escaped) { |match| [match[1, 2].hex].pack("C") }.force_encoding(enc)
17
15
  end
18
16
  end
19
17
  end
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "active_support/callbacks"
4
+
3
5
  module ActiveSupport
4
6
  # Abstract super class that provides a thread-isolated attributes singleton, which resets automatically
5
7
  # before and after each request. This allows you to keep all the per-request attributes easily
@@ -117,10 +119,16 @@ module ActiveSupport
117
119
  end
118
120
  end
119
121
 
122
+ # Calls this block before #reset is called on the instance. Used for resetting external collaborators that depend on current values.
123
+ def before_reset(&block)
124
+ set_callback :reset, :before, &block
125
+ end
126
+
120
127
  # Calls this block after #reset is called on the instance. Used for resetting external collaborators, like Time.zone.
121
128
  def resets(&block)
122
129
  set_callback :reset, :after, &block
123
130
  end
131
+ alias_method :after_reset, :resets
124
132
 
125
133
  delegate :set, :reset, to: :instance
126
134
 
@@ -20,6 +20,9 @@ module ActiveSupport #:nodoc:
20
20
  module Dependencies #:nodoc:
21
21
  extend self
22
22
 
23
+ UNBOUND_METHOD_MODULE_NAME = Module.instance_method(:name)
24
+ private_constant :UNBOUND_METHOD_MODULE_NAME
25
+
23
26
  mattr_accessor :interlock, default: Interlock.new
24
27
 
25
28
  # :doc:
@@ -70,6 +73,11 @@ module ActiveSupport #:nodoc:
70
73
  # only once. All directories in this set must also be present in +autoload_paths+.
71
74
  mattr_accessor :autoload_once_paths, default: []
72
75
 
76
+ # This is a private set that collects all eager load paths during bootstrap.
77
+ # Useful for Zeitwerk integration. Its public interface is the config.* path
78
+ # accessors of each engine.
79
+ mattr_accessor :_eager_load_paths, default: Set.new
80
+
73
81
  # An array of qualified constant names that have been loaded. Adding a name
74
82
  # to this array will cause it to be unloaded the next time Dependencies are
75
83
  # cleared.
@@ -79,6 +87,12 @@ module ActiveSupport #:nodoc:
79
87
  # to allow arbitrary constants to be marked for unloading.
80
88
  mattr_accessor :explicitly_unloadable_constants, default: []
81
89
 
90
+ # The logger used when tracing autoloads.
91
+ mattr_accessor :logger
92
+
93
+ # If true, trace autoloads with +logger.debug+.
94
+ mattr_accessor :verbose, default: false
95
+
82
96
  # The WatchStack keeps a stack of the modules being watched as files are
83
97
  # loaded. If a file in the process of being loaded (parent.rb) triggers the
84
98
  # load of another file (child.rb) the stack will ensure that child.rb
@@ -97,6 +111,8 @@ module ActiveSupport #:nodoc:
97
111
  # parent.rb then requires namespace/child.rb, the stack will look like
98
112
  # [[Object], [Namespace]].
99
113
 
114
+ attr_reader :watching
115
+
100
116
  def initialize
101
117
  @watching = []
102
118
  @stack = Hash.new { |h, k| h[k] = [] }
@@ -138,7 +154,7 @@ module ActiveSupport #:nodoc:
138
154
 
139
155
  # Normalize the list of new constants, and add them to the list we will return
140
156
  new_constants.each do |suffix|
141
- constants << ([namespace, suffix] - ["Object"]).join("::".freeze)
157
+ constants << ([namespace, suffix] - ["Object"]).join("::")
142
158
  end
143
159
  end
144
160
  constants
@@ -188,6 +204,11 @@ module ActiveSupport #:nodoc:
188
204
  end
189
205
  end
190
206
 
207
+ def self.include_into(base)
208
+ base.include(self)
209
+ append_features(base)
210
+ end
211
+
191
212
  def const_missing(const_name)
192
213
  from_mod = anonymous? ? guess_for_anonymous(const_name) : self
193
214
  Dependencies.load_missing_constant(from_mod, const_name)
@@ -217,6 +238,21 @@ module ActiveSupport #:nodoc:
217
238
  base.class_eval do
218
239
  define_method(:load, Kernel.instance_method(:load))
219
240
  private :load
241
+
242
+ define_method(:require, Kernel.instance_method(:require))
243
+ private :require
244
+ end
245
+ end
246
+
247
+ def self.include_into(base)
248
+ base.include(self)
249
+
250
+ if base.instance_method(:load).owner == base
251
+ base.remove_method(:load)
252
+ end
253
+
254
+ if base.instance_method(:require).owner == base
255
+ base.remove_method(:require)
220
256
  end
221
257
  end
222
258
 
@@ -224,6 +260,8 @@ module ActiveSupport #:nodoc:
224
260
  Dependencies.require_or_load(file_name)
225
261
  end
226
262
 
263
+ # :doc:
264
+
227
265
  # Interprets a file using <tt>mechanism</tt> and marks its defined
228
266
  # constants as autoloaded. <tt>file_name</tt> can be either a string or
229
267
  # respond to <tt>to_path</tt>.
@@ -242,9 +280,13 @@ module ActiveSupport #:nodoc:
242
280
  Dependencies.depend_on(file_name, message)
243
281
  end
244
282
 
283
+ # :nodoc:
284
+
245
285
  def load_dependency(file)
246
286
  if Dependencies.load? && Dependencies.constant_watch_stack.watching?
247
- Dependencies.new_constants_in(Object) { yield }
287
+ descs = Dependencies.constant_watch_stack.watching.flatten.uniq
288
+
289
+ Dependencies.new_constants_in(*descs) { yield }
248
290
  else
249
291
  yield
250
292
  end
@@ -271,7 +313,6 @@ module ActiveSupport #:nodoc:
271
313
  end
272
314
 
273
315
  private
274
-
275
316
  def load(file, wrap = false)
276
317
  result = false
277
318
  load_dependency(file) { result = super }
@@ -307,9 +348,9 @@ module ActiveSupport #:nodoc:
307
348
  end
308
349
 
309
350
  def hook!
310
- Object.class_eval { include Loadable }
311
- Module.class_eval { include ModuleConstMissing }
312
- Exception.class_eval { include Blamable }
351
+ Loadable.include_into(Object)
352
+ ModuleConstMissing.include_into(Module)
353
+ Exception.include(Blamable)
313
354
  end
314
355
 
315
356
  def unhook!
@@ -341,7 +382,7 @@ module ActiveSupport #:nodoc:
341
382
  end
342
383
 
343
384
  def require_or_load(file_name, const_path = nil)
344
- file_name = $` if file_name =~ /\.rb\z/
385
+ file_name = file_name.chomp(".rb")
345
386
  expanded = File.expand_path(file_name)
346
387
  return if loaded.include?(expanded)
347
388
 
@@ -391,7 +432,7 @@ module ActiveSupport #:nodoc:
391
432
  # constant paths which would cause Dependencies to attempt to load this
392
433
  # file.
393
434
  def loadable_constants_for_path(path, bases = autoload_paths)
394
- path = $` if path =~ /\.rb\z/
435
+ path = path.chomp(".rb")
395
436
  expanded_path = File.expand_path(path)
396
437
  paths = []
397
438
 
@@ -400,7 +441,7 @@ module ActiveSupport #:nodoc:
400
441
  next unless expanded_path.start_with?(expanded_root)
401
442
 
402
443
  root_size = expanded_root.size
403
- next if expanded_path[root_size] != ?/.freeze
444
+ next if expanded_path[root_size] != ?/
404
445
 
405
446
  nesting = expanded_path[(root_size + 1)..-1]
406
447
  paths << nesting.camelize unless nesting.blank?
@@ -412,7 +453,7 @@ module ActiveSupport #:nodoc:
412
453
 
413
454
  # Search for a file in autoload_paths matching the provided suffix.
414
455
  def search_for_file(path_suffix)
415
- path_suffix = path_suffix.sub(/(\.rb)?$/, ".rb".freeze)
456
+ path_suffix += ".rb" unless path_suffix.ends_with?(".rb")
416
457
 
417
458
  autoload_paths.each do |root|
418
459
  path = File.join(root, path_suffix)
@@ -446,6 +487,7 @@ module ActiveSupport #:nodoc:
446
487
  return nil unless base_path = autoloadable_module?(path_suffix)
447
488
  mod = Module.new
448
489
  into.const_set const_name, mod
490
+ log("constant #{qualified_name} autoloaded (module autovivified from #{File.join(base_path, path_suffix)})")
449
491
  autoloaded_constants << qualified_name unless autoload_once_paths.include?(base_path)
450
492
  autoloaded_constants.uniq!
451
493
  mod
@@ -487,26 +529,31 @@ module ActiveSupport #:nodoc:
487
529
  raise ArgumentError, "A copy of #{from_mod} has been removed from the module tree but is still active!"
488
530
  end
489
531
 
490
- qualified_name = qualified_name_for from_mod, const_name
532
+ qualified_name = qualified_name_for(from_mod, const_name)
491
533
  path_suffix = qualified_name.underscore
492
534
 
493
535
  file_path = search_for_file(path_suffix)
494
536
 
495
537
  if file_path
496
538
  expanded = File.expand_path(file_path)
497
- expanded.sub!(/\.rb\z/, "".freeze)
539
+ expanded.sub!(/\.rb\z/, "")
498
540
 
499
541
  if loading.include?(expanded)
500
542
  raise "Circular dependency detected while autoloading constant #{qualified_name}"
501
543
  else
502
544
  require_or_load(expanded, qualified_name)
503
- raise LoadError, "Unable to autoload constant #{qualified_name}, expected #{file_path} to define it" unless from_mod.const_defined?(const_name, false)
504
- return from_mod.const_get(const_name)
545
+
546
+ if from_mod.const_defined?(const_name, false)
547
+ log("constant #{qualified_name} autoloaded from #{expanded}.rb")
548
+ return from_mod.const_get(const_name)
549
+ else
550
+ raise LoadError, "Unable to autoload constant #{qualified_name}, expected #{file_path} to define it"
551
+ end
505
552
  end
506
553
  elsif mod = autoload_module!(from_mod, const_name, qualified_name, path_suffix)
507
554
  return mod
508
- elsif (parent = from_mod.parent) && parent != from_mod &&
509
- ! from_mod.parents.any? { |p| p.const_defined?(const_name, false) }
555
+ elsif (parent = from_mod.module_parent) && parent != from_mod &&
556
+ ! from_mod.module_parents.any? { |p| p.const_defined?(const_name, false) }
510
557
  # If our parents do not have a constant named +const_name+ then we are free
511
558
  # to attempt to load upwards. If they do have such a constant, then this
512
559
  # const_missing must be due to from_mod::const_name, which should not
@@ -550,6 +597,7 @@ module ActiveSupport #:nodoc:
550
597
  # as the environment will be in an inconsistent state, e.g. other constants
551
598
  # may have already been unloaded and not accessible.
552
599
  def remove_unloadable_constants!
600
+ log("removing unloadable constants")
553
601
  autoloaded_constants.each { |const| remove_constant const }
554
602
  autoloaded_constants.clear
555
603
  Reference.clear!
@@ -613,7 +661,7 @@ module ActiveSupport #:nodoc:
613
661
 
614
662
  # Determine if the given constant has been automatically loaded.
615
663
  def autoloaded?(desc)
616
- return false if desc.is_a?(Module) && desc.anonymous?
664
+ return false if desc.is_a?(Module) && real_mod_name(desc).nil?
617
665
  name = to_constant_name desc
618
666
  return false unless qualified_const_defined?(name)
619
667
  autoloaded_constants.include?(name)
@@ -669,7 +717,7 @@ module ActiveSupport #:nodoc:
669
717
  when String then desc.sub(/^::/, "")
670
718
  when Symbol then desc.to_s
671
719
  when Module
672
- desc.name ||
720
+ real_mod_name(desc) ||
673
721
  raise(ArgumentError, "Anonymous modules have no name to be referenced by")
674
722
  else raise TypeError, "Not a valid constant descriptor: #{desc.inspect}"
675
723
  end
@@ -739,6 +787,17 @@ module ActiveSupport #:nodoc:
739
787
  # The constant is no longer reachable, just skip it.
740
788
  end
741
789
  end
790
+
791
+ def log(message)
792
+ logger.debug("autoloading: #{message}") if logger && verbose
793
+ end
794
+
795
+ private
796
+ # Returns the original name of a class or module even if `name` has been
797
+ # overridden.
798
+ def real_mod_name(mod)
799
+ UNBOUND_METHOD_MODULE_NAME.bind(mod).call
800
+ end
742
801
  end
743
802
  end
744
803