activesupport 4.2.0 → 5.0.0

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 (185) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +630 -220
  3. data/MIT-LICENSE +2 -2
  4. data/README.rdoc +2 -3
  5. data/lib/active_support/array_inquirer.rb +44 -0
  6. data/lib/active_support/backtrace_cleaner.rb +1 -1
  7. data/lib/active_support/benchmarkable.rb +1 -1
  8. data/lib/active_support/cache/file_store.rb +36 -22
  9. data/lib/active_support/cache/mem_cache_store.rb +63 -54
  10. data/lib/active_support/cache/memory_store.rb +16 -21
  11. data/lib/active_support/cache/null_store.rb +1 -4
  12. data/lib/active_support/cache/strategy/local_cache.rb +31 -20
  13. data/lib/active_support/cache.rb +73 -89
  14. data/lib/active_support/callbacks.rb +195 -155
  15. data/lib/active_support/concern.rb +2 -2
  16. data/lib/active_support/concurrency/latch.rb +7 -15
  17. data/lib/active_support/concurrency/share_lock.rb +186 -0
  18. data/lib/active_support/configurable.rb +1 -0
  19. data/lib/active_support/core_ext/array/access.rb +27 -1
  20. data/lib/active_support/core_ext/array/conversions.rb +6 -4
  21. data/lib/active_support/core_ext/array/grouping.rb +9 -18
  22. data/lib/active_support/core_ext/array/inquiry.rb +17 -0
  23. data/lib/active_support/core_ext/array/wrap.rb +5 -4
  24. data/lib/active_support/core_ext/array.rb +1 -0
  25. data/lib/active_support/core_ext/big_decimal/conversions.rb +8 -10
  26. data/lib/active_support/core_ext/class/attribute.rb +10 -9
  27. data/lib/active_support/core_ext/class/subclasses.rb +3 -4
  28. data/lib/active_support/core_ext/class.rb +0 -1
  29. data/lib/active_support/core_ext/date/blank.rb +12 -0
  30. data/lib/active_support/core_ext/date/calculations.rb +1 -1
  31. data/lib/active_support/core_ext/date/conversions.rb +13 -6
  32. data/lib/active_support/core_ext/date.rb +1 -1
  33. data/lib/active_support/core_ext/date_and_time/calculations.rb +109 -25
  34. data/lib/active_support/core_ext/date_and_time/compatibility.rb +18 -0
  35. data/lib/active_support/core_ext/date_and_time/zones.rb +3 -4
  36. data/lib/active_support/core_ext/date_time/blank.rb +12 -0
  37. data/lib/active_support/core_ext/date_time/calculations.rb +36 -10
  38. data/lib/active_support/core_ext/date_time/compatibility.rb +5 -0
  39. data/lib/active_support/core_ext/date_time/conversions.rb +2 -0
  40. data/lib/active_support/core_ext/date_time.rb +2 -1
  41. data/lib/active_support/core_ext/enumerable.rb +49 -5
  42. data/lib/active_support/core_ext/file/atomic.rb +30 -25
  43. data/lib/active_support/core_ext/hash/conversions.rb +23 -4
  44. data/lib/active_support/core_ext/hash/deep_merge.rb +1 -1
  45. data/lib/active_support/core_ext/hash/except.rb +9 -8
  46. data/lib/active_support/core_ext/hash/indifferent_access.rb +1 -1
  47. data/lib/active_support/core_ext/hash/keys.rb +23 -19
  48. data/lib/active_support/core_ext/hash/slice.rb +1 -1
  49. data/lib/active_support/core_ext/hash/transform_values.rb +11 -5
  50. data/lib/active_support/core_ext/integer/time.rb +1 -16
  51. data/lib/active_support/core_ext/kernel/concern.rb +2 -0
  52. data/lib/active_support/core_ext/kernel/debugger.rb +3 -10
  53. data/lib/active_support/core_ext/kernel/reporting.rb +2 -83
  54. data/lib/active_support/core_ext/kernel.rb +0 -1
  55. data/lib/active_support/core_ext/load_error.rb +4 -2
  56. data/lib/active_support/core_ext/marshal.rb +12 -11
  57. data/lib/active_support/core_ext/module/aliasing.rb +6 -1
  58. data/lib/active_support/core_ext/module/anonymous.rb +10 -1
  59. data/lib/active_support/core_ext/module/attr_internal.rb +2 -5
  60. data/lib/active_support/core_ext/module/attribute_accessors.rb +15 -15
  61. data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +141 -0
  62. data/lib/active_support/core_ext/module/concerning.rb +4 -4
  63. data/lib/active_support/core_ext/module/delegation.rb +35 -25
  64. data/lib/active_support/core_ext/module/deprecation.rb +2 -2
  65. data/lib/active_support/core_ext/module/introspection.rb +4 -0
  66. data/lib/active_support/core_ext/module/method_transplanting.rb +3 -11
  67. data/lib/active_support/core_ext/module/qualified_const.rb +30 -12
  68. data/lib/active_support/core_ext/module/remove_method.rb +23 -0
  69. data/lib/active_support/core_ext/module.rb +1 -0
  70. data/lib/active_support/core_ext/name_error.rb +15 -2
  71. data/lib/active_support/core_ext/numeric/bytes.rb +20 -0
  72. data/lib/active_support/core_ext/numeric/conversions.rb +74 -64
  73. data/lib/active_support/core_ext/numeric/inquiry.rb +26 -0
  74. data/lib/active_support/core_ext/numeric/time.rb +24 -19
  75. data/lib/active_support/core_ext/numeric.rb +1 -0
  76. data/lib/active_support/core_ext/object/blank.rb +17 -5
  77. data/lib/active_support/core_ext/object/deep_dup.rb +10 -3
  78. data/lib/active_support/core_ext/object/duplicable.rb +8 -13
  79. data/lib/active_support/core_ext/object/inclusion.rb +2 -2
  80. data/lib/active_support/core_ext/object/instance_variables.rb +1 -1
  81. data/lib/active_support/core_ext/object/json.rb +15 -7
  82. data/lib/active_support/core_ext/object/to_query.rb +1 -1
  83. data/lib/active_support/core_ext/object/try.rb +68 -22
  84. data/lib/active_support/core_ext/object/with_options.rb +1 -1
  85. data/lib/active_support/core_ext/object.rb +0 -1
  86. data/lib/active_support/core_ext/range/conversions.rb +18 -6
  87. data/lib/active_support/core_ext/range/each.rb +16 -18
  88. data/lib/active_support/core_ext/range/include_range.rb +20 -20
  89. data/lib/active_support/core_ext/securerandom.rb +23 -0
  90. data/lib/active_support/core_ext/string/access.rb +1 -1
  91. data/lib/active_support/core_ext/string/behavior.rb +1 -1
  92. data/lib/active_support/core_ext/string/conversions.rb +4 -3
  93. data/lib/active_support/core_ext/string/filters.rb +5 -5
  94. data/lib/active_support/core_ext/string/inflections.rb +32 -5
  95. data/lib/active_support/core_ext/string/multibyte.rb +11 -7
  96. data/lib/active_support/core_ext/string/output_safety.rb +18 -16
  97. data/lib/active_support/core_ext/string/strip.rb +3 -6
  98. data/lib/active_support/core_ext/struct.rb +3 -6
  99. data/lib/active_support/core_ext/time/calculations.rb +36 -11
  100. data/lib/active_support/core_ext/time/compatibility.rb +5 -0
  101. data/lib/active_support/core_ext/time/conversions.rb +4 -2
  102. data/lib/active_support/core_ext/time/marshal.rb +2 -29
  103. data/lib/active_support/core_ext/time/zones.rb +36 -4
  104. data/lib/active_support/core_ext/time.rb +1 -1
  105. data/lib/active_support/core_ext/uri.rb +1 -3
  106. data/lib/active_support/core_ext.rb +2 -1
  107. data/lib/active_support/dependencies/interlock.rb +51 -0
  108. data/lib/active_support/dependencies.rb +87 -95
  109. data/lib/active_support/deprecation/behaviors.rb +16 -2
  110. data/lib/active_support/deprecation/method_wrappers.rb +42 -16
  111. data/lib/active_support/deprecation/proxy_wrappers.rb +47 -24
  112. data/lib/active_support/deprecation/reporting.rb +23 -5
  113. data/lib/active_support/deprecation.rb +1 -1
  114. data/lib/active_support/duration/iso8601_parser.rb +122 -0
  115. data/lib/active_support/duration/iso8601_serializer.rb +51 -0
  116. data/lib/active_support/duration.rb +55 -10
  117. data/lib/active_support/evented_file_update_checker.rb +194 -0
  118. data/lib/active_support/execution_wrapper.rb +117 -0
  119. data/lib/active_support/executor.rb +6 -0
  120. data/lib/active_support/file_update_checker.rb +23 -3
  121. data/lib/active_support/gem_version.rb +3 -3
  122. data/lib/active_support/hash_with_indifferent_access.rb +46 -13
  123. data/lib/active_support/i18n_railtie.rb +25 -4
  124. data/lib/active_support/inflector/inflections.rb +36 -5
  125. data/lib/active_support/inflector/methods.rb +97 -90
  126. data/lib/active_support/inflector/transliterate.rb +36 -21
  127. data/lib/active_support/json/decoding.rb +11 -10
  128. data/lib/active_support/json/encoding.rb +4 -49
  129. data/lib/active_support/key_generator.rb +7 -9
  130. data/lib/active_support/locale/en.yml +2 -0
  131. data/lib/active_support/log_subscriber/test_helper.rb +3 -3
  132. data/lib/active_support/log_subscriber.rb +1 -1
  133. data/lib/active_support/logger.rb +50 -1
  134. data/lib/active_support/logger_silence.rb +8 -4
  135. data/lib/active_support/logger_thread_safe_level.rb +31 -0
  136. data/lib/active_support/message_encryptor.rb +4 -4
  137. data/lib/active_support/message_verifier.rb +70 -8
  138. data/lib/active_support/multibyte/chars.rb +13 -4
  139. data/lib/active_support/multibyte/unicode.rb +44 -21
  140. data/lib/active_support/notifications/fanout.rb +6 -6
  141. data/lib/active_support/notifications/instrumenter.rb +20 -2
  142. data/lib/active_support/notifications.rb +2 -2
  143. data/lib/active_support/number_helper/number_to_currency_converter.rb +7 -9
  144. data/lib/active_support/number_helper/number_to_delimited_converter.rb +8 -3
  145. data/lib/active_support/number_helper/number_to_human_converter.rb +6 -4
  146. data/lib/active_support/number_helper/number_to_human_size_converter.rb +6 -2
  147. data/lib/active_support/number_helper/number_to_percentage_converter.rb +1 -1
  148. data/lib/active_support/number_helper/number_to_phone_converter.rb +11 -2
  149. data/lib/active_support/number_helper/number_to_rounded_converter.rb +30 -25
  150. data/lib/active_support/number_helper.rb +90 -67
  151. data/lib/active_support/ordered_hash.rb +1 -1
  152. data/lib/active_support/ordered_options.rb +15 -1
  153. data/lib/active_support/per_thread_registry.rb +8 -3
  154. data/lib/active_support/rails.rb +2 -2
  155. data/lib/active_support/railtie.rb +6 -1
  156. data/lib/active_support/reloader.rb +129 -0
  157. data/lib/active_support/rescuable.rb +93 -47
  158. data/lib/active_support/security_utils.rb +7 -0
  159. data/lib/active_support/string_inquirer.rb +1 -1
  160. data/lib/active_support/subscriber.rb +5 -10
  161. data/lib/active_support/tagged_logging.rb +3 -1
  162. data/lib/active_support/test_case.rb +15 -29
  163. data/lib/active_support/testing/assertions.rb +15 -13
  164. data/lib/active_support/testing/autorun.rb +8 -1
  165. data/lib/active_support/testing/deprecation.rb +9 -8
  166. data/lib/active_support/testing/file_fixtures.rb +34 -0
  167. data/lib/active_support/testing/isolation.rb +22 -8
  168. data/lib/active_support/testing/method_call_assertions.rb +41 -0
  169. data/lib/active_support/testing/stream.rb +42 -0
  170. data/lib/active_support/testing/time_helpers.rb +13 -10
  171. data/lib/active_support/time_with_zone.rb +135 -46
  172. data/lib/active_support/values/time_zone.rb +95 -47
  173. data/lib/active_support/values/unicode_tables.dat +0 -0
  174. data/lib/active_support/xml_mini/jdom.rb +7 -6
  175. data/lib/active_support/xml_mini/libxml.rb +2 -2
  176. data/lib/active_support/xml_mini/nokogiri.rb +2 -2
  177. data/lib/active_support/xml_mini/rexml.rb +7 -8
  178. data/lib/active_support/xml_mini.rb +22 -14
  179. data/lib/active_support.rb +20 -6
  180. metadata +32 -35
  181. data/lib/active_support/core_ext/big_decimal/yaml_conversions.rb +0 -14
  182. data/lib/active_support/core_ext/class/delegating_attributes.rb +0 -45
  183. data/lib/active_support/core_ext/date_time/zones.rb +0 -6
  184. data/lib/active_support/core_ext/object/itself.rb +0 -15
  185. data/lib/active_support/core_ext/thread.rb +0 -86
