activesupport 5.2.8.1 → 6.0.0.beta1

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 (128) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +182 -586
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +1 -1
  5. data/lib/active_support/backtrace_cleaner.rb +23 -0
  6. data/lib/active_support/cache/file_store.rb +19 -12
  7. data/lib/active_support/cache/mem_cache_store.rb +16 -2
  8. data/lib/active_support/cache/memory_store.rb +5 -0
  9. data/lib/active_support/cache/null_store.rb +5 -0
  10. data/lib/active_support/cache/redis_cache_store.rb +39 -20
  11. data/lib/active_support/cache.rb +40 -18
  12. data/lib/active_support/callbacks.rb +16 -5
  13. data/lib/active_support/concurrency/load_interlock_aware_monitor.rb +0 -18
  14. data/lib/active_support/configurable.rb +4 -8
  15. data/lib/active_support/core_ext/array/extract.rb +21 -0
  16. data/lib/active_support/core_ext/array/prepend_and_append.rb +2 -6
  17. data/lib/active_support/core_ext/array.rb +1 -1
  18. data/lib/active_support/core_ext/class/attribute.rb +1 -1
  19. data/lib/active_support/core_ext/class/subclasses.rb +1 -1
  20. data/lib/active_support/core_ext/date/calculations.rb +6 -5
  21. data/lib/active_support/core_ext/date_and_time/calculations.rb +24 -17
  22. data/lib/active_support/core_ext/date_time/calculations.rb +1 -1
  23. data/lib/active_support/core_ext/enumerable.rb +71 -67
  24. data/lib/active_support/core_ext/hash/compact.rb +2 -26
  25. data/lib/active_support/core_ext/hash/keys.rb +0 -29
  26. data/lib/active_support/core_ext/hash/slice.rb +3 -25
  27. data/lib/active_support/core_ext/hash/transform_values.rb +2 -29
  28. data/lib/active_support/core_ext/hash.rb +0 -2
  29. data/lib/active_support/core_ext/integer/multiple.rb +1 -1
  30. data/lib/active_support/core_ext/load_error.rb +1 -1
  31. data/lib/active_support/core_ext/module/attribute_accessors.rb +2 -5
  32. data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +8 -14
  33. data/lib/active_support/core_ext/module/delegation.rb +27 -7
  34. data/lib/active_support/core_ext/module/introspection.rb +37 -13
  35. data/lib/active_support/core_ext/module/reachable.rb +1 -6
  36. data/lib/active_support/core_ext/module/redefine_method.rb +8 -17
  37. data/lib/active_support/core_ext/module.rb +0 -1
  38. data/lib/active_support/core_ext/numeric/conversions.rb +124 -128
  39. data/lib/active_support/core_ext/numeric/inquiry.rb +2 -25
  40. data/lib/active_support/core_ext/numeric.rb +0 -1
  41. data/lib/active_support/core_ext/object/blank.rb +1 -2
  42. data/lib/active_support/core_ext/object/duplicable.rb +5 -2
  43. data/lib/active_support/core_ext/object/json.rb +1 -0
  44. data/lib/active_support/core_ext/object/try.rb +15 -7
  45. data/lib/active_support/core_ext/object/with_options.rb +1 -1
  46. data/lib/active_support/core_ext/range/compare_range.rb +1 -1
  47. data/lib/active_support/core_ext/range/conversions.rb +31 -29
  48. data/lib/active_support/core_ext/range/include_range.rb +6 -0
  49. data/lib/active_support/core_ext/regexp.rb +0 -4
  50. data/lib/active_support/core_ext/securerandom.rb +23 -3
  51. data/lib/active_support/core_ext/string/access.rb +8 -0
  52. data/lib/active_support/core_ext/string/filters.rb +41 -0
  53. data/lib/active_support/core_ext/string/multibyte.rb +4 -3
  54. data/lib/active_support/core_ext/string/output_safety.rb +16 -33
  55. data/lib/active_support/core_ext/string/strip.rb +3 -1
  56. data/lib/active_support/core_ext/uri.rb +1 -0
  57. data/lib/active_support/current_attributes.rb +2 -0
  58. data/lib/active_support/dependencies.rb +28 -11
  59. data/lib/active_support/deprecation/behaviors.rb +1 -1
  60. data/lib/active_support/deprecation/method_wrappers.rb +4 -5
  61. data/lib/active_support/deprecation/proxy_wrappers.rb +0 -2
  62. data/lib/active_support/deprecation.rb +1 -1
  63. data/lib/active_support/descendants_tracker.rb +6 -5
  64. data/lib/active_support/duration/iso8601_parser.rb +2 -3
  65. data/lib/active_support/duration/iso8601_serializer.rb +3 -4
  66. data/lib/active_support/duration.rb +12 -14
  67. data/lib/active_support/encrypted_configuration.rb +0 -4
  68. data/lib/active_support/evented_file_update_checker.rb +25 -7
  69. data/lib/active_support/execution_wrapper.rb +14 -16
  70. data/lib/active_support/gem_version.rb +4 -4
  71. data/lib/active_support/hash_with_indifferent_access.rb +16 -28
  72. data/lib/active_support/i18n.rb +1 -0
  73. data/lib/active_support/i18n_railtie.rb +8 -1
  74. data/lib/active_support/inflector/inflections.rb +1 -4
  75. data/lib/active_support/inflector/methods.rb +15 -27
  76. data/lib/active_support/inflector/transliterate.rb +6 -6
  77. data/lib/active_support/json/decoding.rb +23 -23
  78. data/lib/active_support/json/encoding.rb +6 -2
  79. data/lib/active_support/key_generator.rb +0 -32
  80. data/lib/active_support/lazy_load_hooks.rb +5 -1
  81. data/lib/active_support/locale/en.rb +31 -0
  82. data/lib/active_support/log_subscriber.rb +31 -8
  83. data/lib/active_support/logger.rb +0 -15
  84. data/lib/active_support/logger_silence.rb +28 -12
  85. data/lib/active_support/logger_thread_safe_level.rb +27 -6
  86. data/lib/active_support/message_encryptor.rb +2 -4
  87. data/lib/active_support/message_verifier.rb +2 -2
  88. data/lib/active_support/multibyte/chars.rb +29 -48
  89. data/lib/active_support/multibyte/unicode.rb +44 -281
  90. data/lib/active_support/notifications/fanout.rb +42 -4
  91. data/lib/active_support/notifications/instrumenter.rb +73 -2
  92. data/lib/active_support/notifications.rb +32 -4
  93. data/lib/active_support/number_helper/number_to_currency_converter.rb +2 -2
  94. data/lib/active_support/number_helper/number_to_delimited_converter.rb +3 -1
  95. data/lib/active_support/number_helper/number_to_human_converter.rb +3 -1
  96. data/lib/active_support/number_helper/number_to_human_size_converter.rb +3 -1
  97. data/lib/active_support/number_helper/number_to_percentage_converter.rb +3 -1
  98. data/lib/active_support/number_helper/number_to_phone_converter.rb +2 -0
  99. data/lib/active_support/number_helper/number_to_rounded_converter.rb +5 -3
  100. data/lib/active_support/number_helper.rb +7 -0
  101. data/lib/active_support/ordered_options.rb +1 -1
  102. data/lib/active_support/parameter_filter.rb +124 -0
  103. data/lib/active_support/rails.rb +0 -6
  104. data/lib/active_support/reloader.rb +5 -6
  105. data/lib/active_support/subscriber.rb +16 -26
  106. data/lib/active_support/tagged_logging.rb +13 -4
  107. data/lib/active_support/test_case.rb +91 -0
  108. data/lib/active_support/testing/assertions.rb +15 -1
  109. data/lib/active_support/testing/deprecation.rb +0 -1
  110. data/lib/active_support/testing/file_fixtures.rb +2 -0
  111. data/lib/active_support/testing/isolation.rb +2 -2
  112. data/lib/active_support/testing/method_call_assertions.rb +28 -1
  113. data/lib/active_support/testing/parallelization.rb +109 -0
  114. data/lib/active_support/testing/stream.rb +1 -1
  115. data/lib/active_support/testing/time_helpers.rb +7 -7
  116. data/lib/active_support/time_with_zone.rb +15 -5
  117. data/lib/active_support/values/time_zone.rb +12 -7
  118. data/lib/active_support/xml_mini/jdom.rb +2 -2
  119. data/lib/active_support/xml_mini/libxml.rb +2 -2
  120. data/lib/active_support/xml_mini/libxmlsax.rb +4 -4
  121. data/lib/active_support/xml_mini/nokogiri.rb +2 -2
  122. data/lib/active_support/xml_mini/nokogirisax.rb +3 -3
  123. data/lib/active_support/xml_mini/rexml.rb +2 -2
  124. data/lib/active_support/xml_mini.rb +2 -9
  125. data/lib/active_support.rb +1 -1
  126. metadata +15 -13
  127. data/lib/active_support/core_ext/digest.rb +0 -3
  128. data/lib/active_support/values/unicode_tables.dat +0 -0
