activesupport 5.2.7.1 → 6.1.4.6

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 (187) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +399 -434
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +4 -3
  5. data/lib/active_support/actionable_error.rb +48 -0
  6. data/lib/active_support/array_inquirer.rb +4 -2
  7. data/lib/active_support/backtrace_cleaner.rb +29 -3
  8. data/lib/active_support/benchmarkable.rb +1 -1
  9. data/lib/active_support/cache/file_store.rb +34 -34
  10. data/lib/active_support/cache/mem_cache_store.rb +39 -24
  11. data/lib/active_support/cache/memory_store.rb +59 -33
  12. data/lib/active_support/cache/null_store.rb +8 -3
  13. data/lib/active_support/cache/redis_cache_store.rb +72 -45
  14. data/lib/active_support/cache/strategy/local_cache.rb +41 -26
  15. data/lib/active_support/cache.rb +148 -78
  16. data/lib/active_support/callbacks.rb +81 -64
  17. data/lib/active_support/concern.rb +70 -3
  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 +10 -14
  21. data/lib/active_support/configuration_file.rb +51 -0
  22. data/lib/active_support/core_ext/array/access.rb +18 -6
  23. data/lib/active_support/core_ext/array/conversions.rb +5 -5
  24. data/lib/active_support/core_ext/array/extract.rb +21 -0
  25. data/lib/active_support/core_ext/array.rb +1 -1
  26. data/lib/active_support/core_ext/benchmark.rb +2 -2
  27. data/lib/active_support/core_ext/class/attribute.rb +32 -47
  28. data/lib/active_support/core_ext/class/subclasses.rb +17 -38
  29. data/lib/active_support/core_ext/date/calculations.rb +6 -5
  30. data/lib/active_support/core_ext/date/conversions.rb +2 -1
  31. data/lib/active_support/core_ext/date_and_time/calculations.rb +37 -47
  32. data/lib/active_support/core_ext/date_and_time/compatibility.rb +15 -0
  33. data/lib/active_support/core_ext/date_and_time/zones.rb +0 -1
  34. data/lib/active_support/core_ext/date_time/calculations.rb +1 -1
  35. data/lib/active_support/core_ext/date_time/conversions.rb +0 -1
  36. data/lib/active_support/core_ext/enumerable.rb +171 -75
  37. data/lib/active_support/core_ext/hash/conversions.rb +3 -3
  38. data/lib/active_support/core_ext/hash/deep_transform_values.rb +46 -0
  39. data/lib/active_support/core_ext/hash/except.rb +2 -2
  40. data/lib/active_support/core_ext/hash/keys.rb +1 -30
  41. data/lib/active_support/core_ext/hash/slice.rb +6 -27
  42. data/lib/active_support/core_ext/hash.rb +1 -2
  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/marshal.rb +2 -0
  47. data/lib/active_support/core_ext/module/attr_internal.rb +2 -2
  48. data/lib/active_support/core_ext/module/attribute_accessors.rb +30 -39
  49. data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +17 -19
  50. data/lib/active_support/core_ext/module/concerning.rb +8 -2
  51. data/lib/active_support/core_ext/module/delegation.rb +76 -33
  52. data/lib/active_support/core_ext/module/introspection.rb +16 -15
  53. data/lib/active_support/core_ext/module/redefine_method.rb +8 -17
  54. data/lib/active_support/core_ext/module.rb +0 -1
  55. data/lib/active_support/core_ext/name_error.rb +29 -2
  56. data/lib/active_support/core_ext/numeric/conversions.rb +129 -129
  57. data/lib/active_support/core_ext/numeric.rb +0 -1
  58. data/lib/active_support/core_ext/object/blank.rb +1 -2
  59. data/lib/active_support/core_ext/object/deep_dup.rb +1 -1
  60. data/lib/active_support/core_ext/object/duplicable.rb +7 -114
  61. data/lib/active_support/core_ext/object/json.rb +14 -2
  62. data/lib/active_support/core_ext/object/try.rb +17 -7
  63. data/lib/active_support/core_ext/object/with_options.rb +1 -1
  64. data/lib/active_support/core_ext/range/compare_range.rb +34 -13
  65. data/lib/active_support/core_ext/range/conversions.rb +31 -29
  66. data/lib/active_support/core_ext/range/each.rb +0 -1
  67. data/lib/active_support/core_ext/range/include_time_with_zone.rb +8 -3
  68. data/lib/active_support/core_ext/regexp.rb +8 -5
  69. data/lib/active_support/core_ext/securerandom.rb +23 -3
  70. data/lib/active_support/core_ext/string/access.rb +5 -16
  71. data/lib/active_support/core_ext/string/conversions.rb +1 -0
  72. data/lib/active_support/core_ext/string/filters.rb +42 -1
  73. data/lib/active_support/core_ext/string/inflections.rb +45 -6
  74. data/lib/active_support/core_ext/string/inquiry.rb +1 -0
  75. data/lib/active_support/core_ext/string/multibyte.rb +6 -5
  76. data/lib/active_support/core_ext/string/output_safety.rb +70 -41
  77. data/lib/active_support/core_ext/string/starts_ends_with.rb +2 -2
  78. data/lib/active_support/core_ext/string/strip.rb +3 -1
  79. data/lib/active_support/core_ext/symbol/starts_ends_with.rb +14 -0
  80. data/lib/active_support/core_ext/symbol.rb +3 -0
  81. data/lib/active_support/core_ext/time/calculations.rb +51 -3
  82. data/lib/active_support/core_ext/time/conversions.rb +2 -0
  83. data/lib/active_support/core_ext/uri.rb +6 -1
  84. data/lib/active_support/core_ext.rb +1 -1
  85. data/lib/active_support/current_attributes/test_helper.rb +13 -0
  86. data/lib/active_support/current_attributes.rb +16 -2
  87. data/lib/active_support/dependencies/zeitwerk_integration.rb +117 -0
  88. data/lib/active_support/dependencies.rb +109 -34
  89. data/lib/active_support/deprecation/behaviors.rb +16 -3
  90. data/lib/active_support/deprecation/disallowed.rb +56 -0
  91. data/lib/active_support/deprecation/instance_delegator.rb +0 -1
  92. data/lib/active_support/deprecation/method_wrappers.rb +18 -23
  93. data/lib/active_support/deprecation/proxy_wrappers.rb +29 -6
  94. data/lib/active_support/deprecation/reporting.rb +50 -7
  95. data/lib/active_support/deprecation.rb +6 -1
  96. data/lib/active_support/descendants_tracker.rb +59 -9
  97. data/lib/active_support/duration/iso8601_parser.rb +2 -4
  98. data/lib/active_support/duration/iso8601_serializer.rb +18 -14
  99. data/lib/active_support/duration.rb +78 -30
  100. data/lib/active_support/encrypted_configuration.rb +0 -4
  101. data/lib/active_support/encrypted_file.rb +22 -4
  102. data/lib/active_support/environment_inquirer.rb +20 -0
  103. data/lib/active_support/evented_file_update_checker.rb +82 -117
  104. data/lib/active_support/execution_wrapper.rb +2 -1
  105. data/lib/active_support/file_update_checker.rb +0 -1
  106. data/lib/active_support/fork_tracker.rb +64 -0
  107. data/lib/active_support/gem_version.rb +4 -4
  108. data/lib/active_support/hash_with_indifferent_access.rb +70 -42
  109. data/lib/active_support/i18n.rb +1 -0
  110. data/lib/active_support/i18n_railtie.rb +15 -8
  111. data/lib/active_support/inflector/inflections.rb +2 -7
  112. data/lib/active_support/inflector/methods.rb +49 -58
  113. data/lib/active_support/inflector/transliterate.rb +47 -18
  114. data/lib/active_support/json/decoding.rb +25 -26
  115. data/lib/active_support/json/encoding.rb +11 -3
  116. data/lib/active_support/key_generator.rb +1 -33
  117. data/lib/active_support/lazy_load_hooks.rb +5 -2
  118. data/lib/active_support/locale/en.rb +33 -0
  119. data/lib/active_support/locale/en.yml +7 -3
  120. data/lib/active_support/log_subscriber.rb +39 -9
  121. data/lib/active_support/logger.rb +2 -17
  122. data/lib/active_support/logger_silence.rb +11 -19
  123. data/lib/active_support/logger_thread_safe_level.rb +50 -6
  124. data/lib/active_support/message_encryptor.rb +8 -13
  125. data/lib/active_support/message_verifier.rb +10 -10
  126. data/lib/active_support/messages/metadata.rb +11 -2
  127. data/lib/active_support/messages/rotation_configuration.rb +2 -1
  128. data/lib/active_support/messages/rotator.rb +10 -9
  129. data/lib/active_support/multibyte/chars.rb +10 -68
  130. data/lib/active_support/multibyte/unicode.rb +15 -327
  131. data/lib/active_support/notifications/fanout.rb +116 -16
  132. data/lib/active_support/notifications/instrumenter.rb +71 -9
  133. data/lib/active_support/notifications.rb +72 -8
  134. data/lib/active_support/number_helper/number_converter.rb +5 -6
  135. data/lib/active_support/number_helper/number_to_currency_converter.rb +4 -9
  136. data/lib/active_support/number_helper/number_to_delimited_converter.rb +3 -2
  137. data/lib/active_support/number_helper/number_to_human_converter.rb +4 -3
  138. data/lib/active_support/number_helper/number_to_human_size_converter.rb +4 -3
  139. data/lib/active_support/number_helper/number_to_percentage_converter.rb +3 -1
  140. data/lib/active_support/number_helper/number_to_phone_converter.rb +2 -1
  141. data/lib/active_support/number_helper/number_to_rounded_converter.rb +12 -7
  142. data/lib/active_support/number_helper/rounding_helper.rb +12 -28
  143. data/lib/active_support/number_helper.rb +38 -12
  144. data/lib/active_support/option_merger.rb +22 -3
  145. data/lib/active_support/ordered_hash.rb +1 -1
  146. data/lib/active_support/ordered_options.rb +13 -3
  147. data/lib/active_support/parameter_filter.rb +133 -0
  148. data/lib/active_support/per_thread_registry.rb +1 -1
  149. data/lib/active_support/rails.rb +1 -10
  150. data/lib/active_support/railtie.rb +23 -1
  151. data/lib/active_support/reloader.rb +4 -5
  152. data/lib/active_support/rescuable.rb +4 -4
  153. data/lib/active_support/secure_compare_rotator.rb +51 -0
  154. data/lib/active_support/security_utils.rb +19 -12
  155. data/lib/active_support/string_inquirer.rb +4 -3
  156. data/lib/active_support/subscriber.rb +72 -28
  157. data/lib/active_support/tagged_logging.rb +42 -8
  158. data/lib/active_support/test_case.rb +91 -0
  159. data/lib/active_support/testing/assertions.rb +30 -9
  160. data/lib/active_support/testing/deprecation.rb +0 -1
  161. data/lib/active_support/testing/file_fixtures.rb +2 -0
  162. data/lib/active_support/testing/isolation.rb +2 -2
  163. data/lib/active_support/testing/method_call_assertions.rb +28 -1
  164. data/lib/active_support/testing/parallelization/server.rb +78 -0
  165. data/lib/active_support/testing/parallelization/worker.rb +100 -0
  166. data/lib/active_support/testing/parallelization.rb +51 -0
  167. data/lib/active_support/testing/stream.rb +1 -2
  168. data/lib/active_support/testing/time_helpers.rb +47 -12
  169. data/lib/active_support/time_with_zone.rb +81 -47
  170. data/lib/active_support/values/time_zone.rb +32 -17
  171. data/lib/active_support/xml_mini/jdom.rb +2 -3
  172. data/lib/active_support/xml_mini/libxml.rb +2 -2
  173. data/lib/active_support/xml_mini/libxmlsax.rb +4 -4
  174. data/lib/active_support/xml_mini/nokogiri.rb +2 -2
  175. data/lib/active_support/xml_mini/nokogirisax.rb +3 -3
  176. data/lib/active_support/xml_mini/rexml.rb +10 -3
  177. data/lib/active_support/xml_mini.rb +2 -10
  178. data/lib/active_support.rb +14 -1
  179. metadata +55 -29
  180. data/lib/active_support/core_ext/array/prepend_and_append.rb +0 -9
  181. data/lib/active_support/core_ext/hash/compact.rb +0 -29
  182. data/lib/active_support/core_ext/hash/transform_values.rb +0 -32
  183. data/lib/active_support/core_ext/kernel/agnostics.rb +0 -13
  184. data/lib/active_support/core_ext/module/reachable.rb +0 -11
  185. data/lib/active_support/core_ext/numeric/inquiry.rb +0 -28
  186. data/lib/active_support/core_ext/range/include_range.rb +0 -3
  187. data/lib/active_support/values/unicode_tables.dat +0 -0
