activesupport 5.2.4.3 → 7.0.3

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

Potentially problematic release.


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

Files changed (228) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +244 -459
  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 +2 -2
  7. data/lib/active_support/backtrace_cleaner.rb +31 -5
  8. data/lib/active_support/benchmarkable.rb +3 -3
  9. data/lib/active_support/cache/file_store.rb +47 -41
  10. data/lib/active_support/cache/mem_cache_store.rb +151 -40
  11. data/lib/active_support/cache/memory_store.rb +68 -34
  12. data/lib/active_support/cache/null_store.rb +16 -3
  13. data/lib/active_support/cache/redis_cache_store.rb +103 -101
  14. data/lib/active_support/cache/strategy/local_cache.rb +56 -64
  15. data/lib/active_support/cache.rb +333 -116
  16. data/lib/active_support/callbacks.rb +244 -128
  17. data/lib/active_support/code_generator.rb +65 -0
  18. data/lib/active_support/concern.rb +72 -5
  19. data/lib/active_support/concurrency/load_interlock_aware_monitor.rb +16 -0
  20. data/lib/active_support/concurrency/share_lock.rb +2 -3
  21. data/lib/active_support/configurable.rb +15 -16
  22. data/lib/active_support/configuration_file.rb +51 -0
  23. data/lib/active_support/core_ext/array/access.rb +15 -7
  24. data/lib/active_support/core_ext/array/conversions.rb +18 -17
  25. data/lib/active_support/core_ext/array/deprecated_conversions.rb +25 -0
  26. data/lib/active_support/core_ext/array/extract.rb +21 -0
  27. data/lib/active_support/core_ext/array/grouping.rb +6 -6
  28. data/lib/active_support/core_ext/array/inquiry.rb +2 -2
  29. data/lib/active_support/core_ext/array.rb +2 -1
  30. data/lib/active_support/core_ext/benchmark.rb +2 -2
  31. data/lib/active_support/core_ext/big_decimal/conversions.rb +1 -1
  32. data/lib/active_support/core_ext/class/attribute.rb +32 -47
  33. data/lib/active_support/core_ext/class/subclasses.rb +9 -22
  34. data/lib/active_support/core_ext/date/blank.rb +1 -1
  35. data/lib/active_support/core_ext/date/calculations.rb +15 -14
  36. data/lib/active_support/core_ext/date/conversions.rb +16 -15
  37. data/lib/active_support/core_ext/date/deprecated_conversions.rb +26 -0
  38. data/lib/active_support/core_ext/date.rb +1 -0
  39. data/lib/active_support/core_ext/date_and_time/calculations.rb +41 -51
  40. data/lib/active_support/core_ext/date_and_time/compatibility.rb +15 -0
  41. data/lib/active_support/core_ext/date_and_time/zones.rb +0 -1
  42. data/lib/active_support/core_ext/date_time/blank.rb +1 -1
  43. data/lib/active_support/core_ext/date_time/calculations.rb +1 -1
  44. data/lib/active_support/core_ext/date_time/conversions.rb +13 -14
  45. data/lib/active_support/core_ext/date_time/deprecated_conversions.rb +22 -0
  46. data/lib/active_support/core_ext/date_time.rb +1 -0
  47. data/lib/active_support/core_ext/digest/uuid.rb +39 -13
  48. data/lib/active_support/core_ext/enumerable.rb +241 -76
  49. data/lib/active_support/core_ext/file/atomic.rb +3 -1
  50. data/lib/active_support/core_ext/hash/conversions.rb +3 -4
  51. data/lib/active_support/core_ext/hash/deep_transform_values.rb +46 -0
  52. data/lib/active_support/core_ext/hash/except.rb +2 -2
  53. data/lib/active_support/core_ext/hash/indifferent_access.rb +3 -3
  54. data/lib/active_support/core_ext/hash/keys.rb +2 -31
  55. data/lib/active_support/core_ext/hash/slice.rb +6 -27
  56. data/lib/active_support/core_ext/hash.rb +1 -2
  57. data/lib/active_support/core_ext/integer/multiple.rb +1 -1
  58. data/lib/active_support/core_ext/kernel/reporting.rb +4 -4
  59. data/lib/active_support/core_ext/kernel/singleton_class.rb +1 -1
  60. data/lib/active_support/core_ext/kernel.rb +0 -1
  61. data/lib/active_support/core_ext/load_error.rb +1 -1
  62. data/lib/active_support/core_ext/module/attr_internal.rb +2 -2
  63. data/lib/active_support/core_ext/module/attribute_accessors.rb +32 -39
  64. data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +35 -28
  65. data/lib/active_support/core_ext/module/concerning.rb +8 -2
  66. data/lib/active_support/core_ext/module/delegation.rb +70 -33
  67. data/lib/active_support/core_ext/module/introspection.rb +16 -15
  68. data/lib/active_support/core_ext/module/redefine_method.rb +8 -17
  69. data/lib/active_support/core_ext/module.rb +0 -1
  70. data/lib/active_support/core_ext/name_error.rb +23 -2
  71. data/lib/active_support/core_ext/numeric/conversions.rb +132 -129
  72. data/lib/active_support/core_ext/numeric/deprecated_conversions.rb +60 -0
  73. data/lib/active_support/core_ext/numeric.rb +1 -1
  74. data/lib/active_support/core_ext/object/acts_like.rb +29 -5
  75. data/lib/active_support/core_ext/object/blank.rb +3 -4
  76. data/lib/active_support/core_ext/object/deep_dup.rb +1 -1
  77. data/lib/active_support/core_ext/object/duplicable.rb +14 -110
  78. data/lib/active_support/core_ext/object/json.rb +44 -27
  79. data/lib/active_support/core_ext/object/to_query.rb +2 -2
  80. data/lib/active_support/core_ext/object/try.rb +24 -14
  81. data/lib/active_support/core_ext/object/with_options.rb +21 -2
  82. data/lib/active_support/core_ext/pathname/existence.rb +21 -0
  83. data/lib/active_support/core_ext/pathname.rb +3 -0
  84. data/lib/active_support/core_ext/range/compare_range.rb +23 -27
  85. data/lib/active_support/core_ext/range/conversions.rb +32 -30
  86. data/lib/active_support/core_ext/range/deprecated_conversions.rb +26 -0
  87. data/lib/active_support/core_ext/range/each.rb +1 -2
  88. data/lib/active_support/core_ext/range/include_time_with_zone.rb +4 -20
  89. data/lib/active_support/core_ext/range/overlaps.rb +1 -1
  90. data/lib/active_support/core_ext/range.rb +1 -1
  91. data/lib/active_support/core_ext/regexp.rb +8 -5
  92. data/lib/active_support/core_ext/securerandom.rb +23 -3
  93. data/lib/active_support/core_ext/string/access.rb +5 -16
  94. data/lib/active_support/core_ext/string/conversions.rb +3 -2
  95. data/lib/active_support/core_ext/string/filters.rb +42 -1
  96. data/lib/active_support/core_ext/string/inflections.rb +46 -7
  97. data/lib/active_support/core_ext/string/inquiry.rb +2 -1
  98. data/lib/active_support/core_ext/string/multibyte.rb +6 -5
  99. data/lib/active_support/core_ext/string/output_safety.rb +129 -20
  100. data/lib/active_support/core_ext/string/starts_ends_with.rb +2 -2
  101. data/lib/active_support/core_ext/string/strip.rb +3 -1
  102. data/lib/active_support/core_ext/symbol/starts_ends_with.rb +6 -0
  103. data/lib/active_support/core_ext/symbol.rb +3 -0
  104. data/lib/active_support/core_ext/time/calculations.rb +59 -10
  105. data/lib/active_support/core_ext/time/conversions.rb +15 -12
  106. data/lib/active_support/core_ext/time/deprecated_conversions.rb +22 -0
  107. data/lib/active_support/core_ext/time/zones.rb +7 -22
  108. data/lib/active_support/core_ext/time.rb +1 -0
  109. data/lib/active_support/core_ext/uri.rb +3 -22
  110. data/lib/active_support/core_ext.rb +2 -1
  111. data/lib/active_support/current_attributes/test_helper.rb +13 -0
  112. data/lib/active_support/current_attributes.rb +47 -16
  113. data/lib/active_support/dependencies/interlock.rb +10 -18
  114. data/lib/active_support/dependencies/require_dependency.rb +28 -0
  115. data/lib/active_support/dependencies.rb +60 -715
  116. data/lib/active_support/deprecation/behaviors.rb +21 -5
  117. data/lib/active_support/deprecation/disallowed.rb +56 -0
  118. data/lib/active_support/deprecation/instance_delegator.rb +0 -1
  119. data/lib/active_support/deprecation/method_wrappers.rb +18 -23
  120. data/lib/active_support/deprecation/proxy_wrappers.rb +31 -8
  121. data/lib/active_support/deprecation/reporting.rb +50 -7
  122. data/lib/active_support/deprecation.rb +7 -2
  123. data/lib/active_support/descendants_tracker.rb +190 -34
  124. data/lib/active_support/digest.rb +5 -3
  125. data/lib/active_support/duration/iso8601_parser.rb +5 -7
  126. data/lib/active_support/duration/iso8601_serializer.rb +27 -15
  127. data/lib/active_support/duration.rb +149 -67
  128. data/lib/active_support/encrypted_configuration.rb +12 -5
  129. data/lib/active_support/encrypted_file.rb +23 -5
  130. data/lib/active_support/environment_inquirer.rb +20 -0
  131. data/lib/active_support/error_reporter.rb +117 -0
  132. data/lib/active_support/evented_file_update_checker.rb +85 -122
  133. data/lib/active_support/execution_context/test_helper.rb +13 -0
  134. data/lib/active_support/execution_context.rb +53 -0
  135. data/lib/active_support/execution_wrapper.rb +44 -21
  136. data/lib/active_support/executor/test_helper.rb +7 -0
  137. data/lib/active_support/file_update_checker.rb +0 -1
  138. data/lib/active_support/fork_tracker.rb +71 -0
  139. data/lib/active_support/gem_version.rb +5 -5
  140. data/lib/active_support/hash_with_indifferent_access.rb +73 -43
  141. data/lib/active_support/html_safe_translation.rb +43 -0
  142. data/lib/active_support/i18n.rb +2 -0
  143. data/lib/active_support/i18n_railtie.rb +15 -8
  144. data/lib/active_support/inflector/inflections.rb +25 -14
  145. data/lib/active_support/inflector/methods.rb +38 -71
  146. data/lib/active_support/inflector/transliterate.rb +47 -18
  147. data/lib/active_support/isolated_execution_state.rb +72 -0
  148. data/lib/active_support/json/decoding.rb +25 -26
  149. data/lib/active_support/json/encoding.rb +14 -6
  150. data/lib/active_support/key_generator.rb +23 -38
  151. data/lib/active_support/lazy_load_hooks.rb +19 -5
  152. data/lib/active_support/locale/en.rb +33 -0
  153. data/lib/active_support/locale/en.yml +8 -4
  154. data/lib/active_support/log_subscriber/test_helper.rb +2 -2
  155. data/lib/active_support/log_subscriber.rb +51 -11
  156. data/lib/active_support/logger.rb +6 -22
  157. data/lib/active_support/logger_silence.rb +11 -19
  158. data/lib/active_support/logger_thread_safe_level.rb +45 -10
  159. data/lib/active_support/message_encryptor.rb +20 -19
  160. data/lib/active_support/message_verifier.rb +53 -21
  161. data/lib/active_support/messages/metadata.rb +13 -4
  162. data/lib/active_support/messages/rotation_configuration.rb +2 -1
  163. data/lib/active_support/messages/rotator.rb +10 -9
  164. data/lib/active_support/multibyte/chars.rb +17 -76
  165. data/lib/active_support/multibyte/unicode.rb +7 -331
  166. data/lib/active_support/multibyte.rb +1 -1
  167. data/lib/active_support/notifications/fanout.rb +163 -37
  168. data/lib/active_support/notifications/instrumenter.rb +90 -11
  169. data/lib/active_support/notifications.rb +88 -30
  170. data/lib/active_support/number_helper/number_converter.rb +6 -9
  171. data/lib/active_support/number_helper/number_to_currency_converter.rb +12 -12
  172. data/lib/active_support/number_helper/number_to_delimited_converter.rb +4 -3
  173. data/lib/active_support/number_helper/number_to_human_converter.rb +4 -3
  174. data/lib/active_support/number_helper/number_to_human_size_converter.rb +5 -4
  175. data/lib/active_support/number_helper/number_to_percentage_converter.rb +3 -1
  176. data/lib/active_support/number_helper/number_to_phone_converter.rb +3 -2
  177. data/lib/active_support/number_helper/number_to_rounded_converter.rb +12 -7
  178. data/lib/active_support/number_helper/rounding_helper.rb +12 -32
  179. data/lib/active_support/number_helper.rb +36 -12
  180. data/lib/active_support/option_merger.rb +15 -4
  181. data/lib/active_support/ordered_hash.rb +2 -2
  182. data/lib/active_support/ordered_options.rb +14 -4
  183. data/lib/active_support/parameter_filter.rb +138 -0
  184. data/lib/active_support/per_thread_registry.rb +6 -1
  185. data/lib/active_support/rails.rb +1 -10
  186. data/lib/active_support/railtie.rb +77 -5
  187. data/lib/active_support/reloader.rb +5 -6
  188. data/lib/active_support/rescuable.rb +8 -8
  189. data/lib/active_support/ruby_features.rb +7 -0
  190. data/lib/active_support/secure_compare_rotator.rb +51 -0
  191. data/lib/active_support/security_utils.rb +19 -12
  192. data/lib/active_support/string_inquirer.rb +2 -3
  193. data/lib/active_support/subscriber.rb +79 -46
  194. data/lib/active_support/tagged_logging.rb +58 -9
  195. data/lib/active_support/test_case.rb +79 -0
  196. data/lib/active_support/testing/assertions.rb +62 -11
  197. data/lib/active_support/testing/deprecation.rb +52 -2
  198. data/lib/active_support/testing/file_fixtures.rb +2 -0
  199. data/lib/active_support/testing/isolation.rb +4 -4
  200. data/lib/active_support/testing/method_call_assertions.rb +32 -5
  201. data/lib/active_support/testing/parallelization/server.rb +82 -0
  202. data/lib/active_support/testing/parallelization/worker.rb +103 -0
  203. data/lib/active_support/testing/parallelization.rb +55 -0
  204. data/lib/active_support/testing/parallelize_executor.rb +76 -0
  205. data/lib/active_support/testing/stream.rb +4 -7
  206. data/lib/active_support/testing/tagged_logging.rb +1 -1
  207. data/lib/active_support/testing/time_helpers.rb +60 -14
  208. data/lib/active_support/time_with_zone.rb +139 -64
  209. data/lib/active_support/values/time_zone.rb +66 -30
  210. data/lib/active_support/version.rb +1 -1
  211. data/lib/active_support/xml_mini/jdom.rb +3 -4
  212. data/lib/active_support/xml_mini/libxml.rb +7 -7
  213. data/lib/active_support/xml_mini/libxmlsax.rb +5 -5
  214. data/lib/active_support/xml_mini/nokogiri.rb +6 -6
  215. data/lib/active_support/xml_mini/nokogirisax.rb +4 -4
  216. data/lib/active_support/xml_mini/rexml.rb +11 -4
  217. data/lib/active_support/xml_mini.rb +7 -14
  218. data/lib/active_support.rb +30 -1
  219. metadata +64 -35
  220. data/lib/active_support/core_ext/array/prepend_and_append.rb +0 -9
  221. data/lib/active_support/core_ext/hash/compact.rb +0 -29
  222. data/lib/active_support/core_ext/hash/transform_values.rb +0 -32
  223. data/lib/active_support/core_ext/kernel/agnostics.rb +0 -13
  224. data/lib/active_support/core_ext/marshal.rb +0 -24
  225. data/lib/active_support/core_ext/module/reachable.rb +0 -11
  226. data/lib/active_support/core_ext/numeric/inquiry.rb +0 -28
  227. data/lib/active_support/core_ext/range/include_range.rb +0 -3
  228. data/lib/active_support/values/unicode_tables.dat +0 -0