@@ -4,6 +4,9 @@ require 'active_support/core_ext/array/extract_options'
4
4
  require 'active_support/core_ext/class/attribute'
5
5
  require 'active_support/core_ext/kernel/reporting'
6
6
  require 'active_support/core_ext/kernel/singleton_class'
7
+ require 'active_support/core_ext/module/attribute_accessors'
8
+ require 'active_support/core_ext/string/filters'
9
+ require 'active_support/deprecation'
7
10
  require 'thread'
8
11
 
9
12
  module ActiveSupport
@@ -64,6 +67,12 @@ module ActiveSupport
64
67
 
65
68
  CALLBACK_FILTER_TYPES = [:before, :after, :around]
66
69
 
70
+ # If true, Active Record and Active Model callbacks returning +false+ will
71
+ # halt the entire callback chain and display a deprecation message.
72
+ # If false, callback chains will only be halted by calling +throw :abort+.
73
+ # Defaults to +true+.
74
+ mattr_accessor(:halt_and_display_warning_on_return_false, instance_writer: false) { true }
75
+
67
76
  # Runs the callbacks for the given event.
68
77
  #
69
78
  # Calls the before and around callbacks in the order they were set, yields
@@ -83,9 +92,9 @@ module ActiveSupport
83
92
 
84
93
  private