@@ -4,10 +4,7 @@ require "active_support/concern"
4
4
  require "active_support/descendants_tracker"
5
5
  require "active_support/core_ext/array/extract_options"
6
6
  require "active_support/core_ext/class/attribute"
7
- require "active_support/core_ext/kernel/reporting"
8
- require "active_support/core_ext/kernel/singleton_class"
9
7
  require "active_support/core_ext/string/filters"
10
- require "active_support/deprecation"
11
8
  require "thread"
12
9
 
13
10
  module ActiveSupport
@@ -23,6 +20,9 @@ module ActiveSupport
23
20
  # +ClassMethods.set_callback+), and run the installed callbacks at the
24
21
  # appropriate times (via +run_callbacks+).
25
22
  #
23
+ # By default callbacks are halted by throwing +:abort+.
24
+ # See +ClassMethods.define_callbacks+ for details.
25
+ #
26
26
  # Three kinds of callbacks are supported: before callbacks, run before a
27
27
  # certain event; after callbacks, run after the event; and around callbacks,
28
28
  # blocks that surround the event, triggering it when they yield. Callback code
@@ -100,32 +100,6 @@ module ActiveSupport
100
100
  env = Filters::Environment.new(self, false, nil)
101
101
  next_sequence = callbacks.compile
102
102
 