@@ -4,10 +4,8 @@ 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"
8
+ require "active_support/core_ext/object/blank"
11
9
  require "thread"
12
10
 
13
11
  module ActiveSupport
@@ -18,16 +16,19 @@ module ActiveSupport
18
16
  # needing to override or redefine methods of the base class.
19
17
  #
20
18
  # Mixing in this module allows you to define the events in the object's
21
- # life cycle that will support callbacks (via +ClassMethods.define_callbacks+),
19
+ # life cycle that will support callbacks (via ClassMethods#define_callbacks),
22
20
  # set the instance methods, procs, or callback objects to be called (via
23
- # +ClassMethods.set_callback+), and run the installed callbacks at the
21
+ # ClassMethods#set_callback), and run the installed callbacks at the
24
22
  # appropriate times (via +run_callbacks+).
25
23
  #
24
+ # By default callbacks are halted by throwing +:abort+.
25
+ # See ClassMethods#define_callbacks for details.
26
+ #
26
27
  # Three kinds of callbacks are supported: before callbacks, run before a
27
28
  # certain event; after callbacks, run after the event; and around callbacks,
28
29
  # blocks that surround the event, triggering it when they yield. Callback code
29
30
  # can be contained in instance methods, procs or lambdas, or callback objects
30
- # that respond to certain predetermined methods. See +ClassMethods.set_callback+
31
+ # that respond to certain predetermined methods. See ClassMethods#set_callback
31
32
  # for details.
