activesupport 5.2.4.rc1 → 6.0.0.rc2

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 (138) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +312 -428
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +3 -2
  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 +28 -1
  8. data/lib/active_support/cache.rb +45 -23
  9. data/lib/active_support/cache/file_store.rb +22 -22
  10. data/lib/active_support/cache/mem_cache_store.rb +5 -0
  11. data/lib/active_support/cache/memory_store.rb +7 -2
  12. data/lib/active_support/cache/null_store.rb +5 -0
  13. data/lib/active_support/cache/redis_cache_store.rb +36 -9
  14. data/lib/active_support/callbacks.rb +16 -5
  15. data/lib/active_support/concern.rb +24 -1
  16. data/lib/active_support/configurable.rb +7 -11
  17. data/lib/active_support/core_ext/array.rb +1 -1
  18. data/lib/active_support/core_ext/array/access.rb +18 -6
  19. data/lib/active_support/core_ext/array/extract.rb +21 -0
  20. data/lib/active_support/core_ext/array/prepend_and_append.rb +2 -6
  21. data/lib/active_support/core_ext/class/attribute.rb +11 -16
  22. data/lib/active_support/core_ext/class/subclasses.rb +1 -1
  23. data/lib/active_support/core_ext/date/calculations.rb +6 -5
  24. data/lib/active_support/core_ext/date_and_time/calculations.rb +24 -47
  25. data/lib/active_support/core_ext/date_time/calculations.rb +1 -1
  26. data/lib/active_support/core_ext/enumerable.rb +97 -73
  27. data/lib/active_support/core_ext/hash.rb +1 -2
  28. data/lib/active_support/core_ext/hash/compact.rb +2 -26
  29. data/lib/active_support/core_ext/hash/deep_transform_values.rb +46 -0
  30. data/lib/active_support/core_ext/hash/except.rb +1 -1
  31. data/lib/active_support/core_ext/hash/keys.rb +0 -29
  32. data/lib/active_support/core_ext/hash/slice.rb +3 -25
  33. data/lib/active_support/core_ext/hash/transform_values.rb +2 -29
  34. data/lib/active_support/core_ext/integer/multiple.rb +1 -1
  35. data/lib/active_support/core_ext/kernel.rb +0 -1
  36. data/lib/active_support/core_ext/load_error.rb +1 -1
  37. data/lib/active_support/core_ext/module.rb +0 -1
  38. data/lib/active_support/core_ext/module/attribute_accessors.rb +7 -10
  39. data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +13 -19
  40. data/lib/active_support/core_ext/module/delegation.rb +27 -7
  41. data/lib/active_support/core_ext/module/introspection.rb +37 -13
  42. data/lib/active_support/core_ext/module/reachable.rb +1 -6
  43. data/lib/active_support/core_ext/module/redefine_method.rb +8 -17
  44. data/lib/active_support/core_ext/numeric.rb +0 -1
  45. data/lib/active_support/core_ext/numeric/conversions.rb +124 -128
  46. data/lib/active_support/core_ext/numeric/inquiry.rb +2 -25
  47. data/lib/active_support/core_ext/object/blank.rb +1 -2
  48. data/lib/active_support/core_ext/object/duplicable.rb +7 -114
  49. data/lib/active_support/core_ext/object/json.rb +1 -0
  50. data/lib/active_support/core_ext/object/try.rb +15 -7
  51. data/lib/active_support/core_ext/object/with_options.rb +1 -1
  52. data/lib/active_support/core_ext/range/compare_range.rb +22 -13
  53. data/lib/active_support/core_ext/range/conversions.rb +31 -29
  54. data/lib/active_support/core_ext/range/include_range.rb +6 -0
  55. data/lib/active_support/core_ext/regexp.rb +0 -4
  56. data/lib/active_support/core_ext/securerandom.rb +23 -3
  57. data/lib/active_support/core_ext/string/access.rb +8 -0
  58. data/lib/active_support/core_ext/string/filters.rb +42 -1
  59. data/lib/active_support/core_ext/string/inflections.rb +7 -2
  60. data/lib/active_support/core_ext/string/multibyte.rb +4 -3
  61. data/lib/active_support/core_ext/string/output_safety.rb +61 -5
  62. data/lib/active_support/core_ext/string/strip.rb +3 -1
  63. data/lib/active_support/core_ext/time/calculations.rb +31 -2
  64. data/lib/active_support/core_ext/uri.rb +1 -0
  65. data/lib/active_support/current_attributes.rb +8 -0
  66. data/lib/active_support/dependencies.rb +56 -14
  67. data/lib/active_support/dependencies/zeitwerk_integration.rb +99 -0
  68. data/lib/active_support/deprecation.rb +1 -1
  69. data/lib/active_support/deprecation/behaviors.rb +1 -1
  70. data/lib/active_support/deprecation/method_wrappers.rb +8 -20
  71. data/lib/active_support/deprecation/proxy_wrappers.rb +24 -5
  72. data/lib/active_support/descendants_tracker.rb +56 -9
  73. data/lib/active_support/duration.rb +4 -3
  74. data/lib/active_support/duration/iso8601_parser.rb +2 -3
  75. data/lib/active_support/duration/iso8601_serializer.rb +3 -4
  76. data/lib/active_support/encrypted_configuration.rb +0 -4
  77. data/lib/active_support/encrypted_file.rb +2 -1
  78. data/lib/active_support/evented_file_update_checker.rb +39 -9
  79. data/lib/active_support/execution_wrapper.rb +1 -0
  80. data/lib/active_support/gem_version.rb +4 -4
  81. data/lib/active_support/hash_with_indifferent_access.rb +22 -18
  82. data/lib/active_support/i18n.rb +1 -0
  83. data/lib/active_support/i18n_railtie.rb +9 -1
  84. data/lib/active_support/inflector/inflections.rb +1 -4
  85. data/lib/active_support/inflector/methods.rb +15 -27
  86. data/lib/active_support/inflector/transliterate.rb +20 -17
  87. data/lib/active_support/json/decoding.rb +23 -23
  88. data/lib/active_support/json/encoding.rb +6 -2
  89. data/lib/active_support/key_generator.rb +0 -32
  90. data/lib/active_support/lazy_load_hooks.rb +5 -1
  91. data/lib/active_support/locale/en.rb +31 -0
  92. data/lib/active_support/log_subscriber.rb +31 -8
  93. data/lib/active_support/logger.rb +0 -15
  94. data/lib/active_support/logger_silence.rb +28 -12
  95. data/lib/active_support/logger_thread_safe_level.rb +27 -6
  96. data/lib/active_support/message_encryptor.rb +3 -5
  97. data/lib/active_support/message_verifier.rb +3 -3
  98. data/lib/active_support/multibyte/chars.rb +29 -48
  99. data/lib/active_support/multibyte/unicode.rb +44 -281
  100. data/lib/active_support/notifications.rb +41 -4
  101. data/lib/active_support/notifications/fanout.rb +98 -13
  102. data/lib/active_support/notifications/instrumenter.rb +79 -8
  103. data/lib/active_support/number_helper.rb +7 -0
  104. data/lib/active_support/number_helper/number_to_currency_converter.rb +2 -2
  105. data/lib/active_support/number_helper/number_to_delimited_converter.rb +3 -1
  106. data/lib/active_support/number_helper/number_to_human_converter.rb +3 -1
  107. data/lib/active_support/number_helper/number_to_human_size_converter.rb +3 -1
  108. data/lib/active_support/number_helper/number_to_percentage_converter.rb +3 -1
  109. data/lib/active_support/number_helper/number_to_phone_converter.rb +2 -0
  110. data/lib/active_support/number_helper/number_to_rounded_converter.rb +5 -3
  111. data/lib/active_support/ordered_options.rb +1 -1
  112. data/lib/active_support/parameter_filter.rb +124 -0
  113. data/lib/active_support/rails.rb +0 -6
  114. data/lib/active_support/reloader.rb +4 -5
  115. data/lib/active_support/security_utils.rb +1 -1
  116. data/lib/active_support/subscriber.rb +65 -26
  117. data/lib/active_support/tagged_logging.rb +13 -4
  118. data/lib/active_support/test_case.rb +91 -0
  119. data/lib/active_support/testing/assertions.rb +15 -1
  120. data/lib/active_support/testing/deprecation.rb +0 -1
  121. data/lib/active_support/testing/file_fixtures.rb +2 -0
  122. data/lib/active_support/testing/isolation.rb +2 -2
  123. data/lib/active_support/testing/method_call_assertions.rb +28 -1
  124. data/lib/active_support/testing/parallelization.rb +128 -0
  125. data/lib/active_support/testing/stream.rb +1 -1
  126. data/lib/active_support/testing/time_helpers.rb +7 -7
  127. data/lib/active_support/time_with_zone.rb +15 -5
  128. data/lib/active_support/values/time_zone.rb +12 -7
  129. data/lib/active_support/xml_mini.rb +2 -9
  130. data/lib/active_support/xml_mini/jdom.rb +2 -2
  131. data/lib/active_support/xml_mini/libxml.rb +2 -2
  132. data/lib/active_support/xml_mini/libxmlsax.rb +4 -4
  133. data/lib/active_support/xml_mini/nokogiri.rb +2 -2
  134. data/lib/active_support/xml_mini/nokogirisax.rb +3 -3
  135. data/lib/active_support/xml_mini/rexml.rb +2 -2
  136. metadata +34 -9
  137. data/lib/active_support/core_ext/kernel/agnostics.rb +0 -13
  138. data/lib/active_support/values/unicode_tables.dat +0 -0