103
- invoke_sequence = Proc.new do
104
- skipped = nil
105
- while true
106
- current = next_sequence
107
- current.invoke_before(env)
108
- if current.final?
109
- env.value = !env.halted && (!block_given? || yield)
110
- elsif current.skip?(env)
111
- (skipped ||= []) << current
112
- next_sequence = next_sequence.nested
113
- next
114
- else
115
- next_sequence = next_sequence.nested
116
- begin
117
- target, block, method, *arguments = current.expand_call_template(env, invoke_sequence)
118
- target.send(method, *arguments, &block)
119
- ensure
120
- next_sequence = current
121
- end
122
- end
123
- current.invoke_after(env)
124
- skipped.pop.invoke_after(env) while skipped && skipped.first
125
- break env.value
126
- end
127
- end
128
-
129
103
  # Common case: no 'around' callbacks defined
130
104
  if next_sequence.final?
131
105
  next_sequence.invoke_before(env)
@@ -133,17 +107,43 @@ module ActiveSupport
133
107
  next_sequence.invoke_after(env)
134
108
  env.value
135
109
  else
110
+ invoke_sequence = Proc.new do
111
+ skipped = nil
112
+
113
+ while true
114
+ current = next_sequence
115
+ current.invoke_before(env)
116
+ if current.final?
117
+ env.value = !env.halted && (!block_given? || yield)
118
+ elsif current.skip?(env)
119
+ (skipped ||= []) << current
120
+ next_sequence = next_sequence.nested
121
+ next
122
+ else
123
+ next_sequence = next_sequence.nested
124
+ begin
125
+ target, block, method, *arguments = current.expand_call_template(env, invoke_sequence)
126
+ target.send(method, *arguments, &block)
127
+ ensure
128
+ next_sequence = current
129
+ end
130
+ end
131
+ current.invoke_after(env)
132
+ skipped.pop.invoke_after(env) while skipped&.first
133
+ break env.value
134
+ end
135
+ end
136
+
136
137
  invoke_sequence.call