@@ -1,3 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "active_support/deprecation"
4
+
5
+ ActiveSupport::Deprecation.warn "You have required `active_support/core_ext/range/include_range`. " \
6
+ "This file will be removed in Rails 6.1. You should require `active_support/core_ext/range/compare_range` " \
7
+ "instead."
8
+
3
9
  require "active_support/core_ext/range/compare_range"
@@ -4,8 +4,4 @@ class Regexp #:nodoc:
4
4
  def multiline?
5
5
  options & MULTILINE == MULTILINE
6
6
  end
7
-
8
- def match?(string, pos = 0)
9
- !!match(string, pos)
10
- end unless //.respond_to?(:match?)
11
7
  end
@@ -4,17 +4,18 @@ require "securerandom"
4
4
 
5
5
  module SecureRandom
6
6
  BASE58_ALPHABET = ("0".."9").to_a + ("A".."Z").to_a + ("a".."z").to_a - ["0", "O", "I", "l"]
7
+ BASE36_ALPHABET = ("0".."9").to_a + ("a".."z").to_a
8
+
7
9
  # SecureRandom.base58 generates a random base58 string.
8
10
  #
9
- # The argument _n_ specifies the length, of the random string to be generated.
11
+ # The argument _n_ specifies the length of the random string to be generated.
10
12
  #