@@ -75,6 +75,10 @@ class String
75
75
  # str.first(0) # => ""
76
76
  # str.first(6) # => "hello"
77
77
  def first(limit = 1)
78
+ ActiveSupport::Deprecation.warn(
79
+ "Calling String#first with a negative integer limit " \
80
+ "will raise an ArgumentError in Rails 6.1."
81
+ ) if limit < 0
78
82
  if limit == 0
79
83
  ""
80
84
  elsif limit >= size
@@ -95,6 +99,10 @@ class String
95
99
  # str.last(0) # => ""
96
100
  # str.last(6) # => "hello"
97
101
  def last(limit = 1)
102
+ ActiveSupport::Deprecation.warn(
103
+ "Calling String#last with a negative integer limit " \
104
+ "will raise an ArgumentError in Rails 6.1."
105
+ ) if limit < 0
98
106
  if limit == 0
99
107
  ""
100
108
  elsif limit >= size
@@ -75,7 +75,48 @@ class String
75
75
  length_with_room_for_omission
76
76
  end
77
77
 
78
- "#{self[0, stop]}#{omission}"
78
+ +"#{self[0, stop]}#{omission}"
79
+ end
80
+
81
+ # Truncates +text+ to at most <tt>bytesize</tt> bytes in length without
82
+ # breaking string encoding by splitting multibyte characters or breaking
83
+ # grapheme clusters ("perceptual characters") by truncating at combining
84
+ # characters.
85
+ #
86
+ # >> "🔪🔪🔪🔪🔪🔪🔪🔪🔪🔪🔪🔪🔪🔪🔪🔪🔪🔪🔪🔪".size
87
+ # => 20
88
+ # >> "🔪🔪🔪🔪🔪🔪🔪🔪🔪🔪🔪🔪🔪🔪🔪🔪🔪🔪🔪🔪".bytesize
89
+ # => 80
90
+ # >> "🔪🔪🔪🔪🔪🔪🔪🔪🔪🔪🔪🔪🔪🔪🔪🔪🔪🔪🔪🔪".truncate_bytes(20)
91
+ # => "🔪🔪🔪🔪…"
92
+ #
93
+ # The truncated text ends with the <tt>:omission</tt> string, defaulting
94
+ # to "…", for a total length not exceeding <tt>bytesize</tt>.
95
+ def truncate_bytes(truncate_at, omission: "…")
96
+ omission ||= ""
97
+
98
+ case
99
+ when bytesize <= truncate_at
100
+ dup
101
+ when omission.bytesize > truncate_at
102
+ raise ArgumentError, "Omission #{omission.inspect} is #{omission.bytesize}, larger than the truncation length of #{truncate_at} bytes"
103
+ when omission.bytesize == truncate_at
104
+ omission.dup
105
+ else
106
+ self.class.new.tap do |cut|
107
+ cut_at = truncate_at - omission.bytesize
108
+
109
+ scan(/\X/) do |grapheme|
110
+ if cut.bytesize + grapheme.bytesize <= cut_at
111
+ cut << grapheme
112
+ else
113
+ break
114
+ end
115
+ end
116
+
117
+ cut << omission
118
+ end
119
+ end
79
120
  end
