activesupport 5.0.7.2

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 (236) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +1018 -0
  3. data/MIT-LICENSE +20 -0
  4. data/README.rdoc +39 -0
  5. data/lib/active_support.rb +99 -0
  6. data/lib/active_support/all.rb +3 -0
  7. data/lib/active_support/array_inquirer.rb +44 -0
  8. data/lib/active_support/backtrace_cleaner.rb +103 -0
  9. data/lib/active_support/benchmarkable.rb +49 -0
  10. data/lib/active_support/builder.rb +6 -0
  11. data/lib/active_support/cache.rb +701 -0
  12. data/lib/active_support/cache/file_store.rb +204 -0
  13. data/lib/active_support/cache/mem_cache_store.rb +207 -0
  14. data/lib/active_support/cache/memory_store.rb +167 -0
  15. data/lib/active_support/cache/null_store.rb +41 -0
  16. data/lib/active_support/cache/strategy/local_cache.rb +172 -0
  17. data/lib/active_support/cache/strategy/local_cache_middleware.rb +44 -0
  18. data/lib/active_support/callbacks.rb +791 -0
  19. data/lib/active_support/concern.rb +142 -0
  20. data/lib/active_support/concurrency/latch.rb +26 -0
  21. data/lib/active_support/concurrency/share_lock.rb +226 -0
  22. data/lib/active_support/configurable.rb +148 -0
  23. data/lib/active_support/core_ext.rb +4 -0
  24. data/lib/active_support/core_ext/array.rb +7 -0
  25. data/lib/active_support/core_ext/array/access.rb +90 -0
  26. data/lib/active_support/core_ext/array/conversions.rb +211 -0
  27. data/lib/active_support/core_ext/array/extract_options.rb +29 -0
  28. data/lib/active_support/core_ext/array/grouping.rb +107 -0
  29. data/lib/active_support/core_ext/array/inquiry.rb +17 -0
  30. data/lib/active_support/core_ext/array/prepend_and_append.rb +7 -0
  31. data/lib/active_support/core_ext/array/wrap.rb +46 -0
  32. data/lib/active_support/core_ext/benchmark.rb +14 -0
  33. data/lib/active_support/core_ext/big_decimal.rb +1 -0
  34. data/lib/active_support/core_ext/big_decimal/conversions.rb +14 -0
  35. data/lib/active_support/core_ext/class.rb +2 -0
  36. data/lib/active_support/core_ext/class/attribute.rb +128 -0
  37. data/lib/active_support/core_ext/class/attribute_accessors.rb +4 -0
  38. data/lib/active_support/core_ext/class/subclasses.rb +41 -0
  39. data/lib/active_support/core_ext/date.rb +5 -0
  40. data/lib/active_support/core_ext/date/acts_like.rb +8 -0
  41. data/lib/active_support/core_ext/date/blank.rb +12 -0
  42. data/lib/active_support/core_ext/date/calculations.rb +143 -0
  43. data/lib/active_support/core_ext/date/conversions.rb +95 -0
  44. data/lib/active_support/core_ext/date/zones.rb +6 -0
  45. data/lib/active_support/core_ext/date_and_time/calculations.rb +335 -0
  46. data/lib/active_support/core_ext/date_and_time/compatibility.rb +14 -0
  47. data/lib/active_support/core_ext/date_and_time/zones.rb +40 -0
  48. data/lib/active_support/core_ext/date_time.rb +5 -0
  49. data/lib/active_support/core_ext/date_time/acts_like.rb +14 -0
  50. data/lib/active_support/core_ext/date_time/blank.rb +12 -0
  51. data/lib/active_support/core_ext/date_time/calculations.rb +199 -0
  52. data/lib/active_support/core_ext/date_time/compatibility.rb +16 -0
  53. data/lib/active_support/core_ext/date_time/conversions.rb +105 -0
  54. data/lib/active_support/core_ext/digest/uuid.rb +51 -0
  55. data/lib/active_support/core_ext/enumerable.rb +146 -0
  56. data/lib/active_support/core_ext/file.rb +1 -0
  57. data/lib/active_support/core_ext/file/atomic.rb +68 -0
  58. data/lib/active_support/core_ext/hash.rb +9 -0
  59. data/lib/active_support/core_ext/hash/compact.rb +24 -0
  60. data/lib/active_support/core_ext/hash/conversions.rb +262 -0
  61. data/lib/active_support/core_ext/hash/deep_merge.rb +38 -0
  62. data/lib/active_support/core_ext/hash/except.rb +22 -0
  63. data/lib/active_support/core_ext/hash/indifferent_access.rb +23 -0
  64. data/lib/active_support/core_ext/hash/keys.rb +170 -0
  65. data/lib/active_support/core_ext/hash/reverse_merge.rb +22 -0
  66. data/lib/active_support/core_ext/hash/slice.rb +48 -0
  67. data/lib/active_support/core_ext/hash/transform_values.rb +29 -0
  68. data/lib/active_support/core_ext/integer.rb +3 -0
  69. data/lib/active_support/core_ext/integer/inflections.rb +29 -0
  70. data/lib/active_support/core_ext/integer/multiple.rb +10 -0
  71. data/lib/active_support/core_ext/integer/time.rb +29 -0
  72. data/lib/active_support/core_ext/kernel.rb +4 -0
  73. data/lib/active_support/core_ext/kernel/agnostics.rb +11 -0
  74. data/lib/active_support/core_ext/kernel/concern.rb +12 -0
  75. data/lib/active_support/core_ext/kernel/debugger.rb +3 -0
  76. data/lib/active_support/core_ext/kernel/reporting.rb +43 -0
  77. data/lib/active_support/core_ext/kernel/singleton_class.rb +6 -0
  78. data/lib/active_support/core_ext/load_error.rb +31 -0
  79. data/lib/active_support/core_ext/marshal.rb +22 -0
  80. data/lib/active_support/core_ext/module.rb +12 -0
  81. data/lib/active_support/core_ext/module/aliasing.rb +74 -0
  82. data/lib/active_support/core_ext/module/anonymous.rb +28 -0
  83. data/lib/active_support/core_ext/module/attr_internal.rb +36 -0
  84. data/lib/active_support/core_ext/module/attribute_accessors.rb +212 -0
  85. data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +141 -0
  86. data/lib/active_support/core_ext/module/concerning.rb +135 -0
  87. data/lib/active_support/core_ext/module/delegation.rb +216 -0
  88. data/lib/active_support/core_ext/module/deprecation.rb +23 -0
  89. data/lib/active_support/core_ext/module/introspection.rb +68 -0
  90. data/lib/active_support/core_ext/module/method_transplanting.rb +3 -0
  91. data/lib/active_support/core_ext/module/qualified_const.rb +70 -0
  92. data/lib/active_support/core_ext/module/reachable.rb +8 -0
  93. data/lib/active_support/core_ext/module/remove_method.rb +35 -0
  94. data/lib/active_support/core_ext/name_error.rb +31 -0
  95. data/lib/active_support/core_ext/numeric.rb +4 -0
  96. data/lib/active_support/core_ext/numeric/bytes.rb +64 -0
  97. data/lib/active_support/core_ext/numeric/conversions.rb +144 -0
  98. data/lib/active_support/core_ext/numeric/inquiry.rb +26 -0
  99. data/lib/active_support/core_ext/numeric/time.rb +74 -0
  100. data/lib/active_support/core_ext/object.rb +14 -0
  101. data/lib/active_support/core_ext/object/acts_like.rb +10 -0
  102. data/lib/active_support/core_ext/object/blank.rb +143 -0
  103. data/lib/active_support/core_ext/object/conversions.rb +4 -0
  104. data/lib/active_support/core_ext/object/deep_dup.rb +53 -0
  105. data/lib/active_support/core_ext/object/duplicable.rb +124 -0
  106. data/lib/active_support/core_ext/object/inclusion.rb +27 -0
  107. data/lib/active_support/core_ext/object/instance_variables.rb +28 -0
  108. data/lib/active_support/core_ext/object/json.rb +205 -0
  109. data/lib/active_support/core_ext/object/to_param.rb +1 -0
  110. data/lib/active_support/core_ext/object/to_query.rb +84 -0
  111. data/lib/active_support/core_ext/object/try.rb +146 -0
  112. data/lib/active_support/core_ext/object/with_options.rb +69 -0
  113. data/lib/active_support/core_ext/range.rb +4 -0
  114. data/lib/active_support/core_ext/range/conversions.rb +31 -0
  115. data/lib/active_support/core_ext/range/each.rb +21 -0
  116. data/lib/active_support/core_ext/range/include_range.rb +23 -0
  117. data/lib/active_support/core_ext/range/overlaps.rb +8 -0
  118. data/lib/active_support/core_ext/regexp.rb +5 -0
  119. data/lib/active_support/core_ext/securerandom.rb +23 -0
  120. data/lib/active_support/core_ext/string.rb +13 -0
  121. data/lib/active_support/core_ext/string/access.rb +104 -0
  122. data/lib/active_support/core_ext/string/behavior.rb +6 -0
  123. data/lib/active_support/core_ext/string/conversions.rb +57 -0
  124. data/lib/active_support/core_ext/string/exclude.rb +11 -0
  125. data/lib/active_support/core_ext/string/filters.rb +102 -0
  126. data/lib/active_support/core_ext/string/indent.rb +43 -0
  127. data/lib/active_support/core_ext/string/inflections.rb +244 -0
  128. data/lib/active_support/core_ext/string/inquiry.rb +13 -0
  129. data/lib/active_support/core_ext/string/multibyte.rb +53 -0
  130. data/lib/active_support/core_ext/string/output_safety.rb +260 -0
  131. data/lib/active_support/core_ext/string/starts_ends_with.rb +4 -0
  132. data/lib/active_support/core_ext/string/strip.rb +23 -0
  133. data/lib/active_support/core_ext/string/zones.rb +14 -0
  134. data/lib/active_support/core_ext/struct.rb +3 -0
  135. data/lib/active_support/core_ext/time.rb +5 -0
  136. data/lib/active_support/core_ext/time/acts_like.rb +8 -0
  137. data/lib/active_support/core_ext/time/calculations.rb +290 -0
  138. data/lib/active_support/core_ext/time/compatibility.rb +14 -0
  139. data/lib/active_support/core_ext/time/conversions.rb +67 -0
  140. data/lib/active_support/core_ext/time/marshal.rb +3 -0
  141. data/lib/active_support/core_ext/time/zones.rb +111 -0
  142. data/lib/active_support/core_ext/uri.rb +24 -0
  143. data/lib/active_support/dependencies.rb +755 -0
  144. data/lib/active_support/dependencies/autoload.rb +77 -0
  145. data/lib/active_support/dependencies/interlock.rb +55 -0
  146. data/lib/active_support/deprecation.rb +43 -0
  147. data/lib/active_support/deprecation/behaviors.rb +90 -0
  148. data/lib/active_support/deprecation/instance_delegator.rb +37 -0
  149. data/lib/active_support/deprecation/method_wrappers.rb +70 -0
  150. data/lib/active_support/deprecation/proxy_wrappers.rb +149 -0
  151. data/lib/active_support/deprecation/reporting.rb +112 -0
  152. data/lib/active_support/descendants_tracker.rb +60 -0
  153. data/lib/active_support/duration.rb +235 -0
  154. data/lib/active_support/duration/iso8601_parser.rb +122 -0
  155. data/lib/active_support/duration/iso8601_serializer.rb +51 -0
  156. data/lib/active_support/evented_file_update_checker.rb +199 -0
  157. data/lib/active_support/execution_wrapper.rb +126 -0
  158. data/lib/active_support/executor.rb +6 -0
  159. data/lib/active_support/file_update_checker.rb +157 -0
  160. data/lib/active_support/gem_version.rb +15 -0
  161. data/lib/active_support/gzip.rb +36 -0
  162. data/lib/active_support/hash_with_indifferent_access.rb +329 -0
  163. data/lib/active_support/i18n.rb +13 -0
  164. data/lib/active_support/i18n_railtie.rb +115 -0
  165. data/lib/active_support/inflections.rb +70 -0
  166. data/lib/active_support/inflector.rb +7 -0
  167. data/lib/active_support/inflector/inflections.rb +242 -0
  168. data/lib/active_support/inflector/methods.rb +390 -0
  169. data/lib/active_support/inflector/transliterate.rb +112 -0
  170. data/lib/active_support/json.rb +2 -0
  171. data/lib/active_support/json/decoding.rb +74 -0
  172. data/lib/active_support/json/encoding.rb +127 -0
  173. data/lib/active_support/key_generator.rb +71 -0
  174. data/lib/active_support/lazy_load_hooks.rb +76 -0
  175. data/lib/active_support/locale/en.yml +135 -0
  176. data/lib/active_support/log_subscriber.rb +109 -0
  177. data/lib/active_support/log_subscriber/test_helper.rb +104 -0
  178. data/lib/active_support/logger.rb +106 -0
  179. data/lib/active_support/logger_silence.rb +28 -0
  180. data/lib/active_support/logger_thread_safe_level.rb +31 -0
  181. data/lib/active_support/message_encryptor.rb +114 -0
  182. data/lib/active_support/message_verifier.rb +134 -0
  183. data/lib/active_support/multibyte.rb +21 -0
  184. data/lib/active_support/multibyte/chars.rb +231 -0
  185. data/lib/active_support/multibyte/unicode.rb +413 -0
  186. data/lib/active_support/notifications.rb +212 -0
  187. data/lib/active_support/notifications/fanout.rb +157 -0
  188. data/lib/active_support/notifications/instrumenter.rb +91 -0
  189. data/lib/active_support/number_helper.rb +368 -0
  190. data/lib/active_support/number_helper/number_converter.rb +182 -0
  191. data/lib/active_support/number_helper/number_to_currency_converter.rb +44 -0
  192. data/lib/active_support/number_helper/number_to_delimited_converter.rb +28 -0
  193. data/lib/active_support/number_helper/number_to_human_converter.rb +68 -0
  194. data/lib/active_support/number_helper/number_to_human_size_converter.rb +62 -0
  195. data/lib/active_support/number_helper/number_to_percentage_converter.rb +12 -0
  196. data/lib/active_support/number_helper/number_to_phone_converter.rb +58 -0
  197. data/lib/active_support/number_helper/number_to_rounded_converter.rb +92 -0
  198. data/lib/active_support/option_merger.rb +25 -0
  199. data/lib/active_support/ordered_hash.rb +48 -0
  200. data/lib/active_support/ordered_options.rb +81 -0
  201. data/lib/active_support/per_thread_registry.rb +58 -0
  202. data/lib/active_support/proxy_object.rb +13 -0
  203. data/lib/active_support/rails.rb +27 -0
  204. data/lib/active_support/railtie.rb +51 -0
  205. data/lib/active_support/reloader.rb +129 -0
  206. data/lib/active_support/rescuable.rb +173 -0
  207. data/lib/active_support/security_utils.rb +27 -0
  208. data/lib/active_support/string_inquirer.rb +26 -0
  209. data/lib/active_support/subscriber.rb +120 -0
  210. data/lib/active_support/tagged_logging.rb +77 -0
  211. data/lib/active_support/test_case.rb +88 -0
  212. data/lib/active_support/testing/assertions.rb +99 -0
  213. data/lib/active_support/testing/autorun.rb +5 -0
  214. data/lib/active_support/testing/constant_lookup.rb +50 -0
  215. data/lib/active_support/testing/declarative.rb +26 -0
  216. data/lib/active_support/testing/deprecation.rb +36 -0
  217. data/lib/active_support/testing/file_fixtures.rb +34 -0
  218. data/lib/active_support/testing/isolation.rb +115 -0
  219. data/lib/active_support/testing/method_call_assertions.rb +41 -0
  220. data/lib/active_support/testing/setup_and_teardown.rb +50 -0
  221. data/lib/active_support/testing/stream.rb +42 -0
  222. data/lib/active_support/testing/tagged_logging.rb +25 -0
  223. data/lib/active_support/testing/time_helpers.rb +136 -0
  224. data/lib/active_support/time.rb +18 -0
  225. data/lib/active_support/time_with_zone.rb +511 -0
  226. data/lib/active_support/values/time_zone.rb +484 -0
  227. data/lib/active_support/values/unicode_tables.dat +0 -0
  228. data/lib/active_support/version.rb +8 -0
  229. data/lib/active_support/xml_mini.rb +209 -0
  230. data/lib/active_support/xml_mini/jdom.rb +181 -0
  231. data/lib/active_support/xml_mini/libxml.rb +77 -0
  232. data/lib/active_support/xml_mini/libxmlsax.rb +82 -0
  233. data/lib/active_support/xml_mini/nokogiri.rb +81 -0
  234. data/lib/active_support/xml_mini/nokogirisax.rb +85 -0
  235. data/lib/active_support/xml_mini/rexml.rb +128 -0
  236. metadata +349 -0