137
138
  end
138
139
  end
139
140
  end
140
141
 
141
142
  private
142
-
143
143
  # A hook invoked every time a before callback is halted.
144
144
  # This can be overridden in ActiveSupport::Callbacks implementors in order
145
145
  # to provide better debugging/logging.
146
- def halted_callback_hook(filter)
146
+ def halted_callback_hook(filter, name)
147
147
  end
148
148
 
149
149
  module Conditionals # :nodoc:
@@ -159,17 +159,17 @@ module ActiveSupport
159
159
  Environment = Struct.new(:target, :halted, :value)
160
160
 
161
161
  class Before
162
- def self.build(callback_sequence, user_callback, user_conditions, chain_config, filter)
162
+ def self.build(callback_sequence, user_callback, user_conditions, chain_config, filter, name)
163
163
  halted_lambda = chain_config[:terminator]
164
164
 
165
165
  if user_conditions.any?
166
- halting_and_conditional(callback_sequence, user_callback, user_conditions, halted_lambda, filter)
166
+ halting_and_conditional(callback_sequence, user_callback, user_conditions, halted_lambda, filter, name)
167
167
  else
168
- halting(callback_sequence, user_callback, halted_lambda, filter)
168
+ halting(callback_sequence, user_callback, halted_lambda, filter, name)
169
169
  end
170
170
  end
171
171
 
172
- def self.halting_and_conditional(callback_sequence, user_callback, user_conditions, halted_lambda, filter)
172
+ def self.halting_and_conditional(callback_sequence, user_callback, user_conditions, halted_lambda, filter, name)
173
173
  callback_sequence.before do |env|
174
174
  target = env.target
175
175
  value = env.value
@@ -179,7 +179,7 @@ module ActiveSupport
179
179
  result_lambda = -> { user_callback.call target, value }
180
180
  env.halted = halted_lambda.call(target, result_lambda)
181
181
  if env.halted
182
- target.send :halted_callback_hook, filter
182
+ target.send :halted_callback_hook, filter, name
183
183
  end
184
184
  end
185
185
 
@@ -188,7 +188,7 @@ module ActiveSupport
188
188
  end
189
189
  private_class_method :halting_and_conditional
190
190
 
191
- def self.halting(callback_sequence, user_callback, halted_lambda, filter)
191
+ def self.halting(callback_sequence, user_callback, halted_lambda, filter, name)
192
192
  callback_sequence.before do |env|
193
193
  target = env.target
194
194
  value = env.value
@@ -197,9 +197,8 @@ module ActiveSupport
197
197
  unless halted
198
198
  result_lambda = -> { user_callback.call target, value }
199
199
  env.halted = halted_lambda.call(target, result_lambda)
200
-
201
200
  if env.halted
202
- target.send :halted_callback_hook, filter
201
+ target.send :halted_callback_hook, filter, name
203
202
  end
204
203
  end
205
204
 
@@ -298,8 +297,8 @@ module ActiveSupport
298
297
  @kind = kind
299
298
  @filter = filter
300
299
  @key = compute_identifier filter
301
- @if = check_conditionals(Array(options[:if]))
302
- @unless = check_conditionals(Array(options[:unless]))
300
+ @if = check_conditionals(options[:if])
301
+ @unless = check_conditionals(options[:unless])
303
302
  end
304
303
 
305
304
  def filter; @key; end
@@ -337,7 +336,7 @@ module ActiveSupport
337
336
 
338
337
  case kind
339
338
  when :before
340
- Filters::Before.build(callback_sequence, user_callback.make_lambda, user_conditions, chain_config, @filter)
339
+ Filters::Before.build(callback_sequence, user_callback.make_lambda, user_conditions, chain_config, @filter, name)
341
340
  when :after
342
341
  Filters::After.build(callback_sequence, user_callback.make_lambda, user_conditions, chain_config)
343
342
  when :around
@@ -350,7 +349,13 @@ module ActiveSupport
350
349
  end
351
350
 
352
351
  private
352
+ EMPTY_ARRAY = [].freeze
353
+ private_constant :EMPTY_ARRAY
354
+
353
355
  def check_conditionals(conditionals)