80
121
 
81
122
  # Truncates a given +text+ after a given number of words (<tt>words_count</tt>):
@@ -162,6 +162,11 @@ class String
162
162
 
163
163
  # Replaces special characters in a string so that it may be used as part of a 'pretty' URL.
164
164
  #
165
+ # If the optional parameter +locale+ is specified,
166
+ # the word will be parameterized as a word of that language.
167
+ # By default, this parameter is set to <tt>nil</tt> and it will use
168
+ # the configured <tt>I18n.locale</tt>.
169
+ #
165
170
  # class Person
166
171
  # def to_param
167
172
  # "#{id}-#{name.parameterize}"
@@ -187,8 +192,8 @@ class String
187
192
  #
188
193
  # <%= link_to(@person.name, person_path) %>
189
194
  # # => <a href="/person/1-Donald-E-Knuth">Donald E. Knuth</a>
190
- def parameterize(separator: "-", preserve_case: false)
191
- ActiveSupport::Inflector.parameterize(self, separator: separator, preserve_case: preserve_case)
195
+ def parameterize(separator: "-", preserve_case: false, locale: nil)
196
+ ActiveSupport::Inflector.parameterize(self, separator: separator, preserve_case: preserve_case, locale: locale)
192
197
  end
193
198
 
194
199
  # Creates the name of a table like Rails does for models to table names. This method