11
13
  # If _n_ is not specified or is +nil+, 16 is assumed. It may be larger in the future.
12
14
  #
13
- # The result may contain alphanumeric characters except 0, O, I and l
15
+ # The result may contain alphanumeric characters except 0, O, I and l.
14
16
  #
15
17
  # p SecureRandom.base58 # => "4kUgL2pdQMSCQtjE"
16
18
  # p SecureRandom.base58(24) # => "77TMHrHJFvFDwodq8w7Ev2m7"
17
- #
18
19
  def self.base58(n = 16)
19
20
  SecureRandom.random_bytes(n).unpack("C*").map do |byte|
20
21
  idx = byte % 64
@@ -22,4 +23,23 @@ module SecureRandom
22
23
  BASE58_ALPHABET[idx]
23
24
  end.join
24
25
  end
26
+
27
+ # SecureRandom.base36 generates a random base36 string in lowercase.
28
+ #
29
+ # The argument _n_ specifies the length of the random string to be generated.
30
+ #
31
+ # If _n_ is not specified or is +nil+, 16 is assumed. It may be larger in the future.
32
+ # This method can be used over +base58+ if a deterministic case key is necessary.
33
+ #
34
+ # The result will contain alphanumeric characters in lowercase.
35
+ #
36
+ # p SecureRandom.base36 # => "4kugl2pdqmscqtje"
37
+ # p SecureRandom.base36(24) # => "77tmhrhjfvfdwodq8w7ev2m7"
38
+ def self.base36(n = 16)
39
+ SecureRandom.random_bytes(n).unpack("C*").map do |byte|
40
+ idx = byte % 64
41
+ idx = SecureRandom.random_number(36) if idx >= 36
42
+ BASE36_ALPHABET[idx]
43
+ end.join
44
+ end
25
45
  end
@@ -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
@@ -78,6 +78,47 @@ class String
78
78
  "#{self[0, stop]}#{omission}"
79
79
  end
80
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
120
+ end
121
+
81
122
  # Truncates a given +text+ after a given number of words (<tt>words_count</tt>):
82
123
  #
83
124
  # 'Once upon a time in a world far far away'.truncate_words(4)
@@ -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
  #