32
33
  #
33
34
  # class Record
@@ -100,32 +101,6 @@ module ActiveSupport
100
101
  env = Filters::Environment.new(self, false, nil)
101
102
  next_sequence = callbacks.compile
102
103
 
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
104
  # Common case: no 'around' callbacks defined
130
105
  if next_sequence.final?
131
106
  next_sequence.invoke_before(env)
@@ -133,17 +108,43 @@ module ActiveSupport
133
108
  next_sequence.invoke_after(env)
134
109
  env.value
135
110
  else
111
+ invoke_sequence = Proc.new do
112
+ skipped = nil
113
+
114
+ while true
115
+ current = next_sequence
116
+ current.invoke_before(env)
117
+ if current.final?
118
+ env.value = !env.halted && (!block_given? || yield)
119
+ elsif current.skip?(env)
120
+ (skipped ||= []) << current
121
+ next_sequence = next_sequence.nested
122
+ next
123
+ else
124
+ next_sequence = next_sequence.nested
125
+ begin
126
+ target, block, method, *arguments = current.expand_call_template(env, invoke_sequence)
127
+ target.send(method, *arguments, &block)
128
+ ensure
129
+ next_sequence = current
130
+ end
131
+ end
132
+ current.invoke_after(env)
133
+ skipped.pop.invoke_after(env) while skipped&.first
134
+ break env.value
135
+ end
136
+ end
137
+
136
138
  invoke_sequence.call