@@ -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,44 @@ module ActiveSupport #:nodoc:
238
261
  end
239
262
  end
240
263
 
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
292
+
241
293
  private
242
294
 
243
295
  def html_escape_interpolated_argument(arg)
244
296
  (!html_safe? || arg.html_safe?) ? arg : CGI.escapeHTML(arg.to_s)
245
297
  end
298
+
299
+ def set_block_back_references(block, match_data)
300
+ block.binding.eval("proc { |m| $~ = m }").call(match_data)
301
+ end
246
302
  end
247
303
  end
248
304
 
@@ -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,6 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "uri"
4
+
4
5
  if RUBY_VERSION < "2.6.0"
5
6
  require "active_support/core_ext/module/redefine_method"
6
7
  URI::Parser.class_eval do
@@ -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
 
@@ -70,6 +70,11 @@ module ActiveSupport #:nodoc:
70
70
  # only once. All directories in this set must also be present in +autoload_paths+.
71
71
  mattr_accessor :autoload_once_paths, default: []
72
72
 
73
+ # This is a private set that collects all eager load paths during bootstrap.
74
+ # Useful for Zeitwerk integration. Its public interface is the config.* path
75
+ # accessors of each engine.
76
+ mattr_accessor :_eager_load_paths, default: Set.new
77
+
73
78
  # An array of qualified constant names that have been loaded. Adding a name
74
79
  # to this array will cause it to be unloaded the next time Dependencies are
75
80
  # cleared.