356
+ return EMPTY_ARRAY if conditionals.blank?
357
+
358
+ conditionals = Array(conditionals)
354
359
  if conditionals.any? { |c| c.is_a?(String) }
355
360
  raise ArgumentError, <<-MSG.squish
356
361
  Passing string to be evaluated in :if and :unless conditional
@@ -359,7 +364,7 @@ module ActiveSupport
359
364
  MSG
360
365
  end
361
366
 
362
- conditionals
367
+ conditionals.freeze
363
368
  end
364
369
 
365
370
  def compute_identifier(filter)
@@ -401,21 +406,17 @@ module ActiveSupport
401
406
  # The actual invocation is left up to the caller to minimize
402
407
  # call stack pollution.
403
408
  def expand(target, value, block)
404
- result = @arguments.map { |arg|
409
+ expanded = [@override_target || target, @override_block || block, @method_name]
410
+
411
+ @arguments.each do |arg|
405
412
  case arg
406
- when :value; value
407
- when :target; target
408
- when :block; block || raise(ArgumentError)
413
+ when :value then expanded << value
414
+ when :target then expanded << target
415
+ when :block then expanded << (block || raise(ArgumentError))
409
416
  end
410
- }
411
-
412
- result.unshift @method_name
413
- result.unshift @override_block || block
414
- result.unshift @override_target || target
417
+ end
415
418
 
416
- # target, block, method, *arguments = result
417
- # target.send(method, *arguments, &block)
418
- result
419
+ expanded
419
420
  end
420
421
 
421
422
  # Return a lambda that will make this call when given the input
@@ -497,9 +498,7 @@ module ActiveSupport
497
498
  arg.halted || !@user_conditions.all? { |c| c.call(arg.target, arg.value) }
498
499
  end
499
500
 
500
- def nested
501
- @nested
502
- end
501
+ attr_reader :nested
503
502
 
504
503
  def final?
505
504
  !@call_template
@@ -578,10 +577,9 @@ module ActiveSupport
578
577
  end
579
578
 
580
579
  protected
581
- def chain; @chain; end
580
+ attr_reader :chain
582
581
 
583
582
  private
584
-
585
583
  def append_one(callback)
586
584
  @callbacks = nil
587
585
  remove_duplicates(callback)
@@ -659,9 +657,17 @@ module ActiveSupport
659
657
  # * <tt>:if</tt> - A symbol or an array of symbols, each naming an instance
660
658
  # method or a proc; the callback will be called only when they all return
661
659
  # a true value.
660
+ #
661
+ # If a proc is given, its body is evaluated in the context of the
662
+ # current object. It can also optionally accept the current object as
663
+ # an argument.
662
664
  # * <tt>:unless</tt> - A symbol or an array of symbols, each naming an
663
665
  # instance method or a proc; the callback will be called only when they
664
666
  # all return a false value.
667
+ #
668
+ # If a proc is given, its body is evaluated in the context of the
669
+ # current object. It can also optionally accept the current object as
670
+ # an argument.
665
671
  # * <tt>:prepend</tt> - If +true+, the callback will be prepended to the
666
672
  # existing chain rather than appended.
667
673
  def set_callback(name, *filter_list, &block)
@@ -809,7 +815,9 @@ module ActiveSupport
809
815
  names.each do |name|
810
816
  name = name.to_sym
811
817
 
812
- set_callbacks name, CallbackChain.new(name, options)
818
+ ([self] + ActiveSupport::DescendantsTracker.descendants(self)).each do |target|
819
+ target.set_callbacks name, CallbackChain.new(name, options)
820
+ end
813
821
 
814
822
  module_eval <<-RUBY, __FILE__, __LINE__ + 1
815
823
  def _run_#{name}_callbacks(&block)
@@ -832,13 +840,22 @@ module ActiveSupport
832
840
  end
833
841
 
834
842
  protected
835
-
836
843
  def get_callbacks(name) # :nodoc:
837
844
  __callbacks[name.to_sym]
838
845
  end
839
846
 
840
- def set_callbacks(name, callbacks) # :nodoc:
841
- self.__callbacks = __callbacks.merge(name.to_sym => callbacks)
847
+ if Module.instance_method(:method_defined?).arity == 1 # Ruby 2.5 and older
848
+ def set_callbacks(name, callbacks) # :nodoc:
849
+ self.__callbacks = __callbacks.merge(name.to_sym => callbacks)
850
+ end
851
+ else # Ruby 2.6 and newer
852
+ def set_callbacks(name, callbacks) # :nodoc:
853
+ unless singleton_class.method_defined?(:__callbacks, false)
854
+ self.__callbacks = __callbacks.dup
855
+ end
856
+ self.__callbacks[name.to_sym] = callbacks
857
+ self.__callbacks
858
+ end
842
859
  end
843
860
  end
844
861
  end
@@ -19,7 +19,7 @@ module ActiveSupport
19
19
  # By using <tt>ActiveSupport::Concern</tt> the above module could instead be
20
20
  # written as:
21
21
  #