85
94
 
86
- def _run_callbacks(callbacks, &block)
95
+ def __run_callbacks__(callbacks, &block)
87
96
  if callbacks.empty?
88
- block.call if block
97
+ yield if block_given?
89
98
  else
90
99
  runner = callbacks.compile
91
100
  e = Filters::Environment.new(self, false, nil, block)
@@ -121,102 +130,75 @@ module ActiveSupport
121
130
  ENDING = End.new
122
131
 
123
132
  class Before
124
- def self.build(next_callback, user_callback, user_conditions, chain_config, filter)
133
+ def self.build(callback_sequence, user_callback, user_conditions, chain_config, filter)
125
134
  halted_lambda = chain_config[:terminator]
126
135
 
127
- if chain_config.key?(:terminator) && user_conditions.any?
128
- halting_and_conditional(next_callback, user_callback, user_conditions, halted_lambda, filter)
129
- elsif chain_config.key? :terminator
130
- halting(next_callback, user_callback, halted_lambda, filter)
131
- elsif user_conditions.any?
132
- conditional(next_callback, user_callback, user_conditions)
136
+ if user_conditions.any?
137
+ halting_and_conditional(callback_sequence, user_callback, user_conditions, halted_lambda, filter)
133
138
  else
134
- simple next_callback, user_callback
139
+ halting(callback_sequence, user_callback, halted_lambda, filter)
135
140
  end