@@ -79,6 +84,12 @@ module ActiveSupport #:nodoc:
79
84
  # to allow arbitrary constants to be marked for unloading.
80
85
  mattr_accessor :explicitly_unloadable_constants, default: []
81
86
 
87
+ # The logger used when tracing autoloads.
88
+ mattr_accessor :logger
89
+
90
+ # If true, trace autoloads with +logger.debug+.
91
+ mattr_accessor :verbose, default: false
92
+
82
93
  # The WatchStack keeps a stack of the modules being watched as files are
83
94
  # loaded. If a file in the process of being loaded (parent.rb) triggers the
84
95
  # load of another file (child.rb) the stack will ensure that child.rb
@@ -140,7 +151,7 @@ module ActiveSupport #:nodoc:
140
151
 
141
152
  # Normalize the list of new constants, and add them to the list we will return
142
153
  new_constants.each do |suffix|
143
- constants << ([namespace, suffix] - ["Object"]).join("::".freeze)
154
+ constants << ([namespace, suffix] - ["Object"]).join("::")
144
155
  end
145
156
  end
146
157
  constants
@@ -190,6 +201,11 @@ module ActiveSupport #:nodoc:
190
201
  end
191
202
  end
192
203
 
204
+ def self.include_into(base)
205
+ base.include(self)
206
+ append_features(base)
207
+ end
208
+
193
209
  def const_missing(const_name)
194
210
  from_mod = anonymous? ? guess_for_anonymous(const_name) : self
195
211
  Dependencies.load_missing_constant(from_mod, const_name)
@@ -219,6 +235,21 @@ module ActiveSupport #:nodoc:
219
235
  base.class_eval do
220
236
  define_method(:load, Kernel.instance_method(:load))
221
237
  private :load
238
+
239
+ define_method(:require, Kernel.instance_method(:require))
240
+ private :require
241
+ end
242
+ end
243
+
244
+ def self.include_into(base)
245
+ base.include(self)
246
+
247
+ if base.instance_method(:load).owner == base
248
+ base.remove_method(:load)
249
+ end
250
+
251
+ if base.instance_method(:require).owner == base
252
+ base.remove_method(:require)
222
253
  end
223
254
  end
224
255
 
@@ -315,9 +346,9 @@ module ActiveSupport #:nodoc:
315
346
  end
316
347
 
317
348
  def hook!
318
- Object.class_eval { include Loadable }
319
- Module.class_eval { include ModuleConstMissing }
320
- Exception.class_eval { include Blamable }
349
+ Loadable.include_into(Object)
350
+ ModuleConstMissing.include_into(Module)
351
+ Exception.include(Blamable)
321
352
  end
322
353
 
323
354
  def unhook!
@@ -349,7 +380,7 @@ module ActiveSupport #:nodoc:
349
380
  end
350
381
 
351
382
  def require_or_load(file_name, const_path = nil)
352
- file_name = $` if file_name =~ /\.rb\z/
383
+ file_name = file_name.chomp(".rb")
353
384
  expanded = File.expand_path(file_name)
354
385
  return if loaded.include?(expanded)
355
386
 
@@ -399,7 +430,7 @@ module ActiveSupport #:nodoc:
399
430
  # constant paths which would cause Dependencies to attempt to load this
400
431
  # file.
401
432
  def loadable_constants_for_path(path, bases = autoload_paths)
402
- path = $` if path =~ /\.rb\z/
433
+ path = path.chomp(".rb")
403
434
  expanded_path = File.expand_path(path)
404
435
  paths = []
405
436
 
@@ -408,7 +439,7 @@ module ActiveSupport #:nodoc:
408
439
  next unless expanded_path.start_with?(expanded_root)
409
440
 
410
441
  root_size = expanded_root.size
411
- next if expanded_path[root_size] != ?/.freeze
442
+ next if expanded_path[root_size] != ?/
412
443
 
413
444
  nesting = expanded_path[(root_size + 1)..-1]
414
445
  paths << nesting.camelize unless nesting.blank?