137
139
  end
138
140
  end
139
141
  end
140
142
 
141
143
  private
142
-
143
144
  # A hook invoked every time a before callback is halted.
144
145
  # This can be overridden in ActiveSupport::Callbacks implementors in order
145
146
  # to provide better debugging/logging.
146
- def halted_callback_hook(filter)
147
+ def halted_callback_hook(filter, name)
147
148
  end
148
149
 
149
150
  module Conditionals # :nodoc:
@@ -159,17 +160,17 @@ module ActiveSupport
159
160
  Environment = Struct.new(:target, :halted, :value)
160
161
 
161
162
  class Before
162
- def self.build(callback_sequence, user_callback, user_conditions, chain_config, filter)
163
+ def self.build(callback_sequence, user_callback, user_conditions, chain_config, filter, name)
163
164
  halted_lambda = chain_config[:terminator]
164
165
 
165
166
  if user_conditions.any?
166
- halting_and_conditional(callback_sequence, user_callback, user_conditions, halted_lambda, filter)
167
+ halting_and_conditional(callback_sequence, user_callback, user_conditions, halted_lambda, filter, name)
167
168
  else
168
- halting(callback_sequence, user_callback, halted_lambda, filter)
169
+ halting(callback_sequence, user_callback, halted_lambda, filter, name)
169
170
  end