136
141
  end
137
142
 
138
- def self.halting_and_conditional(next_callback, user_callback, user_conditions, halted_lambda, filter)
139
- lambda { |env|
143
+ def self.halting_and_conditional(callback_sequence, user_callback, user_conditions, halted_lambda, filter)
144
+ callback_sequence.before do |env|
140
145
  target = env.target
141
146
  value = env.value
142
147
  halted = env.halted
143
148
 
144
149
  if !halted && user_conditions.all? { |c| c.call(target, value) }
145
- result = user_callback.call target, value
146
- env.halted = halted_lambda.call(target, result)
150
+ result_lambda = -> { user_callback.call target, value }
151
+ env.halted = halted_lambda.call(target, result_lambda)
147
152
  if env.halted
148
153
  target.send :halted_callback_hook, filter
149
154
  end
150
155
  end
151
- next_callback.call env
152
- }
156
+
157
+ env
158
+ end
153
159
  end
154
160
  private_class_method :halting_and_conditional
155
161
 
156
- def self.halting(next_callback, user_callback, halted_lambda, filter)
157
- lambda { |env|
162
+ def self.halting(callback_sequence, user_callback, halted_lambda, filter)
163
+ callback_sequence.before do |env|
158
164
  target = env.target
159
165
  value = env.value
160
166
  halted = env.halted
161
167
 
162
168
  unless halted
163
- result = user_callback.call target, value
164
- env.halted = halted_lambda.call(target, result)
169
+ result_lambda = -> { user_callback.call target, value }
170
+ env.halted = halted_lambda.call(target, result_lambda)
171
+
165
172
  if env.halted
166
173
  target.send :halted_callback_hook, filter
167
174
  end
168
175
  end
169
- next_callback.call env
170
- }
171
- end
172
- private_class_method :halting
173
-
174
- def self.conditional(next_callback, user_callback, user_conditions)
175
- lambda { |env|
176
- target = env.target
177
- value = env.value
178
-
179
- if user_conditions.all? { |c| c.call(target, value) }
180
- user_callback.call target, value
181
- end
182
- next_callback.call env
183
- }
184
- end
185
- private_class_method :conditional
186
176
 
187
- def self.simple(next_callback, user_callback)
188
- lambda { |env|
189
- user_callback.call env.target, env.value
190
- next_callback.call env
191
- }
177
+ env
178
+ end
192
179
  end
193
- private_class_method :simple
180
+ private_class_method :halting
194
181
  end
195
182
 
196
183
  class After
197
- def self.build(next_callback, user_callback, user_conditions, chain_config)
184
+ def self.build(callback_sequence, user_callback, user_conditions, chain_config)
198
185
  if chain_config[:skip_after_callbacks_if_terminated]
199
- if chain_config.key?(:terminator) && user_conditions.any?
200
- halting_and_conditional(next_callback, user_callback, user_conditions)
201
- elsif chain_config.key?(:terminator)
202
- halting(next_callback, user_callback)
203
- elsif user_conditions.any?
204
- conditional next_callback, user_callback, user_conditions
186
+ if user_conditions.any?
187
+ halting_and_conditional(callback_sequence, user_callback, user_conditions)
205
188
  else
206
- simple next_callback, user_callback
189
+ halting(callback_sequence, user_callback)
207
190
  end
208
191
  else
209
192
  if user_conditions.any?
210
- conditional next_callback, user_callback, user_conditions
193
+ conditional callback_sequence, user_callback, user_conditions
211
194
  else