@@ -420,7 +451,7 @@ module ActiveSupport #:nodoc:
420
451
 
421
452
  # Search for a file in autoload_paths matching the provided suffix.
422
453
  def search_for_file(path_suffix)
423
- path_suffix = path_suffix.sub(/(\.rb)?$/, ".rb".freeze)
454
+ path_suffix += ".rb" unless path_suffix.ends_with?(".rb")
424
455
 
425
456
  autoload_paths.each do |root|
426
457
  path = File.join(root, path_suffix)
@@ -454,6 +485,7 @@ module ActiveSupport #:nodoc:
454
485
  return nil unless base_path = autoloadable_module?(path_suffix)
455
486
  mod = Module.new
456
487
  into.const_set const_name, mod
488
+ log("constant #{qualified_name} autoloaded (module autovivified from #{File.join(base_path, path_suffix)})")
457
489
  autoloaded_constants << qualified_name unless autoload_once_paths.include?(base_path)
458
490
  autoloaded_constants.uniq!
459
491
  mod
@@ -495,26 +527,31 @@ module ActiveSupport #:nodoc:
495
527
  raise ArgumentError, "A copy of #{from_mod} has been removed from the module tree but is still active!"
496
528
  end
497
529
 
498
- qualified_name = qualified_name_for from_mod, const_name
530
+ qualified_name = qualified_name_for(from_mod, const_name)
499
531
  path_suffix = qualified_name.underscore
500
532
 
501
533
  file_path = search_for_file(path_suffix)
502
534
 
503
535
  if file_path
504
536
  expanded = File.expand_path(file_path)
505
- expanded.sub!(/\.rb\z/, "".freeze)
537
+ expanded.sub!(/\.rb\z/, "")
506
538
 
507
539
  if loading.include?(expanded)
508
540
  raise "Circular dependency detected while autoloading constant #{qualified_name}"
509
541
  else
510
542
  require_or_load(expanded, qualified_name)
511
- raise LoadError, "Unable to autoload constant #{qualified_name}, expected #{file_path} to define it" unless from_mod.const_defined?(const_name, false)
512
- return from_mod.const_get(const_name)
543
+
544
+ if from_mod.const_defined?(const_name, false)
545
+ log("constant #{qualified_name} autoloaded from #{expanded}.rb")
546
+ return from_mod.const_get(const_name)
547
+ else
548
+ raise LoadError, "Unable to autoload constant #{qualified_name}, expected #{file_path} to define it"
549
+ end
513
550
  end
514
551
  elsif mod = autoload_module!(from_mod, const_name, qualified_name, path_suffix)
515
552
  return mod
516
- elsif (parent = from_mod.parent) && parent != from_mod &&
517
- ! from_mod.parents.any? { |p| p.const_defined?(const_name, false) }
553
+ elsif (parent = from_mod.module_parent) && parent != from_mod &&
554
+ ! from_mod.module_parents.any? { |p| p.const_defined?(const_name, false) }
518
555
  # If our parents do not have a constant named +const_name+ then we are free
519
556
  # to attempt to load upwards. If they do have such a constant, then this
520
557
  # const_missing must be due to from_mod::const_name, which should not
@@ -558,6 +595,7 @@ module ActiveSupport #:nodoc:
558
595
  # as the environment will be in an inconsistent state, e.g. other constants
559
596
  # may have already been unloaded and not accessible.
560
597
  def remove_unloadable_constants!
598
+ log("removing unloadable constants")
561
599
  autoloaded_constants.each { |const| remove_constant const }
562
600
  autoloaded_constants.clear
563
601
  Reference.clear!
@@ -747,6 +785,10 @@ module ActiveSupport #:nodoc:
747
785
  # The constant is no longer reachable, just skip it.
748
786
  end
749
787
  end
788
+
789
+ def log(message)
790
+ logger.debug("autoloading: #{message}") if logger && verbose
791
+ end
750
792
  end
751
793
  end
752
794