@@ -12,14 +12,6 @@ class ERB
12
12
  HTML_ESCAPE_ONCE_REGEXP = /["><']|&(?!([a-zA-Z]+|(#\d+)|(#[xX][\dA-Fa-f]+));)/
13
13
  JSON_ESCAPE_REGEXP = /[\u2028\u2029&><]/u
14
14
 
15
- # Following XML requirements: https://www.w3.org/TR/REC-xml/#NT-Name
16
- TAG_NAME_START_REGEXP_SET = "@:A-Z_a-z\u{C0}-\u{D6}\u{D8}-\u{F6}\u{F8}-\u{2FF}\u{370}-\u{37D}\u{37F}-\u{1FFF}" \
17
- "\u{200C}-\u{200D}\u{2070}-\u{218F}\u{2C00}-\u{2FEF}\u{3001}-\u{D7FF}\u{F900}-\u{FDCF}" \
18
- "\u{FDF0}-\u{FFFD}\u{10000}-\u{EFFFF}"
19
- TAG_NAME_START_REGEXP = /[^#{TAG_NAME_START_REGEXP_SET}]/
20
- TAG_NAME_FOLLOWING_REGEXP = /[^#{TAG_NAME_START_REGEXP_SET}\-.0-9\u{B7}\u{0300}-\u{036F}\u{203F}-\u{2040}]/
21
- TAG_NAME_REPLACEMENT_CHAR = "_"
22
-
23
15
  # A utility method for escaping HTML tag characters.
24
16
  # This method is also aliased as <tt>h</tt>.
25
17
  #
@@ -124,26 +116,6 @@ class ERB
124
116
  end
125
117
 
126
118
  module_function :json_escape
127
-
128
- # A utility method for escaping XML names of tags and names of attributes.
129
- #
130
- # xml_name_escape('1 < 2 & 3')
131
- # # => "1___2___3"
132
- #
133
- # It follows the requirements of the specification: https://www.w3.org/TR/REC-xml/#NT-Name
134
- def xml_name_escape(name)
135
- name = name.to_s
136
- return "" if name.blank?
137
-
138
- starting_char = name[0].gsub(TAG_NAME_START_REGEXP, TAG_NAME_REPLACEMENT_CHAR)
139
-
140
- return starting_char if name.size == 1
141
-
142
- following_chars = name[1..-1].gsub(TAG_NAME_FOLLOWING_REGEXP, TAG_NAME_REPLACEMENT_CHAR)
143
-
144
- starting_char + following_chars
145
- end
146
- module_function :xml_name_escape
147
119
  end
148
120
  end
149
121
 
@@ -162,8 +134,9 @@ end
162
134
  module ActiveSupport #:nodoc:
163
135
  class SafeBuffer < String
164
136
  UNSAFE_STRING_METHODS = %w(
165
- capitalize chomp chop delete downcase gsub lstrip next reverse rstrip
166
- slice squeeze strip sub succ swapcase tr tr_s upcase
137
+ capitalize chomp chop delete delete_prefix delete_suffix
138
+ downcase gsub lstrip next reverse rstrip slice squeeze strip
139
+ sub succ swapcase tr tr_s unicode_normalize upcase
167
140
  )
168
141
 
169
142
  alias_method :original_concat, :concat
@@ -177,9 +150,7 @@ module ActiveSupport #:nodoc:
177
150
  end
178
151
 
179
152
  def [](*args)
180
- if args.size < 2
181
- super
182
- elsif html_safe?
153
+ if html_safe?
183
154
  new_safe_buffer = super
184
155
 
185
156
  if new_safe_buffer
@@ -216,10 +187,22 @@ module ActiveSupport #:nodoc:
216
187
  end
217
188
  alias << concat
218
189
 
190
+ def insert(index, value)
191
+ super(index, html_escape_interpolated_argument(value))
192
+ end
193
+
219
194
  def prepend(value)
220
195
  super(html_escape_interpolated_argument(value))
221
196
  end
222
197
 
198
+ def replace(value)
199
+ super(html_escape_interpolated_argument(value))
200
+ end
201
+
202
+ def []=(index, value)
203
+ super(index, html_escape_interpolated_argument(value))
204
+ end
205
+
223
206
  def +(other)
224
207
  dup.concat(other)
225
208
  end
@@ -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
@@ -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
@@ -79,6 +79,12 @@ module ActiveSupport #:nodoc:
79
79
  # to allow arbitrary constants to be marked for unloading.
80
80
  mattr_accessor :explicitly_unloadable_constants, default: []
81
81
 
82
+ # The logger used when tracing autoloads.
83
+ mattr_accessor :logger
84
+
85
+ # If true, trace autoloads with +logger.debug+.
86
+ mattr_accessor :verbose, default: false
87
+
82
88
  # The WatchStack keeps a stack of the modules being watched as files are
83
89
  # loaded. If a file in the process of being loaded (parent.rb) triggers the
84
90
  # load of another file (child.rb) the stack will ensure that child.rb
@@ -140,7 +146,7 @@ module ActiveSupport #:nodoc:
140
146
 
141
147
  # Normalize the list of new constants, and add them to the list we will return
142
148
  new_constants.each do |suffix|
143
- constants << ([namespace, suffix] - ["Object"]).join("::".freeze)
149
+ constants << ([namespace, suffix] - ["Object"]).join("::")
144
150
  end
145
151
  end
146
152
  constants
@@ -349,7 +355,7 @@ module ActiveSupport #:nodoc:
349
355
  end
350
356
 
351
357
  def require_or_load(file_name, const_path = nil)
352
- file_name = $` if file_name =~ /\.rb\z/
358
+ file_name = file_name.chomp(".rb")
353
359
  expanded = File.expand_path(file_name)
354
360
  return if loaded.include?(expanded)
355
361
 
@@ -399,7 +405,7 @@ module ActiveSupport #:nodoc:
399
405
  # constant paths which would cause Dependencies to attempt to load this
400
406
  # file.
401
407
  def loadable_constants_for_path(path, bases = autoload_paths)
402
- path = $` if path =~ /\.rb\z/
408
+ path = path.chomp(".rb")
403
409
  expanded_path = File.expand_path(path)
404
410
  paths = []
405
411
 
@@ -408,7 +414,7 @@ module ActiveSupport #:nodoc:
408
414
  next unless expanded_path.start_with?(expanded_root)
409
415
 
410
416
  root_size = expanded_root.size
411
- next if expanded_path[root_size] != ?/.freeze
417
+ next if expanded_path[root_size] != ?/
412
418
 
413
419
  nesting = expanded_path[(root_size + 1)..-1]
414
420
  paths << nesting.camelize unless nesting.blank?
@@ -420,7 +426,7 @@ module ActiveSupport #:nodoc:
420
426
 
421
427
  # Search for a file in autoload_paths matching the provided suffix.
422
428
  def search_for_file(path_suffix)
423
- path_suffix = path_suffix.sub(/(\.rb)?$/, ".rb".freeze)
429
+ path_suffix += ".rb" unless path_suffix.ends_with?(".rb")
424
430
 
425
431
  autoload_paths.each do |root|
426
432
  path = File.join(root, path_suffix)
@@ -454,6 +460,7 @@ module ActiveSupport #:nodoc:
454
460
  return nil unless base_path = autoloadable_module?(path_suffix)
455
461
  mod = Module.new
456
462
  into.const_set const_name, mod
463
+ log("constant #{qualified_name} autoloaded (module autovivified from #{File.join(base_path, path_suffix)})")
457
464
  autoloaded_constants << qualified_name unless autoload_once_paths.include?(base_path)
458
465
  autoloaded_constants.uniq!
459
466
  mod
@@ -495,26 +502,31 @@ module ActiveSupport #:nodoc:
495
502
  raise ArgumentError, "A copy of #{from_mod} has been removed from the module tree but is still active!"
496
503
  end
497
504
 
498
- qualified_name = qualified_name_for from_mod, const_name
505
+ qualified_name = qualified_name_for(from_mod, const_name)
499
506
  path_suffix = qualified_name.underscore
500
507
 
501
508
  file_path = search_for_file(path_suffix)
502
509
 
503
510
  if file_path
504
511
  expanded = File.expand_path(file_path)
505
- expanded.sub!(/\.rb\z/, "".freeze)
512
+ expanded.sub!(/\.rb\z/, "")
506
513
 
507
514
  if loading.include?(expanded)
508
515
  raise "Circular dependency detected while autoloading constant #{qualified_name}"
509
516
  else
510
517
  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)
518
+
519
+ if from_mod.const_defined?(const_name, false)
520
+ log("constant #{qualified_name} autoloaded from #{expanded}.rb")
521
+ return from_mod.const_get(const_name)
522
+ else
523
+ raise LoadError, "Unable to autoload constant #{qualified_name}, expected #{file_path} to define it"
524
+ end
513
525
  end
514
526
  elsif mod = autoload_module!(from_mod, const_name, qualified_name, path_suffix)
515
527
  return mod
516
- elsif (parent = from_mod.parent) && parent != from_mod &&
517
- ! from_mod.parents.any? { |p| p.const_defined?(const_name, false) }
528
+ elsif (parent = from_mod.module_parent) && parent != from_mod &&
529
+ ! from_mod.module_parents.any? { |p| p.const_defined?(const_name, false) }
518
530
  # If our parents do not have a constant named +const_name+ then we are free
519
531
  # to attempt to load upwards. If they do have such a constant, then this
520
532
  # const_missing must be due to from_mod::const_name, which should not
@@ -558,6 +570,7 @@ module ActiveSupport #:nodoc:
558
570
  # as the environment will be in an inconsistent state, e.g. other constants
559
571
  # may have already been unloaded and not accessible.
560
572
  def remove_unloadable_constants!
573
+ log("removing unloadable constants")
561
574
  autoloaded_constants.each { |const| remove_constant const }
562
575
  autoloaded_constants.clear
563
576
  Reference.clear!
@@ -747,6 +760,10 @@ module ActiveSupport #:nodoc:
747
760
  # The constant is no longer reachable, just skip it.
748
761
  end
749
762
  end
763
+
764
+ def log(message)
765
+ logger.debug("autoloading: #{message}") if logger && verbose
766
+ end
750
767
  end
751
768
  end
752
769
 
@@ -43,7 +43,7 @@ module ActiveSupport
43
43
  deprecation_horizon: deprecation_horizon)
44
44
  },