212
- simple next_callback, user_callback
195
+ simple callback_sequence, user_callback
213
196
  end
214
197
  end
215
198
  end
216
199
 
217
- def self.halting_and_conditional(next_callback, user_callback, user_conditions)
218
- lambda { |env|
219
- env = next_callback.call env
200
+ def self.halting_and_conditional(callback_sequence, user_callback, user_conditions)
201
+ callback_sequence.after do |env|
220
202
  target = env.target
221
203
  value = env.value
222
204
  halted = env.halted
@@ -224,129 +206,102 @@ module ActiveSupport
224
206
  if !halted && user_conditions.all? { |c| c.call(target, value) }
225
207
  user_callback.call target, value
226
208
  end
209
+
227
210
  env
228
- }
211
+ end
229
212
  end
230
213
  private_class_method :halting_and_conditional
231
214
 
232
- def self.halting(next_callback, user_callback)
233
- lambda { |env|
234
- env = next_callback.call env
215
+ def self.halting(callback_sequence, user_callback)
216
+ callback_sequence.after do |env|
235
217
  unless env.halted
236
218
  user_callback.call env.target, env.value
237
219
  end
220
+
238
221
  env
239
- }
222
+ end
240
223
  end
241
224
  private_class_method :halting
242
225
 
243
- def self.conditional(next_callback, user_callback, user_conditions)
244
- lambda { |env|
245
- env = next_callback.call env
226
+ def self.conditional(callback_sequence, user_callback, user_conditions)
227
+ callback_sequence.after do |env|
246
228
  target = env.target
247
229
  value = env.value
248
230
 
249
231
  if user_conditions.all? { |c| c.call(target, value) }
250
232
  user_callback.call target, value
251
233
  end
234
+
252
235
  env
253
- }
236
+ end
254
237
  end
255
238
  private_class_method :conditional
256
239
 
257
- def self.simple(next_callback, user_callback)
258
- lambda { |env|
259
- env = next_callback.call env
240
+ def self.simple(callback_sequence, user_callback)
241
+ callback_sequence.after do |env|
260
242
  user_callback.call env.target, env.value
243
+
261
244
  env
262
- }
245
+ end
263
246
  end
264
247
  private_class_method :simple
265
248
  end
266
249
 
267
250
  class Around
268
- def self.build(next_callback, user_callback, user_conditions, chain_config)
269
- if chain_config.key?(:terminator) && user_conditions.any?
270
- halting_and_conditional(next_callback, user_callback, user_conditions)
271
- elsif chain_config.key? :terminator
272
- halting(next_callback, user_callback)
273
- elsif user_conditions.any?
274
- conditional(next_callback, user_callback, user_conditions)
251
+ def self.build(callback_sequence, user_callback, user_conditions, chain_config)
252
+ if user_conditions.any?
253
+ halting_and_conditional(callback_sequence, user_callback, user_conditions)
275
254
  else
276
- simple(next_callback, user_callback)
255
+ halting(callback_sequence, user_callback)
277
256
  end
278
257
  end
279
258
 
280
- def self.halting_and_conditional(next_callback, user_callback, user_conditions)
281
- lambda { |env|
259
+ def self.halting_and_conditional(callback_sequence, user_callback, user_conditions)
260
+ callback_sequence.around do |env, &run|
282
261
  target = env.target
283
262
  value = env.value
284
263
  halted = env.halted
285
264
 
286
265
  if !halted && user_conditions.all? { |c| c.call(target, value) }
287
266
  user_callback.call(target, value) {
288
- env = next_callback.call env
289
- env.value
267
+ run.call.value
290
268
  }
291
269
  env
292
270
  else
293
- next_callback.call env
271
+ run.call
294
272
  end
295
- }
273
+ end
296
274
  end
297
275
  private_class_method :halting_and_conditional
298
276
 
299
- def self.halting(next_callback, user_callback)
300
- lambda { |env|
277
+ def self.halting(callback_sequence, user_callback)
278
+ callback_sequence.around do |env, &run|
301
279
  target = env.target
302
280
  value = env.value
303
281
 
304
282
  if env.halted
305
- next_callback.call env
283
+ run.call
306
284
  else
307
285
  user_callback.call(target, value) {
308
- env = next_callback.call env
309
- env.value
286
+ run.call.value
310
287
  }
311
288
  env
312
289
  end
313
- }
290
+ end
314
291
  end
315
292
  private_class_method :halting
316
-
317
- def self.conditional(next_callback, user_callback, user_conditions)
318
- lambda { |env|
319
- target = env.target
320
- value = env.value
321
-
322
- if user_conditions.all? { |c| c.call(target, value) }
323
- user_callback.call(target, value) {
324
- env = next_callback.call env
325
- env.value
326
- }
327
- env
328
- else
329
- next_callback.call env
330
- end
331
- }
332
- end
333
- private_class_method :conditional
334
-
335
- def self.simple(next_callback, user_callback)
336
- lambda { |env|
337
- user_callback.call(env.target, env.value) {
338
- env = next_callback.call env
339
- env.value
340
- }
341
- env
342
- }
343
- end
344
- private_class_method :simple
345
293
  end