@@ -0,0 +1,41 @@
1
+ module ActiveSupport
2
+ module Cache
3
+ # A cache store implementation which doesn't actually store anything. Useful in
4
+ # development and test environments where you don't want caching turned on but
5
+ # need to go through the caching interface.
6
+ #
7
+ # This cache does implement the local cache strategy, so values will actually
8
+ # be cached inside blocks that utilize this strategy. See
9
+ # ActiveSupport::Cache::Strategy::LocalCache for more details.
10
+ class NullStore < Store
11
+ prepend Strategy::LocalCache
12
+
13
+ def clear(options = nil)
14
+ end
15
+
16
+ def cleanup(options = nil)
17
+ end
18
+
19
+ def increment(name, amount = 1, options = nil)
20
+ end
21
+
22
+ def decrement(name, amount = 1, options = nil)
23
+ end
24
+
25
+ def delete_matched(matcher, options = nil)
26
+ end
27
+
28
+ protected
29
+ def read_entry(key, options) # :nodoc:
30
+ end
31
+
32
+ def write_entry(key, entry, options) # :nodoc:
33
+ true
34
+ end
35
+
36
+ def delete_entry(key, options) # :nodoc:
37
+ false
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,172 @@
1
+ require 'active_support/core_ext/object/duplicable'
2
+ require 'active_support/core_ext/string/inflections'
3
+ require 'active_support/per_thread_registry'
4
+
5
+ module ActiveSupport
6
+ module Cache
7
+ module Strategy
8
+ # Caches that implement LocalCache will be backed by an in-memory cache for the
9
+ # duration of a block. Repeated calls to the cache for the same key will hit the
10
+ # in-memory cache for faster access.
11
+ module LocalCache
12
+ autoload :Middleware, 'active_support/cache/strategy/local_cache_middleware'
13
+
14
+ # Class for storing and registering the local caches.
15
+ class LocalCacheRegistry # :nodoc:
16
+ extend ActiveSupport::PerThreadRegistry
17
+
18
+ def initialize
19
+ @registry = {}
20
+ end
21
+
22
+ def cache_for(local_cache_key)
23
+ @registry[local_cache_key]
24
+ end
25
+
26
+ def set_cache_for(local_cache_key, value)
27
+ @registry[local_cache_key] = value
28
+ end
29
+
30
+ def self.set_cache_for(l, v); instance.set_cache_for l, v; end
31
+ def self.cache_for(l); instance.cache_for l; end
32
+ end
33
+
34
+ # Simple memory backed cache. This cache is not thread safe and is intended only
35
+ # for serving as a temporary memory cache for a single thread.
36
+ class LocalStore < Store
37
+ def initialize
38
+ super
39
+ @data = {}
40
+ end
41
+
42
+ # Don't allow synchronizing since it isn't thread safe.
43
+ def synchronize # :nodoc:
44
+ yield
45
+ end
46
+
47
+ def clear(options = nil)
48
+ @data.clear
49
+ end
50
+
51
+ def read_entry(key, options)
52
+ @data[key]
53
+ end
54
+
55
+ def write_entry(key, value, options)
56
+ @data[key] = value
57
+ true
58
+ end
59
+
60
+ def delete_entry(key, options)
61
+ !!@data.delete(key)
62
+ end
63
+
64
+ def fetch_entry(key, options = nil) # :nodoc:
65
+ @data.fetch(key) { @data[key] = yield }
66
+ end
67
+ end
68
+
69
+ # Use a local cache for the duration of block.
70
+ def with_local_cache
71
+ use_temporary_local_cache(LocalStore.new) { yield }
72
+ end
73
+ # Middleware class can be inserted as a Rack handler to be local cache for the
74
+ # duration of request.
75
+ def middleware
76
+ @middleware ||= Middleware.new(
77
+ "ActiveSupport::Cache::Strategy::LocalCache",
78
+ local_cache_key)
79
+ end
80
+
81
+ def clear(options = nil) # :nodoc:
82
+ return super unless cache = local_cache
83
+ cache.clear(options)
84
+ super
85
+ end
86
+
87
+ def cleanup(options = nil) # :nodoc:
88
+ return super unless cache = local_cache
89
+ cache.clear(options)
90
+ super
91
+ end
92
+
93
+ def increment(name, amount = 1, options = nil) # :nodoc:
94
+ return super unless local_cache
95
+ value = bypass_local_cache{super}
96
+ write_cache_value(name, value, options)
97
+ value
98
+ end
99
+
100
+ def decrement(name, amount = 1, options = nil) # :nodoc:
101
+ return super unless local_cache
102
+ value = bypass_local_cache{super}
103
+ write_cache_value(name, value, options)
104
+ value
105
+ end
106
+
107
+ protected
108
+ def read_entry(key, options) # :nodoc:
109
+ if cache = local_cache
110
+ cache.fetch_entry(key) { super }
111
+ else
112
+ super
113
+ end
114
+ end
115
+
116
+ def write_entry(key, entry, options) # :nodoc:
117
+ local_cache.write_entry(key, entry, options) if local_cache
118
+ super
119
+ end
120
+
121
+ def delete_entry(key, options) # :nodoc:
122
+ local_cache.delete_entry(key, options) if local_cache
123
+ super
124
+ end
125
+
126
+ def set_cache_value(value, name, amount, options) # :nodoc:
127
+ ActiveSupport::Deprecation.warn(<<-MESSAGE.strip_heredoc)
128
+ `set_cache_value` is deprecated and will be removed from Rails 5.1.
129
+ Please use `write_cache_value` instead.
130
+ MESSAGE
131
+ write_cache_value name, value, options
132
+ end
133
+
134
+ def write_cache_value(name, value, options) # :nodoc:
135
+ name = normalize_key(name, options)
136
+ cache = local_cache
137
+ cache.mute do
138
+ if value
139
+ cache.write(name, value, options)
140
+ else
141
+ cache.delete(name, options)
142
+ end
143
+ end
144
+ end
145
+
146
+ private
147
+
148
+ def local_cache_key
149
+ @local_cache_key ||= "#{self.class.name.underscore}_local_cache_#{object_id}".gsub(/[\/-]/, '_').to_sym
150
+ end
151
+
152
+ def local_cache
153
+ LocalCacheRegistry.cache_for(local_cache_key)
154
+ end
155
+
156
+ def bypass_local_cache
157
+ use_temporary_local_cache(nil) { yield }
158
+ end
159
+
160
+ def use_temporary_local_cache(temporary_cache)
161
+ save_cache = LocalCacheRegistry.cache_for(local_cache_key)
162
+ begin
163
+ LocalCacheRegistry.set_cache_for(local_cache_key, temporary_cache)
164
+ yield
165
+ ensure
166
+ LocalCacheRegistry.set_cache_for(local_cache_key, save_cache)
167
+ end
168
+ end
169
+ end
170
+ end
171
+ end
172
+ end
@@ -0,0 +1,44 @@
1
+ require 'rack/body_proxy'
2
+ require 'rack/utils'
3
+
4
+ module ActiveSupport
5
+ module Cache
6
+ module Strategy
7
+ module LocalCache
8
+
9
+ #--
10
+ # This class wraps up local storage for middlewares. Only the middleware method should
11
+ # construct them.
12
+ class Middleware # :nodoc:
13
+ attr_reader :name, :local_cache_key
14
+
15
+ def initialize(name, local_cache_key)
16
+ @name = name
17
+ @local_cache_key = local_cache_key
18
+ @app = nil
19
+ end
20
+
21
+ def new(app)
22
+ @app = app
23
+ self
24
+ end
25
+
26
+ def call(env)
27
+ LocalCacheRegistry.set_cache_for(local_cache_key, LocalStore.new)
28
+ response = @app.call(env)
29
+ response[2] = ::Rack::BodyProxy.new(response[2]) do
30
+ LocalCacheRegistry.set_cache_for(local_cache_key, nil)
31
+ end
32
+ cleanup_on_body_close = true
33
+ response
34
+ rescue Rack::Utils::InvalidParameterError
35
+ [400, {}, []]
36
+ ensure
37
+ LocalCacheRegistry.set_cache_for(local_cache_key, nil) unless
38
+ cleanup_on_body_close
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,791 @@
1
+ require 'active_support/concern'
2
+ require 'active_support/descendants_tracker'
3
+ require 'active_support/core_ext/array/extract_options'
4
+ require 'active_support/core_ext/class/attribute'
5
+ require 'active_support/core_ext/kernel/reporting'
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'
10
+ require 'thread'
11
+
12
+ module ActiveSupport
13
+ # Callbacks are code hooks that are run at key points in an object's life cycle.
14
+ # The typical use case is to have a base class define a set of callbacks
15
+ # relevant to the other functionality it supplies, so that subclasses can
16
+ # install callbacks that enhance or modify the base functionality without
17
+ # needing to override or redefine methods of the base class.
18
+ #
19
+ # Mixing in this module allows you to define the events in the object's
20
+ # life cycle that will support callbacks (via +ClassMethods.define_callbacks+),
21
+ # set the instance methods, procs, or callback objects to be called (via
22
+ # +ClassMethods.set_callback+), and run the installed callbacks at the
23
+ # appropriate times (via +run_callbacks+).
24
+ #
25
+ # Three kinds of callbacks are supported: before callbacks, run before a
26
+ # certain event; after callbacks, run after the event; and around callbacks,
27
+ # blocks that surround the event, triggering it when they yield. Callback code
28
+ # can be contained in instance methods, procs or lambdas, or callback objects
29
+ # that respond to certain predetermined methods. See +ClassMethods.set_callback+
30
+ # for details.
31
+ #
32
+ # class Record
33
+ # include ActiveSupport::Callbacks
34
+ # define_callbacks :save
35
+ #
36
+ # def save
37
+ # run_callbacks :save do
38
+ # puts "- save"
39
+ # end
40
+ # end
41
+ # end
42
+ #
43
+ # class PersonRecord < Record
44
+ # set_callback :save, :before, :saving_message
45
+ # def saving_message
46
+ # puts "saving..."
47
+ # end
48
+ #
49
+ # set_callback :save, :after do |object|
50
+ # puts "saved"
51
+ # end
52
+ # end
53
+ #
54
+ # person = PersonRecord.new
55
+ # person.save
56
+ #
57
+ # Output:
58
+ # saving...
59
+ # - save
60
+ # saved
61
+ module Callbacks
62
+ extend Concern
63
+
64
+ included do
65
+ extend ActiveSupport::DescendantsTracker
66
+ end
67
+
68
+ CALLBACK_FILTER_TYPES = [:before, :after, :around]
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
+
76
+ # Runs the callbacks for the given event.
77
+ #
78
+ # Calls the before and around callbacks in the order they were set, yields
79
+ # the block (if given one), and then runs the after callbacks in reverse
80
+ # order.
81
+ #
82
+ # If the callback chain was halted, returns +false+. Otherwise returns the
83
+ # result of the block, +nil+ if no callbacks have been set, or +true+
84
+ # if callbacks have been set but no block is given.
85
+ #
86
+ # run_callbacks :save do
87
+ # save
88
+ # end
89
+ def run_callbacks(kind, &block)
90
+ send "_run_#{kind}_callbacks", &block
91
+ end
92
+
93
+ private
94
+
95
+ def __run_callbacks__(callbacks, &block)
96
+ if callbacks.empty?
97
+ yield if block_given?
98
+ else
99
+ runner = callbacks.compile
100
+ e = Filters::Environment.new(self, false, nil, block)
101
+ runner.call(e).value
102
+ end
103
+ end
104
+
105
+ # A hook invoked every time a before callback is halted.
106
+ # This can be overridden in AS::Callback implementors in order
107
+ # to provide better debugging/logging.
108
+ def halted_callback_hook(filter)
109
+ end
110
+
111
+ module Conditionals # :nodoc:
112
+ class Value
113
+ def initialize(&block)
114
+ @block = block
115
+ end
116
+ def call(target, value); @block.call(value); end
117
+ end
118
+ end
119
+
120
+ module Filters
121
+ Environment = Struct.new(:target, :halted, :value, :run_block)
122
+
123
+ class End
124
+ def call(env)
125
+ block = env.run_block
126
+ env.value = !env.halted && (!block || block.call)
127
+ env
128
+ end
129
+ end
130
+ ENDING = End.new
131
+
132
+ class Before
133
+ def self.build(callback_sequence, user_callback, user_conditions, chain_config, filter)
134
+ halted_lambda = chain_config[:terminator]
135
+
136
+ if user_conditions.any?
137
+ halting_and_conditional(callback_sequence, user_callback, user_conditions, halted_lambda, filter)
138
+ else
139
+ halting(callback_sequence, user_callback, halted_lambda, filter)
140
+ end
141
+ end
142
+
143
+ def self.halting_and_conditional(callback_sequence, user_callback, user_conditions, halted_lambda, filter)
144
+ callback_sequence.before do |env|
145
+ target = env.target
146
+ value = env.value
147
+ halted = env.halted
148
+
149
+ if !halted && user_conditions.all? { |c| c.call(target, value) }
150
+ result_lambda = -> { user_callback.call target, value }
151
+ env.halted = halted_lambda.call(target, result_lambda)
152
+ if env.halted
153
+ target.send :halted_callback_hook, filter
154
+ end
155
+ end
156
+
157
+ env
158
+ end
159
+ end
160
+ private_class_method :halting_and_conditional
161
+
162
+ def self.halting(callback_sequence, user_callback, halted_lambda, filter)
163
+ callback_sequence.before do |env|
164
+ target = env.target
165
+ value = env.value
166
+ halted = env.halted
167
+
168
+ unless halted
169
+ result_lambda = -> { user_callback.call target, value }
170
+ env.halted = halted_lambda.call(target, result_lambda)
171
+
172
+ if env.halted
173
+ target.send :halted_callback_hook, filter
174
+ end
175
+ end
176
+
177
+ env
178
+ end
179
+ end
180
+ private_class_method :halting
181
+ end
182
+
183
+ class After
184
+ def self.build(callback_sequence, user_callback, user_conditions, chain_config)
185
+ if chain_config[:skip_after_callbacks_if_terminated]
186
+ if user_conditions.any?
187
+ halting_and_conditional(callback_sequence, user_callback, user_conditions)
188
+ else
189
+ halting(callback_sequence, user_callback)
190
+ end
191
+ else
192
+ if user_conditions.any?
193
+ conditional callback_sequence, user_callback, user_conditions
194
+ else
195
+ simple callback_sequence, user_callback
196
+ end
197
+ end
198
+ end
199
+
200
+ def self.halting_and_conditional(callback_sequence, user_callback, user_conditions)
201
+ callback_sequence.after do |env|
202
+ target = env.target
203
+ value = env.value
204
+ halted = env.halted
205
+
206
+ if !halted && user_conditions.all? { |c| c.call(target, value) }
207
+ user_callback.call target, value
208
+ end
209
+
210
+ env
211
+ end
212
+ end
213
+ private_class_method :halting_and_conditional
214
+
215
+ def self.halting(callback_sequence, user_callback)
216
+ callback_sequence.after do |env|
217
+ unless env.halted
218
+ user_callback.call env.target, env.value
219
+ end
220
+
221
+ env
222
+ end
223
+ end
224
+ private_class_method :halting
225
+
226
+ def self.conditional(callback_sequence, user_callback, user_conditions)
227
+ callback_sequence.after do |env|
228
+ target = env.target
229
+ value = env.value
230
+
231
+ if user_conditions.all? { |c| c.call(target, value) }
232
+ user_callback.call target, value
233
+ end
234
+
235
+ env
236
+ end
237
+ end
238
+ private_class_method :conditional
239
+
240
+ def self.simple(callback_sequence, user_callback)
241
+ callback_sequence.after do |env|
242
+ user_callback.call env.target, env.value
243
+
244
+ env
245
+ end
246
+ end
247
+ private_class_method :simple
248
+ end
249
+
250
+ class Around
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)
254
+ else
255
+ halting(callback_sequence, user_callback)
256
+ end
257
+ end
258
+
259
+ def self.halting_and_conditional(callback_sequence, user_callback, user_conditions)
260
+ callback_sequence.around do |env, &run|
261
+ target = env.target
262
+ value = env.value
263
+ halted = env.halted
264
+
265
+ if !halted && user_conditions.all? { |c| c.call(target, value) }
266
+ user_callback.call(target, value) {
267
+ run.call.value
268
+ }
269
+ env
270
+ else
271
+ run.call
272
+ end
273
+ end
274
+ end
275
+ private_class_method :halting_and_conditional
276
+
277
+ def self.halting(callback_sequence, user_callback)
278
+ callback_sequence.around do |env, &run|
279
+ target = env.target
280
+ value = env.value
281
+
282
+ if env.halted
283
+ run.call
284
+ else
285
+ user_callback.call(target, value) {
286
+ run.call.value
287
+ }
288
+ env
289
+ end
290
+ end
291
+ end
292
+ private_class_method :halting
293
+ end
294
+ end
295
+
296
+ class Callback #:nodoc:#
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
+
305
+ new chain.name, filter, kind, options, chain.config
306
+ end
307
+
308
+ attr_accessor :kind, :name
309
+ attr_reader :chain_config
310
+
311
+ def initialize(name, filter, kind, options, chain_config)
312
+ @chain_config = chain_config
313
+ @name = name
314
+ @kind = kind
315
+ @filter = filter
316
+ @key = compute_identifier filter
317
+ @if = Array(options[:if])
318
+ @unless = Array(options[:unless])
319
+ end
320
+
321
+ def filter; @key; end
322
+ def raw_filter; @filter; end
323
+
324
+ def merge_conditional_options(chain, if_option:, unless_option:)
325
+ options = {
326
+ :if => @if.dup,
327
+ :unless => @unless.dup
328
+ }
329
+
330
+ options[:if].concat Array(unless_option)
331
+ options[:unless].concat Array(if_option)
332
+
333
+ self.class.build chain, @filter, @kind, options
334
+ end
335
+
336
+ def matches?(_kind, _filter)
337
+ @kind == _kind && filter == _filter
338
+ end
339
+
340
+ def duplicates?(other)
341
+ case @filter
342
+ when Symbol, String
343
+ matches?(other.kind, other.filter)
344
+ else
345
+ false
346
+ end
347
+ end
348
+
349
+ # Wraps code with filter
350
+ def apply(callback_sequence)
351
+ user_conditions = conditions_lambdas
352
+ user_callback = make_lambda @filter
353
+
354
+ case kind
355
+ when :before
356
+ Filters::Before.build(callback_sequence, user_callback, user_conditions, chain_config, @filter)
357
+ when :after
358
+ Filters::After.build(callback_sequence, user_callback, user_conditions, chain_config)
359
+ when :around
360
+ Filters::Around.build(callback_sequence, user_callback, user_conditions, chain_config)
361
+ end
362
+ end
363
+
364
+ private
365
+
366
+ def invert_lambda(l)
367
+ lambda { |*args, &blk| !l.call(*args, &blk) }
368
+ end
369
+
370
+ # Filters support:
371
+ #
372
+ # Symbols:: A method to call.
373
+ # Strings:: Some content to evaluate.
374
+ # Procs:: A proc to call with the object.
375
+ # Objects:: An object with a <tt>before_foo</tt> method on it to call.
376
+ #
377
+ # All of these objects are converted into a lambda and handled
378
+ # the same after this point.
379
+ def make_lambda(filter)
380
+ case filter
381
+ when Symbol
382
+ lambda { |target, _, &blk| target.send filter, &blk }
383
+ when String
384
+ l = eval "lambda { |value| #{filter} }"
385
+ lambda { |target, value| target.instance_exec(value, &l) }
386
+ when Conditionals::Value then filter
387
+ when ::Proc
388
+ if filter.arity > 1
389
+ return lambda { |target, _, &block|
390
+ raise ArgumentError unless block
391
+ target.instance_exec(target, block, &filter)
392
+ }
393
+ end
394
+
395
+ if filter.arity <= 0
396
+ lambda { |target, _| target.instance_exec(&filter) }
397
+ else
398
+ lambda { |target, _| target.instance_exec(target, &filter) }
399
+ end
400
+ else
401
+ scopes = Array(chain_config[:scope])
402
+ method_to_call = scopes.map{ |s| public_send(s) }.join("_")
403
+
404
+ lambda { |target, _, &blk|
405
+ filter.public_send method_to_call, target, &blk
406
+ }
407
+ end
408
+ end
409
+
410
+ def compute_identifier(filter)
411
+ case filter
412
+ when String, ::Proc
413
+ filter.object_id
414
+ else
415
+ filter
416
+ end
417
+ end
418
+
419
+ def conditions_lambdas
420
+ @if.map { |c| make_lambda c } +
421
+ @unless.map { |c| invert_lambda make_lambda c }
422
+ end
423
+ end
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
+
461
+ # An Array with a compile method.
462
+ class CallbackChain #:nodoc:#
463
+ include Enumerable
464
+
465
+ attr_reader :name, :config
466
+
467
+ def initialize(name, config)
468
+ @name = name
469
+ @config = {
470
+ scope: [:kind],
471
+ terminator: default_terminator
472
+ }.merge!(config)
473
+ @chain = []
474
+ @callbacks = nil
475
+ @mutex = Mutex.new
476
+ end
477
+
478
+ def each(&block); @chain.each(&block); end
479
+ def index(o); @chain.index(o); end
480
+ def empty?; @chain.empty?; end
481
+
482
+ def insert(index, o)
483
+ @callbacks = nil
484
+ @chain.insert(index, o)
485
+ end
486
+
487
+ def delete(o)
488
+ @callbacks = nil
489
+ @chain.delete(o)
490
+ end
491
+
492
+ def clear
493
+ @callbacks = nil
494
+ @chain.clear
495
+ self
496
+ end
497
+
498
+ def initialize_copy(other)
499
+ @callbacks = nil
500
+ @chain = other.chain.dup
501
+ @mutex = Mutex.new
502
+ end
503
+
504
+ def compile
505
+ @callbacks || @mutex.synchronize do
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
509
+ end
510
+ end
511
+ end
512
+
513
+ def append(*callbacks)
514
+ callbacks.each { |c| append_one(c) }
515
+ end
516
+
517
+ def prepend(*callbacks)
518
+ callbacks.each { |c| prepend_one(c) }
519
+ end
520
+
521
+ protected
522
+ def chain; @chain; end
523
+
524
+ private
525
+
526
+ def append_one(callback)
527
+ @callbacks = nil
528
+ remove_duplicates(callback)
529
+ @chain.push(callback)
530
+ end
531
+
532
+ def prepend_one(callback)
533
+ @callbacks = nil
534
+ remove_duplicates(callback)
535
+ @chain.unshift(callback)
536
+ end
537
+
538
+ def remove_duplicates(callback)
539
+ @callbacks = nil
540
+ @chain.delete_if { |c| callback.duplicates?(c) }
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
553
+ end
554
+
555
+ module ClassMethods
556
+ def normalize_callback_params(filters, block) # :nodoc:
557
+ type = CALLBACK_FILTER_TYPES.include?(filters.first) ? filters.shift : :before
558
+ options = filters.extract_options!
559
+ filters.unshift(block) if block
560
+ [type, filters, options.dup]
561
+ end
562
+
563
+ # This is used internally to append, prepend and skip callbacks to the
564
+ # CallbackChain.
565
+ def __update_callbacks(name) #:nodoc:
566
+ ([self] + ActiveSupport::DescendantsTracker.descendants(self)).reverse_each do |target|
567
+ chain = target.get_callbacks name
568
+ yield target, chain.dup
569
+ end
570
+ end
571
+
572
+ # Install a callback for the given event.
573
+ #
574
+ # set_callback :save, :before, :before_method
575
+ # set_callback :save, :after, :after_method, if: :condition
576
+ # set_callback :save, :around, ->(r, block) { stuff; result = block.call; stuff }
577
+ #
578
+ # The second argument indicates whether the callback is to be run +:before+,
579
+ # +:after+, or +:around+ the event. If omitted, +:before+ is assumed. This
580
+ # means the first example above can also be written as:
581
+ #
582
+ # set_callback :save, :before_method
583
+ #
584
+ # The callback can be specified as a symbol naming an instance method; as a
585
+ # proc, lambda, or block; as a string to be instance evaluated(deprecated); or as an
586
+ # object that responds to a certain method determined by the <tt>:scope</tt>
587
+ # argument to +define_callbacks+.
588
+ #
589
+ # If a proc, lambda, or block is given, its body is evaluated in the context
590
+ # of the current object. It can also optionally accept the current object as
591
+ # an argument.
592
+ #
593
+ # Before and around callbacks are called in the order that they are set;
594
+ # after callbacks are called in the reverse order.
595
+ #
596
+ # Around callbacks can access the return value from the event, if it
597
+ # wasn't halted, from the +yield+ call.
598
+ #
599
+ # ===== Options
600
+ #
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.
607
+ # * <tt>:prepend</tt> - If +true+, the callback will be prepended to the
608
+ # existing chain rather than appended.
609
+ def set_callback(name, *filter_list, &block)
610
+ type, filters, options = normalize_callback_params(filter_list, block)
611
+ self_chain = get_callbacks name
612
+ mapped = filters.map do |filter|
613
+ Callback.build(self_chain, filter, type, options)
614
+ end
615
+
616
+ __update_callbacks(name) do |target, chain|
617
+ options[:prepend] ? chain.prepend(*mapped) : chain.append(*mapped)
618
+ target.set_callbacks name, chain
619
+ end
620
+ end
621
+
622
+ # Skip a previously set callback. Like +set_callback+, <tt>:if</tt> or
623
+ # <tt>:unless</tt> options may be passed in order to control when the
624
+ # callback is skipped.
625
+ #
626
+ # class Writer < Person
627
+ # skip_callback :validate, :before, :check_membership, if: -> { self.age > 18 }
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>).
632
+ def skip_callback(name, *filter_list, &block)
633
+ type, filters, options = normalize_callback_params(filter_list, block)
634
+ options[:raise] = true unless options.key?(:raise)
635
+
636
+ __update_callbacks(name) do |target, chain|
637
+ filters.each do |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
643
+
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)
647
+ end
648
+
649
+ chain.delete(callback)
650
+ end
651
+ target.set_callbacks name, chain
652
+ end
653
+ end
654
+
655
+ # Remove all set callbacks for the given event.
656
+ def reset_callbacks(name)
657
+ callbacks = get_callbacks name
658
+
659
+ ActiveSupport::DescendantsTracker.descendants(self).each do |target|
660
+ chain = target.get_callbacks(name).dup
661
+ callbacks.each { |c| chain.delete(c) }
662
+ target.set_callbacks name, chain
663
+ end
664
+
665
+ self.set_callbacks name, callbacks.dup.clear
666
+ end
667
+
668
+ # Define sets of events in the object life cycle that support callbacks.
669
+ #
670
+ # define_callbacks :validate
671
+ # define_callbacks :initialize, :save, :destroy
672
+ #
673
+ # ===== Options
674
+ #
675
+ # * <tt>:terminator</tt> - Determines when a before filter will halt the
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.
681
+ #
682
+ # define_callbacks :validate, terminator: ->(target, result_lambda) { result_lambda.call == false }
683
+ #
684
+ # In this example, if any before validate callbacks returns +false+,
685
+ # any successive before and around callback is not executed.
686
+ #
687
+ # The default terminator halts the chain when a callback throws +:abort+.
688
+ #
689
+ # * <tt>:skip_after_callbacks_if_terminated</tt> - Determines if after
690
+ # callbacks should be terminated by the <tt>:terminator</tt> option. By
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>
693
+ # option is specified.
694
+ #
695
+ # * <tt>:scope</tt> - Indicates which methods should be executed when an
696
+ # object is used as a callback.
697
+ #
698
+ # class Audit
699
+ # def before(caller)
700
+ # puts 'Audit: before is called'
701
+ # end
702
+ #
703
+ # def before_save(caller)
704
+ # puts 'Audit: before_save is called'
705
+ # end
706
+ # end
707
+ #
708
+ # class Account
709
+ # include ActiveSupport::Callbacks
710
+ #
711
+ # define_callbacks :save
712
+ # set_callback :save, :before, Audit.new
713
+ #
714
+ # def save
715
+ # run_callbacks :save do
716
+ # puts 'save in main'
717
+ # end
718
+ # end
719
+ # end
720
+ #
721
+ # In the above case whenever you save an account the method
722
+ # <tt>Audit#before</tt> will be called. On the other hand
723
+ #
724
+ # define_callbacks :save, scope: [:kind, :name]
725
+ #
726
+ # would trigger <tt>Audit#before_save</tt> instead. That's constructed
727
+ # by calling <tt>#{kind}_#{name}</tt> on the given instance. In this
728
+ # case "kind" is "before" and "name" is "save". In this context +:kind+
729
+ # and +:name+ have special meanings: +:kind+ refers to the kind of
730
+ # callback (before/after/around) and +:name+ refers to the method on
731
+ # which callbacks are being defined.
732
+ #
733
+ # A declaration like
734
+ #
735
+ # define_callbacks :save, scope: [:name]
736
+ #
737
+ # would call <tt>Audit#save</tt>.
738
+ #
739
+ # NOTE: +method_name+ passed to `define_model_callbacks` must not end with
740
+ # `!`, `?` or `=`.
741
+ def define_callbacks(*names)
742
+ options = names.extract_options!
743
+
744
+ names.each do |name|
745
+ class_attribute "_#{name}_callbacks", instance_writer: false
746
+ set_callbacks name, CallbackChain.new(name, options)
747
+
748
+ module_eval <<-RUBY, __FILE__, __LINE__ + 1
749
+ def _run_#{name}_callbacks(&block)
750
+ __run_callbacks__(_#{name}_callbacks, &block)
751
+ end
752
+ RUBY
753
+ end
754
+ end
755
+
756
+ protected
757
+
758
+ def get_callbacks(name) # :nodoc:
759
+ send "_#{name}_callbacks"
760
+ end
761
+
762
+ def set_callbacks(name, callbacks) # :nodoc:
763
+ send "_#{name}_callbacks=", callbacks
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
789
+ end
790
+ end
791
+ end