170
171
  end
171
172
 
172
- def self.halting_and_conditional(callback_sequence, user_callback, user_conditions, halted_lambda, filter)
173
+ def self.halting_and_conditional(callback_sequence, user_callback, user_conditions, halted_lambda, filter, name)
173
174
  callback_sequence.before do |env|
174
175
  target = env.target
175
176
  value = env.value
@@ -179,7 +180,7 @@ module ActiveSupport
179
180
  result_lambda = -> { user_callback.call target, value }
180
181
  env.halted = halted_lambda.call(target, result_lambda)
181
182
  if env.halted
182
- target.send :halted_callback_hook, filter
183
+ target.send :halted_callback_hook, filter, name
183
184
  end
184
185
  end
185
186
 
@@ -188,7 +189,7 @@ module ActiveSupport
188
189
  end
189
190
  private_class_method :halting_and_conditional
190
191
 
191
- def self.halting(callback_sequence, user_callback, halted_lambda, filter)
192
+ def self.halting(callback_sequence, user_callback, halted_lambda, filter, name)
192
193
  callback_sequence.before do |env|
193
194
  target = env.target
194
195
  value = env.value
@@ -197,9 +198,8 @@ module ActiveSupport
197
198
  unless halted
198
199
  result_lambda = -> { user_callback.call target, value }
199
200
  env.halted = halted_lambda.call(target, result_lambda)
200
-
201
201
  if env.halted
202
- target.send :halted_callback_hook, filter
202
+ target.send :halted_callback_hook, filter, name
203
203
  end
204
204
  end
205
205
 
@@ -277,7 +277,7 @@ module ActiveSupport
277
277
  end
278
278
  end
279
279
 
280
- class Callback #:nodoc:#
280
+ class Callback # :nodoc:#
281
281
  def self.build(chain, filter, kind, options)
282
282
  if filter.is_a?(String)
283
283
  raise ArgumentError, <<-MSG.squish
@@ -290,21 +290,17 @@ module ActiveSupport
290
290
  end
291
291
 
292
292
  attr_accessor :kind, :name
293
- attr_reader :chain_config
293
+ attr_reader :chain_config, :filter
294
294
 
295
295
  def initialize(name, filter, kind, options, chain_config)
296
296
  @chain_config = chain_config
297
297
  @name = name
298
298
  @kind = kind
299
299
  @filter = filter
300
- @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
- def filter; @key; end
306
- def raw_filter; @filter; end
307
-
308
304
  def merge_conditional_options(chain, if_option:, unless_option:)