346
294
  end
347
295
 
348
296
  class Callback #:nodoc:#
349
297
  def self.build(chain, filter, kind, options)
298
+ if filter.is_a?(String)
299
+ ActiveSupport::Deprecation.warn(<<-MSG.squish)
300
+ Passing string to define callback is deprecated and will be removed
301
+ in Rails 5.1 without replacement.
302
+ MSG
303
+ end
304
+
350
305
  new chain.name, filter, kind, options, chain.config
351
306
  end
352
307
 
@@ -366,14 +321,14 @@ module ActiveSupport
366
321
  def filter; @key; end
367
322
  def raw_filter; @filter; end
368
323
 
369
- def merge(chain, new_options)
324
+ def merge_conditional_options(chain, if_option:, unless_option:)
370
325
  options = {
371
326
  :if => @if.dup,
372
327
  :unless => @unless.dup
373
328
  }
374
329
 
375
- options[:if].concat Array(new_options.fetch(:unless, []))
376
- options[:unless].concat Array(new_options.fetch(:if, []))
330
+ options[:if].concat Array(unless_option)
331
+ options[:unless].concat Array(if_option)
377
332
 
378
333
  self.class.build chain, @filter, @kind, options
379
334
  end
@@ -392,17 +347,17 @@ module ActiveSupport
392
347
  end
393
348
 
394
349
  # Wraps code with filter
395
- def apply(next_callback)
350
+ def apply(callback_sequence)
396
351
  user_conditions = conditions_lambdas
397
352
  user_callback = make_lambda @filter
398
353
 
399
354
  case kind
400
355
  when :before
401
- Filters::Before.build(next_callback, user_callback, user_conditions, chain_config, @filter)
356
+ Filters::Before.build(callback_sequence, user_callback, user_conditions, chain_config, @filter)
402
357
  when :after
403
- Filters::After.build(next_callback, user_callback, user_conditions, chain_config)
358
+ Filters::After.build(callback_sequence, user_callback, user_conditions, chain_config)
404
359
  when :around
405
- Filters::Around.build(next_callback, user_callback, user_conditions, chain_config)
360
+ Filters::Around.build(callback_sequence, user_callback, user_conditions, chain_config)
406
361
  end
407
362
  end
408
363
 
@@ -467,6 +422,42 @@ module ActiveSupport
467
422
  end
468
423
  end
469
424
 
425
+ # Execute before and after filters in a sequence instead of
426
+ # chaining them with nested lambda calls, see:
427
+ # https://github.com/rails/rails/issues/18011
428
+ class CallbackSequence
429
+ def initialize(&call)
430
+ @call = call
431
+ @before = []
432
+ @after = []
433
+ end
434
+
435
+ def before(&before)
436
+ @before.unshift(before)
437
+ self
438
+ end
439
+
440
+ def after(&after)
441
+ @after.push(after)
442
+ self
443
+ end
444
+
445
+ def around(&around)
446
+ CallbackSequence.new do |arg|
447
+ around.call(arg) {
448
+ self.call(arg)
449
+ }
450
+ end
451
+ end
452
+
453
+ def call(arg)
454
+ @before.each { |b| b.call(arg) }
455
+ value = @call.call(arg)
456
+ @after.each { |a| a.call(arg) }
457
+ value
458
+ end
459
+ end
460
+
470
461
  # An Array with a compile method.
471
462
  class CallbackChain #:nodoc:#
472
463
  include Enumerable
@@ -476,7 +467,8 @@ module ActiveSupport
476
467
  def initialize(name, config)
477
468
  @name = name
478
469
  @config = {
479
- :scope => [ :kind ]
470
+ scope: [:kind],
471
+ terminator: default_terminator
480
472
  }.merge!(config)
481
473
  @chain = []
482
474
  @callbacks = nil
@@ -511,8 +503,9 @@ module ActiveSupport
511
503
 
512
504
  def compile
513
505
  @callbacks || @mutex.synchronize do
514
- @callbacks ||= @chain.reverse.inject(Filters::ENDING) do |chain, callback|
515
- callback.apply chain
506
+ final_sequence = CallbackSequence.new { |env| Filters::ENDING.call(env) }
507
+ @callbacks ||= @chain.reverse.inject(final_sequence) do |callback_sequence, callback|
508
+ callback.apply callback_sequence
516
509
  end
517
510
  end
518
511
  end
@@ -546,6 +539,17 @@ module ActiveSupport
546
539
  @callbacks = nil
547
540
  @chain.delete_if { |c| callback.duplicates?(c) }
548
541
  end
542
+
543
+ def default_terminator
544
+ Proc.new do |target, result_lambda|
545
+ terminate = true
546
+ catch(:abort) do
547
+ result_lambda.call if result_lambda.is_a?(Proc)
548
+ terminate = false
549
+ end
550
+ terminate
551
+ end
552
+ end
549
553
  end