45
45
 
46
- silence: ->(message, callstack, deprecation_horizon, gem_name) {},
46
+ silence: ->(message, callstack, deprecation_horizon, gem_name) { },
47
47
  }
48
48
 
49
49
  # Behavior module allows to determine how to display deprecation messages.
@@ -1,6 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "active_support/core_ext/module/aliasing"
4
3
  require "active_support/core_ext/array/extract_options"
5
4
 
6
5
  module ActiveSupport
@@ -61,13 +60,13 @@ module ActiveSupport
61
60
  with_method = "#{aliased_method}_with_deprecation#{punctuation}"
62
61
  without_method = "#{aliased_method}_without_deprecation#{punctuation}"
63
62
 
64
- target_module.send(:define_method, with_method) do |*args, &block|
63
+ target_module.define_method(with_method) do |*args, &block|
65
64
  deprecator.deprecation_warning(method_name, options[method_name])
66
65
  send(without_method, *args, &block)
67
66
  end
68
67
 
69
- target_module.send(:alias_method, without_method, method_name)
70
- target_module.send(:alias_method, method_name, with_method)
68
+ target_module.alias_method(without_method, method_name)
69
+ target_module.alias_method(method_name, with_method)
71
70
 
72
71
  case
73
72
  when target_module.protected_method_defined?(without_method)