22
- # require 'active_support/concern'
22
+ # require "active_support/concern"
23
23
  #
24
24
  # module M
25
25
  # extend ActiveSupport::Concern
@@ -76,7 +76,7 @@ module ActiveSupport
76
76
  # is the +Bar+ module, not the +Host+ class. With <tt>ActiveSupport::Concern</tt>,
77
77
  # module dependencies are properly resolved:
78
78
  #
79
- # require 'active_support/concern'
79
+ # require "active_support/concern"
80
80
  #
81
81
  # module Foo
82
82
  # extend ActiveSupport::Concern
@@ -99,6 +99,14 @@ module ActiveSupport
99
99
  # class Host
100
100
  # include Bar # It works, now Bar takes care of its dependencies
101
101
  # end
102
+ #
103
+ # === Prepending concerns
104
+ #
105
+ # Just like <tt>include</tt>, concerns also support <tt>prepend</tt> with a corresponding
106
+ # <tt>prepended do</tt> callback. <tt>module ClassMethods</tt> or <tt>class_methods do</tt> are
107
+ # prepended as well.
108
+ #
109
+ # <tt>prepend</tt> is also used for any dependencies.
102
110
  module Concern
103
111
  class MultipleIncludedBlocks < StandardError #:nodoc:
104
112
  def initialize
@@ -106,11 +114,17 @@ module ActiveSupport
106
114
  end
107
115
  end
108
116
 
117
+ class MultiplePrependBlocks < StandardError #:nodoc:
118
+ def initialize
119
+ super "Cannot define multiple 'prepended' blocks for a Concern"
120
+ end
121
+ end
122
+
109
123
  def self.extended(base) #:nodoc:
110
124
  base.instance_variable_set(:@_dependencies, [])
111
125
  end
112
126
 
113
- def append_features(base)
127
+ def append_features(base) #:nodoc:
114
128
  if base.instance_variable_defined?(:@_dependencies)
115
129
  base.instance_variable_get(:@_dependencies) << self
116
130
  false
@@ -123,6 +137,22 @@ module ActiveSupport
123
137
  end
124
138
  end
125
139
 
140
+ def prepend_features(base) #:nodoc:
141
+ if base.instance_variable_defined?(:@_dependencies)
142
+ base.instance_variable_get(:@_dependencies).unshift self
143
+ false
144
+ else
145
+ return false if base < self
146
+ @_dependencies.each { |dep| base.prepend(dep) }
147
+ super
148
+ base.singleton_class.prepend const_get(:ClassMethods) if const_defined?(:ClassMethods)
149
+ base.class_eval(&@_prepended_block) if instance_variable_defined?(:@_prepended_block)
150
+ end
151
+ end
152
+
153
+ # Evaluate given block in context of base class,
154
+ # so that you can write class macros here.
155
+ # When you define more than one +included+ block, it raises an exception.
126
156
  def included(base = nil, &block)
127
157
  if base.nil?
128
158
  if instance_variable_defined?(:@_included_block)
@@ -137,6 +167,43 @@ module ActiveSupport
137
167
  end
138
168
  end
139
169
 
170
+ # Evaluate given block in context of base class,
171
+ # so that you can write class macros here.
172
+ # When you define more than one +prepended+ block, it raises an exception.
173
+ def prepended(base = nil, &block)
174
+ if base.nil?
175
+ if instance_variable_defined?(:@_prepended_block)
176
+ if @_prepended_block.source_location != block.source_location
177
+ raise MultiplePrependBlocks
178
+ end
179
+ else
180
+ @_prepended_block = block
181
+ end
182
+ else
183
+ super
184
+ end
185
+ end
186
+
187
+ # Define class methods from given block.
188
+ # You can define private class methods as well.
189
+ #
190
+ # module Example
191
+ # extend ActiveSupport::Concern
192
+ #
193
+ # class_methods do
194
+ # def foo; puts 'foo'; end
195
+ #
196
+ # private
197
+ # def bar; puts 'bar'; end
198
+ # end
199
+ # end
200
+ #
201
+ # class Buzz
202
+ # include Example
203
+ # end
204
+ #
205
+ # Buzz.foo # => "foo"
206
+ # Buzz.bar # => private method 'bar' called for Buzz:Class(NoMethodError)
140
207
  def class_methods(&class_methods_module_definition)
141
208
  mod = const_defined?(:ClassMethods, false) ?
142
209
  const_get(:ClassMethods) :
@@ -7,11 +7,29 @@ module ActiveSupport
7
7
  # A monitor that will permit dependency loading while blocked waiting for
8
8
  # the lock.
9
9
  class LoadInterlockAwareMonitor < Monitor
10
+ EXCEPTION_NEVER = { Exception => :never }.freeze
11
+ EXCEPTION_IMMEDIATE = { Exception => :immediate }.freeze
12
+ private_constant :EXCEPTION_NEVER, :EXCEPTION_IMMEDIATE
13
+
10
14
  # Enters an exclusive section, but allows dependency loading while blocked
11
15
  def mon_enter
12
16
  mon_try_enter ||
13
17
  ActiveSupport::Dependencies.interlock.permit_concurrent_loads { super }