550
554
 
551
555
  module ClassMethods
@@ -567,18 +571,18 @@ module ActiveSupport
567
571
 
568
572
  # Install a callback for the given event.
569
573
  #
570
- # set_callback :save, :before, :before_meth
571
- # set_callback :save, :after, :after_meth, if: :condition
574
+ # set_callback :save, :before, :before_method
575
+ # set_callback :save, :after, :after_method, if: :condition
572
576
  # set_callback :save, :around, ->(r, block) { stuff; result = block.call; stuff }
573
577
  #
574
- # The second arguments indicates whether the callback is to be run +:before+,
578
+ # The second argument indicates whether the callback is to be run +:before+,
575
579
  # +:after+, or +:around+ the event. If omitted, +:before+ is assumed. This
576
580
  # means the first example above can also be written as:
577
581
  #
578
- # set_callback :save, :before_meth
582
+ # set_callback :save, :before_method
579
583
  #
580
584
  # The callback can be specified as a symbol naming an instance method; as a
581
- # proc, lambda, or block; as a string to be instance evaluated; or as an
585
+ # proc, lambda, or block; as a string to be instance evaluated(deprecated); or as an
582
586
  # object that responds to a certain method determined by the <tt>:scope</tt>
583
587
  # argument to +define_callbacks+.
584
588
  #
@@ -594,10 +598,12 @@ module ActiveSupport
594
598
  #
595
599
  # ===== Options
596
600
  #
597
- # * <tt>:if</tt> - A symbol naming an instance method or a proc; the
598
- # callback will be called only when it returns a +true+ value.
599
- # * <tt>:unless</tt> - A symbol naming an instance method or a proc; the
600
- # callback will be called only when it returns a +false+ value.
601
+ # * <tt>:if</tt> - A symbol, a string or an array of symbols and strings,
602
+ # each naming an instance method or a proc; the callback will be called
603
+ # only when they all return a true value.
604
+ # * <tt>:unless</tt> - A symbol, a string or an array of symbols and
605
+ # strings, each naming an instance method or a proc; the callback will
606
+ # be called only when they all return a false value.
601
607
  # * <tt>:prepend</tt> - If +true+, the callback will be prepended to the
602
608
  # existing chain rather than appended.
603
609
  def set_callback(name, *filter_list, &block)
@@ -620,19 +626,27 @@ module ActiveSupport
620
626
  # class Writer < Person
621
627
  # skip_callback :validate, :before, :check_membership, if: -> { self.age > 18 }
622
628
  # end
629
+ #
630
+ # An <tt>ArgumentError</tt> will be raised if the callback has not
631
+ # already been set (unless the <tt>:raise</tt> option is set to <tt>false</tt>).
623
632
  def skip_callback(name, *filter_list, &block)
624
633
  type, filters, options = normalize_callback_params(filter_list, block)
634
+ options[:raise] = true unless options.key?(:raise)
625
635
 
626
636
  __update_callbacks(name) do |target, chain|
627
637
  filters.each do |filter|
628
- filter = chain.find {|c| c.matches?(type, filter) }
638
+ callback = chain.find {|c| c.matches?(type, filter) }
639
+
640
+ if !callback && options[:raise]
641
+ raise ArgumentError, "#{type.to_s.capitalize} #{name} callback #{filter.inspect} has not been defined"
642
+ end
629
643
 
630
- if filter && options.any?
631
- new_filter = filter.merge(chain, options)
632
- chain.insert(chain.index(filter), new_filter)
644
+ if callback && (options.key?(:if) || options.key?(:unless))
645
+ new_callback = callback.merge_conditional_options(chain, if_option: options[:if], unless_option: options[:unless])
646
+ chain.insert(chain.index(callback), new_callback)
633
647
  end
634
648
 
635
- chain.delete(filter)
649
+ chain.delete(callback)
636
650
  end
637
651
  target.set_callbacks name, chain
638
652
  end
@@ -659,21 +673,23 @@ module ActiveSupport
659
673
  # ===== Options
660
674
  #
661
675
  # * <tt>:terminator</tt> - Determines when a before filter will halt the
662
- # callback chain, preventing following callbacks from being called and
663
- # the event from being triggered. This should be a lambda to be executed.
664
- # The current object and the return result of the callback will be called
665
- # with the lambda.
676
+ # callback chain, preventing following before and around callbacks from
677
+ # being called and the event from being triggered.
678
+ # This should be a lambda to be executed.
679
+ # The current object and the result lambda of the callback will be provided
680
+ # to the terminator lambda.
666
681
  #
667
- # define_callbacks :validate, terminator: ->(target, result) { result == false }
682
+ # define_callbacks :validate, terminator: ->(target, result_lambda) { result_lambda.call == false }
668
683
  #
669
684
  # In this example, if any before validate callbacks returns +false+,