@@ -76,7 +75,7 @@ module ActiveSupport
76
75
  target_module.send(:private, method_name)
77
76
  end
78
77
  else
79
- mod.send(:define_method, method_name) do |*args, &block|
78
+ mod.define_method(method_name) do |*args, &block|
80
79
  deprecator.deprecation_warning(method_name, options[method_name])
81
80
  super(*args, &block)
82
81
  end
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "active_support/core_ext/regexp"
4
-
5
3
  module ActiveSupport
6
4
  class Deprecation
7
5
  class DeprecationProxy #:nodoc:
@@ -35,7 +35,7 @@ module ActiveSupport
35
35
  # and the second is a library name.
36
36
  #
37
37
  # ActiveSupport::Deprecation.new('2.0', 'MyLibrary')
38
- def initialize(deprecation_horizon = "6.0", gem_name = "Rails")
38
+ def initialize(deprecation_horizon = "6.1", gem_name = "Rails")
39
39
  self.gem_name = gem_name
40
40
  self.deprecation_horizon = deprecation_horizon
41
41
  # By default, warnings are not silenced and debugging is off.
@@ -38,12 +38,13 @@ module ActiveSupport
38
38
  end
39
39
 
40
40
  private
41
- def accumulate_descendants(klass, acc)
42
- if direct_descendants = @@direct_descendants[klass]
43
- acc.concat(direct_descendants)
44
- direct_descendants.each { |direct_descendant| accumulate_descendants(direct_descendant, acc) }
41
+
42
+ def accumulate_descendants(klass, acc)
43
+ if direct_descendants = @@direct_descendants[klass]
44
+ acc.concat(direct_descendants)
45
+ direct_descendants.each { |direct_descendant| accumulate_descendants(direct_descendant, acc) }
46
+ end
45
47
  end