309
305
  options = {
310
306
  if: @if.dup,
@@ -337,7 +333,7 @@ module ActiveSupport
337
333
 
338
334
  case kind
339
335
  when :before
340
- Filters::Before.build(callback_sequence, user_callback.make_lambda, user_conditions, chain_config, @filter)
336
+ Filters::Before.build(callback_sequence, user_callback.make_lambda, user_conditions, chain_config, @filter, name)
341
337
  when :after
342
338
  Filters::After.build(callback_sequence, user_callback.make_lambda, user_conditions, chain_config)
343
339
  when :around
@@ -350,8 +346,14 @@ module ActiveSupport
350
346
  end
351
347
 
352
348
  private
349
+ EMPTY_ARRAY = [].freeze
350
+ private_constant :EMPTY_ARRAY
351
+
353
352
  def check_conditionals(conditionals)
354
- if conditionals.any? { |c| c.is_a?(String) }
353
+ return EMPTY_ARRAY if conditionals.blank?
354
+
355
+ conditionals = Array(conditionals)
356
+ if conditionals.any?(String)
355
357
  raise ArgumentError, <<-MSG.squish
356
358
  Passing string to be evaluated in :if and :unless conditional
357
359
  options is not supported. Pass a symbol for an instance method,
@@ -359,16 +361,7 @@ module ActiveSupport
359
361
  MSG
360
362
  end
361
363
 
362
- conditionals
363
- end
364
-
365
- def compute_identifier(filter)
366
- case filter
367
- when ::Proc
368
- filter.object_id
369
- else
370
- filter
371
- end
364
+ conditionals.freeze
372
365
  end
373
366
 
374
367
  def conditions_lambdas
@@ -379,60 +372,153 @@ module ActiveSupport
379
372
 
380
373
  # A future invocation of user-supplied code (either as a callback,
381
374
  # or a condition filter).
382
- class CallTemplate # :nodoc:
383
- def initialize(target, method, arguments, block)
384
- @override_target = target
385
- @method_name = method
386
- @arguments = arguments
387
- @override_block = block
375
+ module CallTemplate # :nodoc:
376
+ class MethodCall
377
+ def initialize(method)
378
+ @method_name = method
379
+ end
380
+
381
+ # Return the parts needed to make this call, with the given
382
+ # input values.
383
+ #
384
+ # Returns an array of the form:
385
+ #
386
+ # [target, block, method, *arguments]
387
+ #
388
+ # This array can be used as such:
389
+ #
390
+ # target.send(method, *arguments, &block)
391
+ #
392
+ # The actual invocation is left up to the caller to minimize
393
+ # call stack pollution.
394
+ def expand(target, value, block)
395
+ [target, block, @method_name]
396
+ end
397
+
398
+ def make_lambda
399
+ lambda do |target, value, &block|
400
+ target.send(@method_name, &block)
401
+ end
402
+ end
403
+
404
+ def inverted_lambda
405
+ lambda do |target, value, &block|
406
+ !target.send(@method_name, &block)
407
+ end
408
+ end
388
409
  end
389
410
 
390
- # Return the parts needed to make this call, with the given
391
- # input values.
392
- #
393
- # Returns an array of the form:
394
- #
395
- # [target, block, method, *arguments]
396
- #
397
- # This array can be used as such:
398
- #
399
- # target.send(method, *arguments, &block)
400
- #
401
- # The actual invocation is left up to the caller to minimize
402
- # call stack pollution.
403
- def expand(target, value, block)
404
- result = @arguments.map { |arg|
405
- case arg
406
- when :value; value
407
- when :target; target
408
- when :block; block || raise(ArgumentError)
411
+ class ObjectCall
412
+ def initialize(target, method)
413
+ @override_target = target
414
+ @method_name = method
415
+ end
416
+
417
+ def expand(target, value, block)
418
+ [@override_target || target, block, @method_name, target]
419
+ end
420
+
421
+ def make_lambda
422
+ lambda do |target, value, &block|
423
+ (@override_target || target).send(@method_name, target, &block)
409
424
  end
410
- }
425
+ end
411
426
 
412
- result.unshift @method_name
413
- result.unshift @override_block || block
414
- result.unshift @override_target || target
427
+ def inverted_lambda
428
+ lambda do |target, value, &block|
429
+ !(@override_target || target).send(@method_name, target, &block)
430
+ end
431
+ end
432
+ end
415
433
 
416
- # target, block, method, *arguments = result
417
- # target.send(method, *arguments, &block)
418
- result
434
+ class InstanceExec0
435
+ def initialize(block)
436
+ @override_block = block
437
+ end
438
+
439
+ def expand(target, value, block)
440
+ [target, @override_block, :instance_exec]
441
+ end
442
+
443
+ def make_lambda
444
+ lambda do |target, value, &block|
445
+ target.instance_exec(&@override_block)
446
+ end
447
+ end
448
+
449
+ def inverted_lambda
450
+ lambda do |target, value, &block|
451
+ !target.instance_exec(&@override_block)
452
+ end
453
+ end
419
454
  end
420
455
 
421
- # Return a lambda that will make this call when given the input
422
- # values.
423
- def make_lambda
424
- lambda do |target, value, &block|
425
- target, block, method, *arguments = expand(target, value, block)
426
- target.send(method, *arguments, &block)
456
+ class InstanceExec1
457
+ def initialize(block)
458
+ @override_block = block
459
+ end
460
+
461
+ def expand(target, value, block)
462
+ [target, @override_block, :instance_exec, target]
463
+ end
464
+
465
+ def make_lambda
466
+ lambda do |target, value, &block|
467
+ target.instance_exec(target, &@override_block)
468
+ end
469
+ end
470
+
471
+ def inverted_lambda
472
+ lambda do |target, value, &block|
473
+ !target.instance_exec(target, &@override_block)
474
+ end
427
475
  end
428
476
  end
429
477
 
430
- # Return a lambda that will make this call when given the input
431
- # values, but then return the boolean inverse of that result.
432
- def inverted_lambda
433
- lambda do |target, value, &block|
434
- target, block, method, *arguments = expand(target, value, block)
435
- ! target.send(method, *arguments, &block)
478
+ class InstanceExec2
479
+ def initialize(block)
480
+ @override_block = block
481
+ end
482
+
483
+ def expand(target, value, block)
484
+ raise ArgumentError unless block
485
+ [target, @override_block || block, :instance_exec, target, block]
486
+ end
487
+
488
+ def make_lambda
489
+ lambda do |target, value, &block|
490
+ raise ArgumentError unless block
491
+ target.instance_exec(target, block, &@override_block)
492
+ end
493
+ end
494
+
495
+ def inverted_lambda
496
+ lambda do |target, value, &block|
497
+ raise ArgumentError unless block
498
+ !target.instance_exec(target, block, &@override_block)
499
+ end
500
+ end
501
+ end
502
+
503
+ class ProcCall
504
+ def initialize(target)
505
+ @override_target = target
506
+ end
507
+
508
+ def expand(target, value, block)
509
+ [@override_target || target, block, :call, target, value]
510
+ end
511
+
512
+ def make_lambda
513
+ lambda do |target, value, &block|
514
+ (@override_target || target).call(target, value, &block)
515
+ end
516
+ end
517
+
518
+ def inverted_lambda
519
+ lambda do |target, value, &block|
520
+ !(@override_target || target).call(target, value, &block)
521
+ end
436
522
  end
437
523
  end
438
524
 
@@ -447,21 +533,19 @@ module ActiveSupport
447
533
  def self.build(filter, callback)
448
534
  case filter
449
535
  when Symbol
450
- new(nil, filter, [], nil)
536
+ MethodCall.new(filter)
451
537
  when Conditionals::Value
452
- new(filter, :call, [:target, :value], nil)
538
+ ProcCall.new(filter)
453
539
  when ::Proc
454
540
  if filter.arity > 1
455
- new(nil, :instance_exec, [:target, :block], filter)
541
+ InstanceExec2.new(filter)
456
542
  elsif filter.arity > 0
457
- new(nil, :instance_exec, [:target], filter)
543
+ InstanceExec1.new(filter)
458
544
  else
459
- new(nil, :instance_exec, [], filter)
545
+ InstanceExec0.new(filter)
460
546
  end
461
547
  else
462
- method_to_call = callback.current_scopes.join("_")
463
-
464
- new(filter, method_to_call, [:target], nil)
548
+ ObjectCall.new(filter, callback.current_scopes.join("_").to_sym)
465
549
  end
466
550
  end
467
551
  end
@@ -497,9 +581,7 @@ module ActiveSupport
497
581
  arg.halted || !@user_conditions.all? { |c| c.call(arg.target, arg.value) }
498
582
  end
499
583
 
500
- def nested
501
- @nested
502
- end
584
+ attr_reader :nested
503
585
 
504
586
  def final?
505
587
  !@call_template
@@ -518,7 +600,7 @@ module ActiveSupport
518
600
  end
519
601
  end
520
602
 
521
- class CallbackChain #:nodoc:#
603
+ class CallbackChain # :nodoc:
522
604
  include Enumerable
523
605
 
524
606
  attr_reader :name, :config
@@ -578,10 +660,9 @@ module ActiveSupport
578
660
  end
579
661
 
580
662
  protected
581
- def chain; @chain; end
663
+ attr_reader :chain
582
664
 
583
665
  private
584
-
585
666
  def append_one(callback)
586
667
  @callbacks = nil
587
668
  remove_duplicates(callback)
@@ -621,8 +702,8 @@ module ActiveSupport
621
702
 
622
703
  # This is used internally to append, prepend and skip callbacks to the
623
704
  # CallbackChain.
624
- def __update_callbacks(name) #:nodoc:
625
- ([self] + ActiveSupport::DescendantsTracker.descendants(self)).reverse_each do |target|
705
+ def __update_callbacks(name) # :nodoc:
706
+ ([self] + self.descendants).reverse_each do |target|
626
707
  chain = target.get_callbacks name
627
708
  yield target, chain.dup
628
709
  end
@@ -659,9 +740,17 @@ module ActiveSupport
659
740
  # * <tt>:if</tt> - A symbol or an array of symbols, each naming an instance
660
741
  # method or a proc; the callback will be called only when they all return
661
742
  # a true value.
743
+ #
744
+ # If a proc is given, its body is evaluated in the context of the
745
+ # current object. It can also optionally accept the current object as
746
+ # an argument.
662
747
  # * <tt>:unless</tt> - A symbol or an array of symbols, each naming an
663
748
  # instance method or a proc; the callback will be called only when they
664
749
  # all return a false value.
750
+ #
751
+ # If a proc is given, its body is evaluated in the context of the
752
+ # current object. It can also optionally accept the current object as
753
+ # an argument.
665
754
  # * <tt>:prepend</tt> - If +true+, the callback will be prepended to the
666
755
  # existing chain rather than appended.
667
756
  def set_callback(name, *filter_list, &block)
@@ -682,10 +771,32 @@ module ActiveSupport
682
771
  # <tt>:unless</tt> options may be passed in order to control when the
683
772
  # callback is skipped.
684
773
  #
685
- # class Writer < Person
686
- # skip_callback :validate, :before, :check_membership, if: -> { age > 18 }
774
+ # class Writer < PersonRecord
775
+ # attr_accessor :age
776
+ # skip_callback :save, :before, :saving_message, if: -> { age > 18 }
687
777
  # end
688
778
  #
779
+ # When if option returns true, callback is skipped.
780
+ #
781
+ # writer = Writer.new
782
+ # writer.age = 20
783
+ # writer.save
784
+ #
785
+ # Output:
786
+ # - save
787
+ # saved
788
+ #
789
+ # When if option returns false, callback is NOT skipped.
790
+ #
791
+ # young_writer = Writer.new
792
+ # young_writer.age = 17
793
+ # young_writer.save
794
+ #
795
+ # Output:
796
+ # saving...
797
+ # - save
798
+ # saved
799
+ #
689
800
  # An <tt>ArgumentError</tt> will be raised if the callback has not
690
801
  # already been set (unless the <tt>:raise</tt> option is set to <tt>false</tt>).
691
802
  def skip_callback(name, *filter_list, &block)
@@ -716,7 +827,7 @@ module ActiveSupport
716
827
  def reset_callbacks(name)
717
828
  callbacks = get_callbacks name
718
829
 
719
- ActiveSupport::DescendantsTracker.descendants(self).each do |target|
830
+ self.descendants.each do |target|
720
831
  chain = target.get_callbacks(name).dup
721
832
  callbacks.each { |c| chain.delete(c) }
722
833
  target.set_callbacks name, chain
@@ -809,7 +920,9 @@ module ActiveSupport
809
920
  names.each do |name|
810
921
  name = name.to_sym
811
922
 
812
- set_callbacks name, CallbackChain.new(name, options)
923
+ ([self] + self.descendants).each do |target|
924
+ target.set_callbacks name, CallbackChain.new(name, options)
925
+ end
813
926
 
814
927
  module_eval <<-RUBY, __FILE__, __LINE__ + 1
815
928
  def _run_#{name}_callbacks(&block)
@@ -832,13 +945,16 @@ module ActiveSupport
832
945
  end
833
946
 
834
947
  protected
835
-
836
948
  def get_callbacks(name) # :nodoc:
837
949
  __callbacks[name.to_sym]
838
950
  end
839
951
 
840
952
  def set_callbacks(name, callbacks) # :nodoc:
841
- self.__callbacks = __callbacks.merge(name.to_sym => callbacks)
953
+ unless singleton_class.method_defined?(:__callbacks, false)
954
+ self.__callbacks = __callbacks.dup
955
+ end
956
+ self.__callbacks[name.to_sym] = callbacks
957
+ self.__callbacks
842
958
  end
843
959
  end
844
960
  end
@@ -0,0 +1,65 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveSupport
4
+ class CodeGenerator # :nodoc:
5
+ class MethodSet
6
+ METHOD_CACHES = Hash.new { |h, k| h[k] = Module.new }
7
+
8
+ def initialize(namespace)
9
+ @cache = METHOD_CACHES[namespace]
10
+ @sources = []
11
+ @methods = {}
12
+ end
13
+
14
+ def define_cached_method(name, as: name)
15
+ name = name.to_sym
16
+ as = as.to_sym
17
+ @methods.fetch(name) do
18
+ unless @cache.method_defined?(as)
19
+ yield @sources
20
+ end
21
+ @methods[name] = as
22
+ end
23
+ end
24
+
25
+ def apply(owner, path, line)
26
+ unless @sources.empty?
27
+ @cache.module_eval("# frozen_string_literal: true\n" + @sources.join(";"), path, line)
28
+ end
29
+ @methods.each do |name, as|
30
+ owner.define_method(name, @cache.instance_method(as))
31
+ end
32
+ end
33
+ end
34
+
35
+ class << self
36
+ def batch(owner, path, line)
37
+ if owner.is_a?(CodeGenerator)
38
+ yield owner
39
+ else
40
+ instance = new(owner, path, line)
41
+ result = yield instance
42
+ instance.execute
43
+ result
44
+ end
45
+ end
46
+ end
47
+
48
+ def initialize(owner, path, line)
49
+ @owner = owner
50
+ @path = path
51
+ @line = line
52
+ @namespaces = Hash.new { |h, k| h[k] = MethodSet.new(k) }
53
+ end
54
+
55
+ def define_cached_method(name, namespace:, as: name, &block)
56
+ @namespaces[namespace].define_cached_method(name, as: as, &block)
57
+ end
58
+
59
+ def execute
60
+ @namespaces.each_value do |method_set|
61
+ method_set.apply(@owner, @path, @line - 1)
62
+ end
63
+ end
64
+ end
65
+ end