670
- # other callbacks are not executed. Defaults to +false+, meaning no value
671
- # halts the chain.
685
+ # any successive before and around callback is not executed.
686
+ #
687
+ # The default terminator halts the chain when a callback throws +:abort+.
672
688
  #
673
689
  # * <tt>:skip_after_callbacks_if_terminated</tt> - Determines if after
674
690
  # callbacks should be terminated by the <tt>:terminator</tt> option. By
675
- # default after callbacks executed no matter if callback chain was
676
- # terminated or not. Option makes sense only when <tt>:terminator</tt>
691
+ # default after callbacks are executed no matter if callback chain was
692
+ # terminated or not. This option makes sense only when <tt>:terminator</tt>
677
693
  # option is specified.
678
694
  #
679
695
  # * <tt>:scope</tt> - Indicates which methods should be executed when an
@@ -726,12 +742,12 @@ module ActiveSupport
726
742
  options = names.extract_options!
727
743
 
728
744
  names.each do |name|
729
- class_attribute "_#{name}_callbacks"
745
+ class_attribute "_#{name}_callbacks", instance_writer: false
730
746
  set_callbacks name, CallbackChain.new(name, options)
731
747
 
732
748
  module_eval <<-RUBY, __FILE__, __LINE__ + 1
733
749
  def _run_#{name}_callbacks(&block)
734
- _run_callbacks(_#{name}_callbacks, &block)
750
+ __run_callbacks__(_#{name}_callbacks, &block)
735
751
  end
736
752
  RUBY
737
753
  end
@@ -739,13 +755,37 @@ module ActiveSupport
739
755
 
740
756
  protected
741
757
 
742
- def get_callbacks(name)
758
+ def get_callbacks(name) # :nodoc:
743
759
  send "_#{name}_callbacks"
744
760
  end
745
761
 
746
- def set_callbacks(name, callbacks)
762
+ def set_callbacks(name, callbacks) # :nodoc:
747
763
  send "_#{name}_callbacks=", callbacks
748
764
  end
765
+
766
+ def deprecated_false_terminator # :nodoc:
767
+ Proc.new do |target, result_lambda|
768
+ terminate = true
769
+ catch(:abort) do
770
+ result = result_lambda.call if result_lambda.is_a?(Proc)
771
+ if Callbacks.halt_and_display_warning_on_return_false && result == false
772
+ display_deprecation_warning_for_false_terminator
773
+ else
774
+ terminate = false
775
+ end
776
+ end
777
+ terminate
778
+ end
779
+ end
780
+
781
+ private
782
+
783
+ def display_deprecation_warning_for_false_terminator
784
+ ActiveSupport::Deprecation.warn(<<-MSG.squish)
785
+ Returning `false` in Active Record and Active Model callbacks will not implicitly halt a callback chain in Rails 5.1.
786
+ To explicitly halt the callback chain, please use `throw :abort` instead.
787
+ MSG
788
+ end
749
789
  end
750
790
  end
751
791
  end
@@ -114,7 +114,7 @@ module ActiveSupport
114
114
  return false
115
115
  else
116
116
  return false if base < self
117
- @_dependencies.each { |dep| base.send(:include, dep) }
117
+ @_dependencies.each { |dep| base.include(dep) }
118
118
  super
119
119
  base.extend const_get(:ClassMethods) if const_defined?(:ClassMethods)
120
120
  base.class_eval(&@_included_block) if instance_variable_defined?(:@_included_block)
@@ -132,7 +132,7 @@ module ActiveSupport
132
132
  end
133
133
 
134
134
  def class_methods(&class_methods_module_definition)
135
- mod = const_defined?(:ClassMethods) ?
135
+ mod = const_defined?(:ClassMethods, false) ?
136
136
  const_get(:ClassMethods) :
137
137
  const_set(:ClassMethods, Module.new)
138
138
 
@@ -1,26 +1,18 @@
1
- require 'thread'
2
- require 'monitor'
1
+ require 'concurrent/atomic/count_down_latch'
3
2
 
4
3
  module ActiveSupport
5
4
  module Concurrency
6
- class Latch
5
+ class Latch < Concurrent::CountDownLatch
6
+
7
7
  def initialize(count = 1)
8
- @count = count
9
- @lock = Monitor.new
10
- @cv = @lock.new_cond
8
+ ActiveSupport::Deprecation.warn("ActiveSupport::Concurrency::Latch is deprecated. Please use Concurrent::CountDownLatch instead.")
9
+ super(count)
11
10
  end
12
11
 
13
- def release
14
- @lock.synchronize do
15
- @count -= 1 if @count > 0
16
- @cv.broadcast if @count.zero?
17
- end
18
- end
12
+ alias_method :release, :count_down
19
13
 
20
14
  def await
21
- @lock.synchronize do
22
- @cv.wait_while { @count > 0 }
23
- end
15
+ wait(nil)
24
16
  end
25
17
  end
26
18
  end