46
- end
47
48
  end
48
49
 
49
50
  def inherited(base)
@@ -1,7 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "strscan"
4
- require "active_support/core_ext/regexp"
5
4
 
6
5
  module ActiveSupport
7
6
  class Duration
@@ -14,8 +13,8 @@ module ActiveSupport
14
13
  class ParsingError < ::ArgumentError; end
15
14
 
16
15
  PERIOD_OR_COMMA = /\.|,/
17
- PERIOD = ".".freeze
18
- COMMA = ",".freeze
16
+ PERIOD = "."
17
+ COMMA = ","
19
18
 
20
19
  SIGN_MARKER = /\A\-|\+|/
21
20
  DATE_MARKER = /P/
@@ -1,7 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "active_support/core_ext/object/blank"
4
- require "active_support/core_ext/hash/transform_values"
5
4
 
6
5
  module ActiveSupport
7
6
  class Duration
@@ -15,14 +14,14 @@ module ActiveSupport
15
14
  # Builds and returns output string.
16
15
  def serialize
17
16
  parts, sign = normalize
18
- return "PT0S".freeze if parts.empty?
17
+ return "PT0S" if parts.empty?
19
18
 
20
- output = "P".dup
19
+ output = +"P"
21
20
  output << "#{parts[:years]}Y" if parts.key?(:years)
22
21
  output << "#{parts[:months]}M" if parts.key?(:months)
23
22
  output << "#{parts[:weeks]}W" if parts.key?(:weeks)
24
23
  output << "#{parts[:days]}D" if parts.key?(:days)
25
- time = "".dup
24
+ time = +""
26
25
  time << "#{parts[:hours]}H" if parts.key?(:hours)
27
26
  time << "#{parts[:minutes]}M" if parts.key?(:minutes)
28
27
  if parts.key?(:seconds)
@@ -183,15 +183,15 @@ module ActiveSupport
183
183
  #
184
184
  def build(value)
185
185
  parts = {}
186
- remainder = value.round(9)
186
+ remainder = value.to_f
187
187
 
188
188
  PARTS.each do |part|
189
189
  unless part == :seconds
190
190
  part_in_seconds = PARTS_IN_SECONDS[part]
191
191
  parts[part] = remainder.div(part_in_seconds)
192
- remainder %= part_in_seconds
192
+ remainder = (remainder % part_in_seconds).round(9)
193
193
  end
194
- end unless value == 0
194
+ end
195
195
 
196
196
  parts[:seconds] = remainder
197
197
 
@@ -210,12 +210,15 @@ module ActiveSupport
210
210
  def initialize(value, parts) #:nodoc:
211
211
  @value, @parts = value, parts.to_h
212
212
  @parts.default = 0
213
- @parts.reject! { |k, v| v.zero? } unless value == 0
213
+ @parts.reject! { |k, v| v.zero? }
214
214
  end
215
215
 
216
216
  def coerce(other) #:nodoc:
217
- if Scalar === other
217
+ case other
218
+ when Scalar
218
219
  [other, self]
220
+ when Duration
221
+ [Scalar.new(other.value), self]
219
222
  else
220
223
  [Scalar.new(other), self]
221
224
  end
@@ -373,7 +376,6 @@ module ActiveSupport
373
376
  return "0 seconds" if parts.empty?