14
18
  end
19
+
20
+ def synchronize
21
+ Thread.handle_interrupt(EXCEPTION_NEVER) do
22
+ mon_enter
23
+
24
+ begin
25
+ Thread.handle_interrupt(EXCEPTION_IMMEDIATE) do
26
+ yield
27
+ end
28
+ ensure
29
+ mon_exit
30
+ end
31
+ end
32
+ end
15
33
  end
16
34
  end
17
35
  end
@@ -200,7 +200,6 @@ module ActiveSupport
200
200
  end
201
201
 
202
202
  private
203
-
204
203
  # Must be called within synchronize
205
204
  def busy_for_exclusive?(purpose)
206
205
  busy_for_sharing?(purpose) ||
@@ -2,12 +2,10 @@
2
2
 
3
3
  require "active_support/concern"
4
4
  require "active_support/ordered_options"
5
- require "active_support/core_ext/array/extract_options"
6
- require "active_support/core_ext/regexp"
7
5
 
8
6
  module ActiveSupport
9
7
  # Configurable provides a <tt>config</tt> method to store and retrieve
10
- # configuration options as an <tt>OrderedHash</tt>.
8
+ # configuration options as an <tt>OrderedOptions</tt>.
11
9
  module Configurable
12
10
  extend ActiveSupport::Concern
13
11
 
@@ -69,8 +67,8 @@ module ActiveSupport
69
67
  # end
70
68
  # # => NameError: invalid config attribute name
71
69
  #
72
- # To opt out of the instance writer method, pass <tt>instance_writer: false</tt>.
73
- # To opt out of the instance reader method, pass <tt>instance_reader: false</tt>.
70
+ # To omit the instance writer method, pass <tt>instance_writer: false</tt>.
71
+ # To omit the instance reader method, pass <tt>instance_reader: false</tt>.
74
72
  #
75
73
  # class User
76
74
  # include ActiveSupport::Configurable
@@ -83,7 +81,7 @@ module ActiveSupport
83
81
  # User.new.allowed_access = true # => NoMethodError
84
82
  # User.new.allowed_access # => NoMethodError
85
83
  #
86
- # Or pass <tt>instance_accessor: false</tt>, to opt out both instance methods.
84
+ # Or pass <tt>instance_accessor: false</tt>, to omit both instance methods.
87
85
  #
88
86
  # class User
89
87
  # include ActiveSupport::Configurable
@@ -106,9 +104,7 @@ module ActiveSupport
106
104
  # end
107
105
  #
108
106
  # User.hair_colors # => [:brown, :black, :blonde, :red]
109
- def config_accessor(*names)
110
- options = names.extract_options!
111
-
107
+ def config_accessor(*names, instance_reader: true, instance_writer: true, instance_accessor: true) # :doc:
112
108
  names.each do |name|
113
109
  raise NameError.new("invalid config attribute name") unless /\A[_A-Za-z]\w*\z/.match?(name)
114
110
 
@@ -118,9 +114,9 @@ module ActiveSupport
118
114
  singleton_class.class_eval reader, __FILE__, reader_line
119
115
  singleton_class.class_eval writer, __FILE__, writer_line
120
116
 
121
- unless options[:instance_accessor] == false
122
- class_eval reader, __FILE__, reader_line unless options[:instance_reader] == false
123
- class_eval writer, __FILE__, writer_line unless options[:instance_writer] == false
117
+ if instance_accessor
118
+ class_eval reader, __FILE__, reader_line if instance_reader
119
+ class_eval writer, __FILE__, writer_line if instance_writer
124
120
  end
125
121
  send("#{name}=", yield) if block_given?
126
122
  end
@@ -128,9 +124,9 @@ module ActiveSupport
128
124
  private :config_accessor
129
125
  end
130
126
 
131
- # Reads and writes attributes from a configuration <tt>OrderedHash</tt>.
127
+ # Reads and writes attributes from a configuration <tt>OrderedOptions</tt>.
132
128
  #
133
- # require 'active_support/configurable'
129
+ # require "active_support/configurable"
134
130
  #
135
131
  # class User
136
132
  # include ActiveSupport::Configurable
@@ -0,0 +1,51 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveSupport
4
+ # Reads a YAML configuration file, evaluating any ERB, then
5
+ # parsing the resulting YAML.
6
+ #
7
+ # Warns in case of YAML confusing characters, like invisible
8
+ # non-breaking spaces.
9
+ class ConfigurationFile # :nodoc:
10
+ class FormatError < StandardError; end
11
+
12
+ def initialize(content_path)
13
+ @content_path = content_path.to_s
14
+ @content = read content_path
15
+ end
16
+
17
+ def self.parse(content_path, **options)
18
+ new(content_path).parse(**options)
19
+ end
20
+
21
+ def parse(context: nil, **options)
22
+ source = render(context)
23
+ if YAML.respond_to?(:unsafe_load)
24
+ YAML.unsafe_load(source, **options) || {}
25
+ else
26
+ YAML.load(source, **options) || {}
27
+ end
28
+ rescue Psych::SyntaxError => error
29
+ raise "YAML syntax error occurred while parsing #{@content_path}. " \
30
+ "Please note that YAML must be consistently indented using spaces. Tabs are not allowed. " \
31
+ "Error: #{error.message}"
32
+ end
33
+
34
+ private
35
+ def read(content_path)
36
+ require "yaml"
37
+ require "erb"
38
+
39
+ File.read(content_path).tap do |content|
40
+ if content.include?("\u00A0")
41
+ warn "File contains invisible non-breaking spaces, you may want to remove those"
42
+ end
43
+ end
44
+ end
45
+
46
+ def render(context)
47
+ erb = ERB.new(@content).tap { |e| e.filename = @content_path }
48
+ context ? erb.result(context) : erb.result
49
+ end
50
+ end
51
+ end
@@ -29,16 +29,28 @@ class Array
29
29
  end
30
30
  end
31
31
 
32
- # Returns a copy of the Array without the specified elements.
32
+ # Returns a new array that includes the passed elements.
33
33
  #
34
- # people = ["David", "Rafael", "Aaron", "Todd"]
35
- # people.without "Aaron", "Todd"
36
- # # => ["David", "Rafael"]
34
+ # [ 1, 2, 3 ].including(4, 5) # => [ 1, 2, 3, 4, 5 ]
35
+ # [ [ 0, 1 ] ].including([ [ 1, 0 ] ]) # => [ [ 0, 1 ], [ 1, 0 ] ]
36
+ def including(*elements)
37
+ self + elements.flatten(1)
38
+ end
39
+
40
+ # Returns a copy of the Array excluding the specified elements.
41
+ #
42
+ # ["David", "Rafael", "Aaron", "Todd"].excluding("Aaron", "Todd") # => ["David", "Rafael"]
43
+ # [ [ 0, 1 ], [ 1, 0 ] ].excluding([ [ 1, 0 ] ]) # => [ [ 0, 1 ] ]
37
44
  #
38
- # Note: This is an optimization of <tt>Enumerable#without</tt> that uses <tt>Array#-</tt>
45
+ # Note: This is an optimization of <tt>Enumerable#excluding</tt> that uses <tt>Array#-</tt>
39
46
  # instead of <tt>Array#reject</tt> for performance reasons.
47
+ def excluding(*elements)
48
+ self - elements.flatten(1)
49
+ end
50
+
51
+ # Alias for #excluding.
40
52
  def without(*elements)
41
- self - elements
53
+ excluding(*elements)
42
54
  end
43
55
 
44
56
  # Equal to <tt>self[1]</tt>.
@@ -74,13 +74,13 @@ class Array
74
74
 
75
75
  case length
76
76
  when 0
77
- ""
77
+ +""
78
78
  when 1
79
- "#{self[0]}"
79
+ +"#{self[0]}"
80
80
  when 2
81
- "#{self[0]}#{options[:two_words_connector]}#{self[1]}"
81
+ +"#{self[0]}#{options[:two_words_connector]}#{self[1]}"
82
82
  else
83
- "#{self[0...-1].join(options[:words_connector])}#{options[:last_word_connector]}#{self[-1]}"
83
+ +"#{self[0...-1].join(options[:words_connector])}#{options[:last_word_connector]}#{self[-1]}"
84
84
  end
85
85
  end
86
86
 
@@ -181,7 +181,7 @@ class Array
181
181
  # </messages>
182
182
  #
183
183
  def to_xml(options = {})
184
- require "active_support/builder" unless defined?(Builder)
184
+ require "active_support/builder" unless defined?(Builder::XmlMarkup)
185
185
 
186
186
  options = options.dup
187
187
  options[:indent] ||= 2
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Array
4
+ # Removes and returns the elements for which the block returns a true value.
5
+ # If no block is given, an Enumerator is returned instead.
6
+ #
7
+ # numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
8
+ # odd_numbers = numbers.extract! { |number| number.odd? } # => [1, 3, 5, 7, 9]
9
+ # numbers # => [0, 2, 4, 6, 8]
10
+ def extract!
11
+ return to_enum(:extract!) { size } unless block_given?
12
+
13
+ extracted_elements = []
14
+
15
+ reject! do |element|
16
+ extracted_elements << element if yield(element)
17
+ end
18
+
19
+ extracted_elements
20
+ end
21
+ end
@@ -3,7 +3,7 @@
3
3
  require "active_support/core_ext/array/wrap"
4
4
  require "active_support/core_ext/array/access"
5
5
  require "active_support/core_ext/array/conversions"
6
+ require "active_support/core_ext/array/extract"
6
7
  require "active_support/core_ext/array/extract_options"
7
8
  require "active_support/core_ext/array/grouping"
8
- require "active_support/core_ext/array/prepend_and_append"
9
9
  require "active_support/core_ext/array/inquiry"
@@ -10,7 +10,7 @@ class << Benchmark
10
10
  #
11
11
  # Benchmark.ms { User.all }
12
12
  # # => 0.074
13
- def ms
14
- 1000 * realtime { yield }
13
+ def ms(&block)
14
+ 1000 * realtime(&block)
15
15
  end
16
16
  end