374
377
 
375
378
  parts.
376
- reduce(::Hash.new(0)) { |h, (l, r)| h[l] += r; h }.
377
379
  sort_by { |unit, _ | PARTS.index(unit) }.
378
380
  map { |unit, val| "#{val} #{val == 1 ? unit.to_s.chop : unit.to_s}" }.
379
381
  to_sentence(locale: ::I18n.default_locale)
@@ -400,14 +402,8 @@ module ActiveSupport
400
402
  private
401
403
 
402
404
  def sum(sign, time = ::Time.current)
403
- unless time.acts_like?(:time) || time.acts_like?(:date)
404
- raise ::ArgumentError, "expected a time or date, got #{time.inspect}"
405
- end
406
-
407
- if parts.empty?
408
- time.since(sign * value)
409
- else
410
- parts.inject(time) do |t, (type, number)|
405
+ parts.inject(time) do |t, (type, number)|
406
+ if t.acts_like?(:time) || t.acts_like?(:date)
411
407
  if type == :seconds
412
408
  t.since(sign * number)
413
409
  elsif type == :minutes
@@ -417,6 +413,8 @@ module ActiveSupport
417
413
  else
418
414
  t.advance(type => sign * number)
419
415
  end
416
+ else
417
+ raise ::ArgumentError, "expected a time or date, got #{time.inspect}"
420
418
  end
421
419
  end
422
420
  end
@@ -38,10 +38,6 @@ module ActiveSupport
38
38
  @options ||= ActiveSupport::InheritableOptions.new(config)
39
39
  end
40
40
 
41
- def serialize(config)
42
- config.present? ? YAML.dump(config) : ""
43
- end
44
-
45
41
  def deserialize(config)
46
42
  YAML.load(config).presence || {}
47
43
  end
@@ -52,16 +52,17 @@ module ActiveSupport
52
52
  @pid = Process.pid
53
53
  @boot_mutex = Mutex.new
54
54
 
55
- if (@dtw = directories_to_watch).any?
55
+ dtw = directories_to_watch
56
+ @dtw, @missing = dtw.partition(&:exist?)
57
+
58
+ if @dtw.any?
56
59
  # Loading listen triggers warnings. These are originated by a legit
57
60
  # usage of attr_* macros for private attributes, but adds a lot of noise
58
61
  # to our test suite. Thus, we lazy load it and disable warnings locally.
59
62
  silence_warnings do
60
- begin
61
- require "listen"
62
- rescue LoadError => e
63
- raise LoadError, "Could not load the 'listen' gem. Add `gem 'listen'` to the development group of your Gemfile", e.backtrace
64
- end
63
+ require "listen"
64
+ rescue LoadError => e
65
+ raise LoadError, "Could not load the 'listen' gem. Add `gem 'listen'` to the development group of your Gemfile", e.backtrace
65
66
  end
66
67
  end
67
68
  boot!
@@ -75,6 +76,19 @@ module ActiveSupport
75
76
  @updated.make_true
76
77
  end
77
78
  end
79
+
80
+ if @missing.any?(&:exist?)
81
+ @boot_mutex.synchronize do
82
+ appeared, @missing = @missing.partition(&:exist?)
83
+ shutdown!
84
+
85
+ @dtw += appeared
86
+ boot!
87
+
88
+ @updated.make_true
89
+ end
90
+ end
91
+
78
92
  @updated.true?
79
93
  end
80
94
 
@@ -96,6 +110,10 @@ module ActiveSupport
96
110
  Listen.to(*@dtw, &method(:changed)).start
97
111
  end
98
112
 
113
+ def shutdown!
114
+ Listen.stop
115
+ end
116
+
99
117
  def changed(modified, added, removed)
100
118
  unless updated?
101
119
  @updated.make_true if (modified + added + removed).any? { |f| watching?(f) }
@@ -123,7 +141,7 @@ module ActiveSupport
123
141
  end
124
142
 
125
143
  def directories_to_watch
126
- dtw = (@files + @dirs.keys).map { |f| @ph.existing_parent(f) }
144
+ dtw = @files.map(&:dirname) + @dirs.keys
127
145
  dtw.compact!
128
146
  dtw.uniq!
129
147