activesupport 5.1.6 → 5.2.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 (240) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +325 -576
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +3 -3
  5. data/lib/active_support/all.rb +2 -0
  6. data/lib/active_support/array_inquirer.rb +2 -0
  7. data/lib/active_support/backtrace_cleaner.rb +2 -0
  8. data/lib/active_support/benchmarkable.rb +2 -0
  9. data/lib/active_support/builder.rb +2 -0
  10. data/lib/active_support/cache/file_store.rb +5 -4
  11. data/lib/active_support/cache/mem_cache_store.rb +37 -27
  12. data/lib/active_support/cache/memory_store.rb +2 -0
  13. data/lib/active_support/cache/null_store.rb +2 -0
  14. data/lib/active_support/cache/redis_cache_store.rb +454 -0
  15. data/lib/active_support/cache/strategy/local_cache.rb +33 -2
  16. data/lib/active_support/cache/strategy/local_cache_middleware.rb +2 -0
  17. data/lib/active_support/cache.rb +181 -64
  18. data/lib/active_support/callbacks.rb +28 -39
  19. data/lib/active_support/concern.rb +3 -1
  20. data/lib/active_support/concurrency/share_lock.rb +2 -0
  21. data/lib/active_support/configurable.rb +2 -0
  22. data/lib/active_support/core_ext/array/access.rb +4 -2
  23. data/lib/active_support/core_ext/array/conversions.rb +2 -0
  24. data/lib/active_support/core_ext/array/extract_options.rb +2 -0
  25. data/lib/active_support/core_ext/array/grouping.rb +2 -0
  26. data/lib/active_support/core_ext/array/inquiry.rb +2 -0
  27. data/lib/active_support/core_ext/array/prepend_and_append.rb +4 -2
  28. data/lib/active_support/core_ext/array/wrap.rb +2 -0
  29. data/lib/active_support/core_ext/array.rb +2 -0
  30. data/lib/active_support/core_ext/benchmark.rb +2 -0
  31. data/lib/active_support/core_ext/big_decimal/conversions.rb +2 -0
  32. data/lib/active_support/core_ext/big_decimal.rb +2 -0
  33. data/lib/active_support/core_ext/class/attribute.rb +34 -16
  34. data/lib/active_support/core_ext/class/attribute_accessors.rb +2 -0
  35. data/lib/active_support/core_ext/class/subclasses.rb +1 -2
  36. data/lib/active_support/core_ext/class.rb +2 -0
  37. data/lib/active_support/core_ext/date/acts_like.rb +2 -0
  38. data/lib/active_support/core_ext/date/blank.rb +2 -0
  39. data/lib/active_support/core_ext/date/calculations.rb +2 -0
  40. data/lib/active_support/core_ext/date/conversions.rb +10 -9
  41. data/lib/active_support/core_ext/date/zones.rb +2 -0
  42. data/lib/active_support/core_ext/date.rb +2 -0
  43. data/lib/active_support/core_ext/date_and_time/calculations.rb +50 -16
  44. data/lib/active_support/core_ext/date_and_time/compatibility.rb +3 -1
  45. data/lib/active_support/core_ext/date_and_time/zones.rb +2 -0
  46. data/lib/active_support/core_ext/date_time/acts_like.rb +2 -0
  47. data/lib/active_support/core_ext/date_time/blank.rb +2 -0
  48. data/lib/active_support/core_ext/date_time/calculations.rb +2 -0
  49. data/lib/active_support/core_ext/date_time/compatibility.rb +7 -5
  50. data/lib/active_support/core_ext/date_time/conversions.rb +2 -0
  51. data/lib/active_support/core_ext/date_time.rb +2 -0
  52. data/lib/active_support/core_ext/digest/uuid.rb +3 -1
  53. data/lib/active_support/core_ext/enumerable.rb +3 -1
  54. data/lib/active_support/core_ext/file/atomic.rb +2 -0
  55. data/lib/active_support/core_ext/file.rb +2 -0
  56. data/lib/active_support/core_ext/hash/compact.rb +2 -0
  57. data/lib/active_support/core_ext/hash/conversions.rb +4 -2
  58. data/lib/active_support/core_ext/hash/deep_merge.rb +8 -12
  59. data/lib/active_support/core_ext/hash/except.rb +2 -0
  60. data/lib/active_support/core_ext/hash/indifferent_access.rb +2 -0
  61. data/lib/active_support/core_ext/hash/keys.rb +2 -0
  62. data/lib/active_support/core_ext/hash/reverse_merge.rb +5 -2
  63. data/lib/active_support/core_ext/hash/slice.rb +4 -4
  64. data/lib/active_support/core_ext/hash/transform_values.rb +2 -0
  65. data/lib/active_support/core_ext/hash.rb +2 -0
  66. data/lib/active_support/core_ext/integer/inflections.rb +2 -0
  67. data/lib/active_support/core_ext/integer/multiple.rb +2 -0
  68. data/lib/active_support/core_ext/integer/time.rb +7 -14
  69. data/lib/active_support/core_ext/integer.rb +2 -0
  70. data/lib/active_support/core_ext/kernel/agnostics.rb +2 -0
  71. data/lib/active_support/core_ext/kernel/concern.rb +2 -0
  72. data/lib/active_support/core_ext/kernel/reporting.rb +2 -0
  73. data/lib/active_support/core_ext/kernel/singleton_class.rb +2 -0
  74. data/lib/active_support/core_ext/kernel.rb +2 -0
  75. data/lib/active_support/core_ext/load_error.rb +2 -7
  76. data/lib/active_support/core_ext/marshal.rb +2 -0
  77. data/lib/active_support/core_ext/module/aliasing.rb +2 -0
  78. data/lib/active_support/core_ext/module/anonymous.rb +2 -0
  79. data/lib/active_support/core_ext/module/attr_internal.rb +2 -0
  80. data/lib/active_support/core_ext/module/attribute_accessors.rb +21 -24
  81. data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +2 -0
  82. data/lib/active_support/core_ext/module/concerning.rb +7 -8
  83. data/lib/active_support/core_ext/module/delegation.rb +31 -29
  84. data/lib/active_support/core_ext/module/deprecation.rb +2 -0
  85. data/lib/active_support/core_ext/module/introspection.rb +2 -0
  86. data/lib/active_support/core_ext/module/reachable.rb +3 -0
  87. data/lib/active_support/core_ext/module/redefine_method.rb +49 -0
  88. data/lib/active_support/core_ext/module/remove_method.rb +5 -23
  89. data/lib/active_support/core_ext/module.rb +3 -0
  90. data/lib/active_support/core_ext/name_error.rb +7 -0
  91. data/lib/active_support/core_ext/numeric/bytes.rb +2 -0
  92. data/lib/active_support/core_ext/numeric/conversions.rb +9 -7
  93. data/lib/active_support/core_ext/numeric/inquiry.rb +2 -0
  94. data/lib/active_support/core_ext/numeric/time.rb +7 -15
  95. data/lib/active_support/core_ext/numeric.rb +2 -0
  96. data/lib/active_support/core_ext/object/acts_like.rb +12 -1
  97. data/lib/active_support/core_ext/object/blank.rb +12 -1
  98. data/lib/active_support/core_ext/object/conversions.rb +2 -0
  99. data/lib/active_support/core_ext/object/deep_dup.rb +2 -0
  100. data/lib/active_support/core_ext/object/duplicable.rb +10 -8
  101. data/lib/active_support/core_ext/object/inclusion.rb +2 -0
  102. data/lib/active_support/core_ext/object/instance_variables.rb +2 -0
  103. data/lib/active_support/core_ext/object/json.rb +8 -0
  104. data/lib/active_support/core_ext/object/to_param.rb +2 -0
  105. data/lib/active_support/core_ext/object/to_query.rb +2 -0
  106. data/lib/active_support/core_ext/object/try.rb +2 -0
  107. data/lib/active_support/core_ext/object/with_options.rb +3 -1
  108. data/lib/active_support/core_ext/object.rb +2 -0
  109. data/lib/active_support/core_ext/range/conversions.rb +9 -1
  110. data/lib/active_support/core_ext/range/each.rb +5 -1
  111. data/lib/active_support/core_ext/range/include_range.rb +2 -0
  112. data/lib/active_support/core_ext/range/include_time_with_zone.rb +23 -0
  113. data/lib/active_support/core_ext/range/overlaps.rb +2 -0
  114. data/lib/active_support/core_ext/range.rb +3 -0
  115. data/lib/active_support/core_ext/regexp.rb +2 -0
  116. data/lib/active_support/core_ext/securerandom.rb +2 -0
  117. data/lib/active_support/core_ext/string/access.rb +2 -0
  118. data/lib/active_support/core_ext/string/behavior.rb +2 -0
  119. data/lib/active_support/core_ext/string/conversions.rb +2 -0
  120. data/lib/active_support/core_ext/string/exclude.rb +2 -0
  121. data/lib/active_support/core_ext/string/filters.rb +2 -0
  122. data/lib/active_support/core_ext/string/indent.rb +2 -0
  123. data/lib/active_support/core_ext/string/inflections.rb +26 -12
  124. data/lib/active_support/core_ext/string/inquiry.rb +2 -0
  125. data/lib/active_support/core_ext/string/multibyte.rb +4 -0
  126. data/lib/active_support/core_ext/string/output_safety.rb +6 -7
  127. data/lib/active_support/core_ext/string/starts_ends_with.rb +2 -0
  128. data/lib/active_support/core_ext/string/strip.rb +2 -0
  129. data/lib/active_support/core_ext/string/zones.rb +2 -0
  130. data/lib/active_support/core_ext/string.rb +2 -0
  131. data/lib/active_support/core_ext/time/acts_like.rb +2 -0
  132. data/lib/active_support/core_ext/time/calculations.rb +23 -15
  133. data/lib/active_support/core_ext/time/compatibility.rb +4 -2
  134. data/lib/active_support/core_ext/time/conversions.rb +2 -0
  135. data/lib/active_support/core_ext/time/zones.rb +6 -4
  136. data/lib/active_support/core_ext/time.rb +2 -0
  137. data/lib/active_support/core_ext/uri.rb +4 -1
  138. data/lib/active_support/core_ext.rb +3 -1
  139. data/lib/active_support/current_attributes.rb +195 -0
  140. data/lib/active_support/dependencies/autoload.rb +2 -0
  141. data/lib/active_support/dependencies/interlock.rb +2 -0
  142. data/lib/active_support/dependencies.rb +16 -25
  143. data/lib/active_support/deprecation/behaviors.rb +24 -9
  144. data/lib/active_support/deprecation/constant_accessor.rb +4 -2
  145. data/lib/active_support/deprecation/instance_delegator.rb +2 -0
  146. data/lib/active_support/deprecation/method_wrappers.rb +8 -8
  147. data/lib/active_support/deprecation/proxy_wrappers.rb +5 -2
  148. data/lib/active_support/deprecation/reporting.rb +5 -3
  149. data/lib/active_support/deprecation.rb +4 -2
  150. data/lib/active_support/descendants_tracker.rb +2 -0
  151. data/lib/active_support/digest.rb +20 -0
  152. data/lib/active_support/duration/iso8601_parser.rb +4 -2
  153. data/lib/active_support/duration/iso8601_serializer.rb +4 -2
  154. data/lib/active_support/duration.rb +11 -7
  155. data/lib/active_support/encrypted_configuration.rb +49 -0
  156. data/lib/active_support/encrypted_file.rb +99 -0
  157. data/lib/active_support/evented_file_update_checker.rb +2 -0
  158. data/lib/active_support/execution_wrapper.rb +2 -0
  159. data/lib/active_support/executor.rb +2 -0
  160. data/lib/active_support/file_update_checker.rb +2 -0
  161. data/lib/active_support/gem_version.rb +4 -2
  162. data/lib/active_support/gzip.rb +2 -0
  163. data/lib/active_support/hash_with_indifferent_access.rb +41 -1
  164. data/lib/active_support/i18n.rb +3 -1
  165. data/lib/active_support/i18n_railtie.rb +4 -6
  166. data/lib/active_support/inflections.rb +2 -0
  167. data/lib/active_support/inflector/inflections.rb +20 -4
  168. data/lib/active_support/inflector/methods.rb +41 -24
  169. data/lib/active_support/inflector/transliterate.rb +17 -8
  170. data/lib/active_support/inflector.rb +2 -0
  171. data/lib/active_support/json/decoding.rb +2 -0
  172. data/lib/active_support/json/encoding.rb +2 -0
  173. data/lib/active_support/json.rb +2 -0
  174. data/lib/active_support/key_generator.rb +3 -1
  175. data/lib/active_support/lazy_load_hooks.rb +2 -0
  176. data/lib/active_support/log_subscriber/test_helper.rb +2 -0
  177. data/lib/active_support/log_subscriber.rb +3 -2
  178. data/lib/active_support/logger.rb +2 -0
  179. data/lib/active_support/logger_silence.rb +3 -2
  180. data/lib/active_support/logger_thread_safe_level.rb +2 -0
  181. data/lib/active_support/message_encryptor.rb +95 -22
  182. data/lib/active_support/message_verifier.rb +78 -7
  183. data/lib/active_support/messages/metadata.rb +71 -0
  184. data/lib/active_support/messages/rotation_configuration.rb +22 -0
  185. data/lib/active_support/messages/rotator.rb +56 -0
  186. data/lib/active_support/multibyte/chars.rb +2 -0
  187. data/lib/active_support/multibyte/unicode.rb +4 -2
  188. data/lib/active_support/multibyte.rb +2 -0
  189. data/lib/active_support/notifications/fanout.rb +2 -0
  190. data/lib/active_support/notifications/instrumenter.rb +2 -0
  191. data/lib/active_support/notifications.rb +2 -0
  192. data/lib/active_support/number_helper/number_converter.rb +2 -0
  193. data/lib/active_support/number_helper/number_to_currency_converter.rb +2 -0
  194. data/lib/active_support/number_helper/number_to_delimited_converter.rb +2 -0
  195. data/lib/active_support/number_helper/number_to_human_converter.rb +2 -0
  196. data/lib/active_support/number_helper/number_to_human_size_converter.rb +2 -0
  197. data/lib/active_support/number_helper/number_to_percentage_converter.rb +2 -0
  198. data/lib/active_support/number_helper/number_to_phone_converter.rb +3 -1
  199. data/lib/active_support/number_helper/number_to_rounded_converter.rb +2 -20
  200. data/lib/active_support/number_helper/rounding_helper.rb +6 -4
  201. data/lib/active_support/number_helper.rb +2 -0
  202. data/lib/active_support/option_merger.rb +2 -0
  203. data/lib/active_support/ordered_hash.rb +2 -0
  204. data/lib/active_support/ordered_options.rb +4 -2
  205. data/lib/active_support/per_thread_registry.rb +2 -0
  206. data/lib/active_support/proxy_object.rb +2 -0
  207. data/lib/active_support/rails.rb +2 -0
  208. data/lib/active_support/railtie.rb +37 -8
  209. data/lib/active_support/reloader.rb +7 -5
  210. data/lib/active_support/rescuable.rb +3 -2
  211. data/lib/active_support/security_utils.rb +15 -11
  212. data/lib/active_support/string_inquirer.rb +2 -0
  213. data/lib/active_support/subscriber.rb +2 -0
  214. data/lib/active_support/tagged_logging.rb +2 -0
  215. data/lib/active_support/test_case.rb +2 -1
  216. data/lib/active_support/testing/assertions.rb +31 -14
  217. data/lib/active_support/testing/autorun.rb +2 -0
  218. data/lib/active_support/testing/constant_lookup.rb +2 -0
  219. data/lib/active_support/testing/declarative.rb +2 -0
  220. data/lib/active_support/testing/deprecation.rb +2 -0
  221. data/lib/active_support/testing/file_fixtures.rb +2 -0
  222. data/lib/active_support/testing/isolation.rb +3 -1
  223. data/lib/active_support/testing/method_call_assertions.rb +2 -0
  224. data/lib/active_support/testing/setup_and_teardown.rb +10 -1
  225. data/lib/active_support/testing/stream.rb +2 -0
  226. data/lib/active_support/testing/tagged_logging.rb +2 -0
  227. data/lib/active_support/testing/time_helpers.rb +33 -3
  228. data/lib/active_support/time.rb +2 -0
  229. data/lib/active_support/time_with_zone.rb +38 -0
  230. data/lib/active_support/values/time_zone.rb +19 -8
  231. data/lib/active_support/version.rb +2 -0
  232. data/lib/active_support/xml_mini/jdom.rb +4 -2
  233. data/lib/active_support/xml_mini/libxml.rb +3 -1
  234. data/lib/active_support/xml_mini/libxmlsax.rb +4 -2
  235. data/lib/active_support/xml_mini/nokogiri.rb +3 -1
  236. data/lib/active_support/xml_mini/nokogirisax.rb +3 -1
  237. data/lib/active_support/xml_mini/rexml.rb +3 -1
  238. data/lib/active_support/xml_mini.rb +3 -1
  239. data/lib/active_support.rb +5 -13
  240. metadata +15 -5
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "zlib"
2
4
  require "active_support/core_ext/array/extract_options"
3
5
  require "active_support/core_ext/array/wrap"
@@ -10,10 +12,11 @@ require "active_support/core_ext/string/inflections"
10
12
  module ActiveSupport
11
13
  # See ActiveSupport::Cache::Store for documentation.
12
14
  module Cache
13
- autoload :FileStore, "active_support/cache/file_store"
14
- autoload :MemoryStore, "active_support/cache/memory_store"
15
- autoload :MemCacheStore, "active_support/cache/mem_cache_store"
16
- autoload :NullStore, "active_support/cache/null_store"
15
+ autoload :FileStore, "active_support/cache/file_store"
16
+ autoload :MemoryStore, "active_support/cache/memory_store"
17
+ autoload :MemCacheStore, "active_support/cache/mem_cache_store"
18
+ autoload :NullStore, "active_support/cache/null_store"
19
+ autoload :RedisCacheStore, "active_support/cache/redis_cache_store"
17
20
 
18
21
  # These options mean something to all cache implementations. Individual cache
19
22
  # implementations may support additional options.
@@ -75,7 +78,7 @@ module ActiveSupport
75
78
  #
76
79
  # The +key+ argument can also respond to +cache_key+ or +to_param+.
77
80
  def expand_cache_key(key, namespace = nil)
78
- expanded_cache_key = namespace ? "#{namespace}/" : ""
81
+ expanded_cache_key = (namespace ? "#{namespace}/" : "").dup
79
82
 
80
83
  if prefix = ENV["RAILS_CACHE_ID"] || ENV["RAILS_APP_VERSION"]
81
84
  expanded_cache_key << "#{prefix}/"
@@ -88,16 +91,19 @@ module ActiveSupport
88
91
  private
89
92
  def retrieve_cache_key(key)
90
93
  case
91
- when key.respond_to?(:cache_key) then key.cache_key
92
- when key.is_a?(Array) then key.map { |element| retrieve_cache_key(element) }.to_param
93
- when key.respond_to?(:to_a) then retrieve_cache_key(key.to_a)
94
- else key.to_param
94
+ when key.respond_to?(:cache_key_with_version) then key.cache_key_with_version
95
+ when key.respond_to?(:cache_key) then key.cache_key
96
+ when key.is_a?(Array) then key.map { |element| retrieve_cache_key(element) }.to_param
97
+ when key.respond_to?(:to_a) then retrieve_cache_key(key.to_a)
98
+ else key.to_param
95
99
  end.to_s
96
100
  end
97
101
 
98
102
  # Obtains the specified cache store class, given the name of the +store+.
99
103
  # Raises an error when the store class cannot be found.
100
104
  def retrieve_store_class(store)
105
+ # require_relative cannot be used here because the class might be
106
+ # provided by another gem, like redis-activesupport for example.
101
107
  require "active_support/cache/#{store}"
102
108
  rescue LoadError => e
103
109
  raise "Could not find cache store adapter for #{store} (#{e})"
@@ -143,18 +149,34 @@ module ActiveSupport
143
149
  # cache.namespace = -> { @last_mod_time } # Set the namespace to a variable
144
150
  # @last_mod_time = Time.now # Invalidate the entire cache by changing namespace
145
151
  #
146
- # Caches can also store values in a compressed format to save space and
147
- # reduce time spent sending data. Since there is overhead, values must be
148
- # large enough to warrant compression. To turn on compression either pass
149
- # <tt>compress: true</tt> in the initializer or as an option to +fetch+
150
- # or +write+. To specify the threshold at which to compress values, set the
151
- # <tt>:compress_threshold</tt> option. The default threshold is 16K.
152
+ # Cached data larger than 1kB are compressed by default. To turn off
153
+ # compression, pass <tt>compress: false</tt> to the initializer or to
154
+ # individual +fetch+ or +write+ method calls. The 1kB compression
155
+ # threshold is configurable with the <tt>:compress_threshold</tt> option,
156
+ # specified in bytes.
152
157
  class Store
153
158
  cattr_accessor :logger, instance_writer: true
154
159
 
155
160
  attr_reader :silence, :options
156
161
  alias :silence? :silence
157
162
 
163
+ class << self
164
+ private
165
+ def retrieve_pool_options(options)
166
+ {}.tap do |pool_options|
167
+ pool_options[:size] = options.delete(:pool_size) if options[:pool_size]
168
+ pool_options[:timeout] = options.delete(:pool_timeout) if options[:pool_timeout]
169
+ end
170
+ end
171
+
172
+ def ensure_connection_pool_added!
173
+ require "connection_pool"
174
+ rescue LoadError => e
175
+ $stderr.puts "You don't have connection_pool installed in your application. Please add it to your Gemfile and run bundle install"
176
+ raise e
177
+ end
178
+ end
179
+
158
180
  # Creates a new cache. The options will be passed to any write method calls
159
181
  # except for <tt>:namespace</tt> which can be used to set the global
160
182
  # namespace for the cache.
@@ -207,8 +229,7 @@ module ActiveSupport
207
229
  # ask whether you should force a cache write. Otherwise, it's clearer to
208
230
  # just call <tt>Cache#write</tt>.
209
231
  #
210
- # Setting <tt>:compress</tt> will store a large cache entry set by the call
211
- # in a compressed format.
232
+ # Setting <tt>compress: false</tt> disables compression of the cache entry.
212
233
  #
213
234
  # Setting <tt>:expires_in</tt> will set an expiration time on the cache.
214
235
  # All caches support auto-expiring content after a specified number of
@@ -219,6 +240,10 @@ module ActiveSupport
219
240
  # cache = ActiveSupport::Cache::MemoryStore.new(expires_in: 5.minutes)
220
241
  # cache.write(key, value, expires_in: 1.minute) # Set a lower value for one entry
221
242
  #
243
+ # Setting <tt>:version</tt> verifies the cache stored under <tt>name</tt>
244
+ # is of the same version. nil is returned on mismatches despite contents.
245
+ # This feature is used to support recyclable cache keys.
246
+ #
222
247
  # Setting <tt>:race_condition_ttl</tt> is very useful in situations where
223
248
  # a cache entry is used very frequently and is under heavy load. If a
224
249
  # cache expires and due to heavy load several different processes will try
@@ -287,6 +312,7 @@ module ActiveSupport
287
312
  instrument(:read, name, options) do |payload|
288
313
  cached_entry = read_entry(key, options) unless options[:force]
289
314
  entry = handle_expired_entry(cached_entry, key, options)
315
+ entry = nil if entry && entry.mismatched?(normalize_version(name, options))
290
316
  payload[:super_operation] = :fetch if payload
291
317
  payload[:hit] = !!entry if payload
292
318
  end
@@ -303,21 +329,30 @@ module ActiveSupport
303
329
  end
304
330
  end
305
331
 
306
- # Fetches data from the cache, using the given key. If there is data in
332
+ # Reads data from the cache, using the given key. If there is data in
307
333
  # the cache with the given key, then that data is returned. Otherwise,
308
334
  # +nil+ is returned.
309
335
  #
336
+ # Note, if data was written with the <tt>:expires_in<tt> or <tt>:version</tt> options,
337
+ # both of these conditions are applied before the data is returned.
338
+ #
310
339
  # Options are passed to the underlying cache implementation.
311
340
  def read(name, options = nil)
312
341
  options = merged_options(options)
313
- key = normalize_key(name, options)
342
+ key = normalize_key(name, options)
343
+ version = normalize_version(name, options)
344
+
314
345
  instrument(:read, name, options) do |payload|
315
346
  entry = read_entry(key, options)
347
+
316
348
  if entry
317
349
  if entry.expired?
318
350
  delete_entry(key, options)
319
351
  payload[:hit] = false if payload
320
352
  nil
353
+ elsif entry.mismatched?(version)
354
+ payload[:hit] = false if payload
355
+ nil
321
356
  else
322
357
  payload[:hit] = true if payload
323
358
  entry.value
@@ -339,19 +374,24 @@ module ActiveSupport
339
374
  options = names.extract_options!
340
375
  options = merged_options(options)
341
376
 
342
- results = {}
343
- names.each do |name|
344
- key = normalize_key(name, options)
345
- entry = read_entry(key, options)
346
- if entry
347
- if entry.expired?
348
- delete_entry(key, options)
349
- else
350
- results[name] = entry.value
351
- end
377
+ instrument :read_multi, names, options do |payload|
378
+ read_multi_entries(names, options).tap do |results|
379
+ payload[:hits] = results.keys
380
+ end
381
+ end
382
+ end
383
+
384
+ # Cache Storage API to write multiple values at once.
385
+ def write_multi(hash, options = nil)
386
+ options = merged_options(options)
387
+
388
+ instrument :write_multi, hash, options do |payload|
389
+ entries = hash.each_with_object({}) do |(name, value), memo|
390
+ memo[normalize_key(name, options)] = Entry.new(value, options.merge(version: normalize_version(name, options)))
352
391
  end
392
+
393
+ write_multi_entries entries, options
353
394
  end
354
- results
355
395
  end
356
396
 
357
397
  # Fetches data from the cache, using the given keys. If there is data in
@@ -378,13 +418,19 @@ module ActiveSupport
378
418
 
379
419
  options = names.extract_options!
380
420
  options = merged_options(options)
381
- results = read_multi(*names, options)
382
421
 
383
- names.each_with_object({}) do |name, memo|
384
- memo[name] = results.fetch(name) do
385
- value = yield name
386
- write(name, value, options)
387
- value
422
+ instrument :read_multi, names, options do |payload|
423
+ read_multi_entries(names, options).tap do |results|
424
+ payload[:hits] = results.keys
425
+ payload[:super_operation] = :fetch_multi
426
+
427
+ writes = {}
428
+
429
+ (names - results.keys).each do |name|
430
+ results[name] = writes[name] = yield(name)
431
+ end
432
+
433
+ write_multi writes, options
388
434
  end
389
435
  end
390
436
  end
@@ -396,7 +442,7 @@ module ActiveSupport
396
442
  options = merged_options(options)
397
443
 
398
444
  instrument(:write, name, options) do
399
- entry = Entry.new(value, options)
445
+ entry = Entry.new(value, options.merge(version: normalize_version(name, options)))
400
446
  write_entry(normalize_key(name, options), entry, options)
401
447
  end
402
448
  end
@@ -420,7 +466,7 @@ module ActiveSupport
420
466
 
421
467
  instrument(:exist?, name) do
422
468
  entry = read_entry(normalize_key(name, options), options)
423
- (entry && !entry.expired?) || false
469
+ (entry && !entry.expired? && !entry.mismatched?(normalize_version(name, options))) || false
424
470
  end
425
471
  end
426
472
 
@@ -502,6 +548,36 @@ module ActiveSupport
502
548
  raise NotImplementedError.new
503
549
  end
504
550
 
551
+ # Reads multiple entries from the cache implementation. Subclasses MAY
552
+ # implement this method.
553
+ def read_multi_entries(names, options)
554
+ results = {}
555
+ names.each do |name|
556
+ key = normalize_key(name, options)
557
+ version = normalize_version(name, options)
558
+ entry = read_entry(key, options)
559
+
560
+ if entry
561
+ if entry.expired?
562
+ delete_entry(key, options)
563
+ elsif entry.mismatched?(version)
564
+ # Skip mismatched versions
565
+ else
566
+ results[name] = entry.value
567
+ end
568
+ end
569
+ end
570
+ results
571
+ end
572
+
573
+ # Writes multiple entries to the cache implementation. Subclasses MAY
574
+ # implement this method.
575
+ def write_multi_entries(hash, options)
576
+ hash.each do |key, entry|
577
+ write_entry key, entry, options
578
+ end
579
+ end
580
+
505
581
  # Deletes an entry from the cache implementation. Subclasses must
506
582
  # implement this method.
507
583
  def delete_entry(key, options)
@@ -517,6 +593,36 @@ module ActiveSupport
517
593
  end
518
594
  end
519
595
 
596
+ # Expands and namespaces the cache key. May be overridden by
597
+ # cache stores to do additional normalization.
598
+ def normalize_key(key, options = nil)
599
+ namespace_key expanded_key(key), options
600
+ end
601
+
602
+ # Prefix the key with a namespace string:
603
+ #
604
+ # namespace_key 'foo', namespace: 'cache'
605
+ # # => 'cache:foo'
606
+ #
607
+ # With a namespace block:
608
+ #
609
+ # namespace_key 'foo', namespace: -> { 'cache' }
610
+ # # => 'cache:foo'
611
+ def namespace_key(key, options = nil)
612
+ options = merged_options(options)
613
+ namespace = options[:namespace]
614
+
615
+ if namespace.respond_to?(:call)
616
+ namespace = namespace.call
617
+ end
618
+
619
+ if namespace
620
+ "#{namespace}:#{key}"
621
+ else
622
+ key
623
+ end
624
+ end
625
+
520
626
  # Expands key to be a consistent string value. Invokes +cache_key+ if
521
627
  # object responds to +cache_key+. Otherwise, +to_param+ method will be
522
628
  # called. If the key is a Hash, then keys will be sorted alphabetically.
@@ -537,14 +643,16 @@ module ActiveSupport
537
643
  key.to_param
538
644
  end
539
645
 
540
- # Prefixes a key with the namespace. Namespace and key will be delimited
541
- # with a colon.
542
- def normalize_key(key, options)
543
- key = expanded_key(key)
544
- namespace = options[:namespace] if options
545
- prefix = namespace.is_a?(Proc) ? namespace.call : namespace
546
- key = "#{prefix}:#{key}" if prefix
547
- key
646
+ def normalize_version(key, options = nil)
647
+ (options && options[:version].try(:to_param)) || expanded_version(key)
648
+ end
649
+
650
+ def expanded_version(key)
651
+ case
652
+ when key.respond_to?(:cache_version) then key.cache_version.to_param
653
+ when key.is_a?(Array) then key.map { |element| expanded_version(element) }.compact.to_param
654
+ when key.respond_to?(:to_a) then expanded_version(key.to_a)
655
+ end
548
656
  end
549
657
 
550
658
  def instrument(operation, key, options = nil)
@@ -591,25 +699,27 @@ module ActiveSupport
591
699
  end
592
700
  end
593
701
 
594
- # This class is used to represent cache entries. Cache entries have a value and an optional
595
- # expiration time. The expiration time is used to support the :race_condition_ttl option
596
- # on the cache.
702
+ # This class is used to represent cache entries. Cache entries have a value, an optional
703
+ # expiration time, and an optional version. The expiration time is used to support the :race_condition_ttl option
704
+ # on the cache. The version is used to support the :version option on the cache for rejecting
705
+ # mismatches.
597
706
  #
598
707
  # Since cache entries in most instances will be serialized, the internals of this class are highly optimized
599
708
  # using short instance variable names that are lazily defined.
600
709
  class Entry # :nodoc:
601
- DEFAULT_COMPRESS_LIMIT = 16.kilobytes
710
+ attr_reader :version
711
+
712
+ DEFAULT_COMPRESS_LIMIT = 1.kilobyte
602
713
 
603
714
  # Creates a new cache entry for the specified value. Options supported are
604
715
  # +:compress+, +:compress_threshold+, and +:expires_in+.
605
716
  def initialize(value, options = {})
606
- if should_compress?(value, options)
607
- @value = compress(value)
608
- @compressed = true
609
- else
610
- @value = value
717
+ @value = value
718
+ if should_compress?(options)
719
+ compress!
611
720
  end
612
721
 
722
+ @version = options[:version]
613
723
  @created_at = Time.now.to_f
614
724
  @expires_in = options[:expires_in]
615
725
  @expires_in = @expires_in.to_f if @expires_in
@@ -619,6 +729,10 @@ module ActiveSupport
619
729
  compressed? ? uncompress(@value) : @value
620
730
  end
621
731
 
732
+ def mismatched?(version)
733
+ @version && version && @version != version
734
+ end
735
+
622
736
  # Checks if the entry is expired. The +expires_in+ parameter can override
623
737
  # the value set when the entry was created.
624
738
  def expired?
@@ -667,28 +781,31 @@ module ActiveSupport
667
781
  end
668
782
 
669
783
  private
670
- def should_compress?(value, options)
671
- if value && options[:compress]
672
- compress_threshold = options[:compress_threshold] || DEFAULT_COMPRESS_LIMIT
673
- serialized_value_size = (value.is_a?(String) ? value : Marshal.dump(value)).bytesize
784
+ def should_compress?(options)
785
+ if @value && options.fetch(:compress, true)
786
+ compress_threshold = options.fetch(:compress_threshold, DEFAULT_COMPRESS_LIMIT)
787
+ serialized_value_size = (@value.is_a?(String) ? @value : marshaled_value).bytesize
674
788
 
675
- return true if serialized_value_size >= compress_threshold
789
+ serialized_value_size >= compress_threshold
676
790
  end
677
-
678
- false
679
791
  end
680
792
 
681
793
  def compressed?
682
794
  defined?(@compressed) ? @compressed : false
683
795
  end
684
796
 
685
- def compress(value)
686
- Zlib::Deflate.deflate(Marshal.dump(value))
797
+ def compress!
798
+ @value = Zlib::Deflate.deflate(marshaled_value)
799
+ @compressed = true
687
800
  end
688
801
 
689
802
  def uncompress(value)
690
803
  Marshal.load(Zlib::Inflate.inflate(value))
691
804
  end
805
+
806
+ def marshaled_value
807
+ @marshaled_value ||= Marshal.dump(@value)
808
+ end
692
809
  end
693
810
  end
694
811
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "active_support/concern"
2
4
  require "active_support/descendants_tracker"
3
5
  require "active_support/core_ext/array/extract_options"
@@ -62,8 +64,7 @@ module ActiveSupport
62
64
 
63
65
  included do
64
66
  extend ActiveSupport::DescendantsTracker
65
- class_attribute :__callbacks, instance_writer: false
66
- self.__callbacks ||= {}
67
+ class_attribute :__callbacks, instance_writer: false, default: {}
67
68
  end
68
69
 
69
70
  CALLBACK_FILTER_TYPES = [:before, :after, :around]
@@ -297,8 +298,8 @@ module ActiveSupport
297
298
  @kind = kind
298
299
  @filter = filter
299
300
  @key = compute_identifier filter
300
- @if = Array(options[:if])
301
- @unless = Array(options[:unless])
301
+ @if = check_conditionals(Array(options[:if]))
302
+ @unless = check_conditionals(Array(options[:unless]))
302
303
  end
303
304
 
304
305
  def filter; @key; end
@@ -322,7 +323,7 @@ module ActiveSupport
322
323
 
323
324
  def duplicates?(other)
324
325
  case @filter
325
- when Symbol, String
326
+ when Symbol
326
327
  matches?(other.kind, other.filter)
327
328
  else
328
329
  false
@@ -349,9 +350,21 @@ module ActiveSupport
349
350
  end
350
351
 
351
352
  private
353
+ def check_conditionals(conditionals)
354
+ if conditionals.any? { |c| c.is_a?(String) }
355
+ raise ArgumentError, <<-MSG.squish
356
+ Passing string to be evaluated in :if and :unless conditional
357
+ options is not supported. Pass a symbol for an instance method,
358
+ or a lambda, proc or block, instead.
359
+ MSG
360
+ end
361
+
362
+ conditionals
363
+ end
364
+
352
365
  def compute_identifier(filter)
353
366
  case filter
354
- when String, ::Proc
367
+ when ::Proc
355
368
  filter.object_id
356
369
  else
357
370
  filter
@@ -426,7 +439,6 @@ module ActiveSupport
426
439
  # Filters support:
427
440
  #
428
441
  # Symbols:: A method to call.
429
- # Strings:: Some content to evaluate.
430
442
  # Procs:: A proc to call with the object.
431
443
  # Objects:: An object with a <tt>before_foo</tt> method on it to call.
432
444
  #
@@ -436,8 +448,6 @@ module ActiveSupport
436
448
  case filter
437
449
  when Symbol
438
450
  new(nil, filter, [], nil)
439
- when String
440
- new(nil, :instance_exec, [:value], compile_lambda(filter))
441
451
  when Conditionals::Value
442
452
  new(filter, :call, [:target, :value], nil)
443
453
  when ::Proc
@@ -454,10 +464,6 @@ module ActiveSupport
454
464
  new(filter, method_to_call, [:target], nil)
455
465
  end
456
466
  end
457
-
458
- def self.compile_lambda(filter)
459
- eval("lambda { |value| #{filter} }")
460
- end
461
467
  end
462
468
 
463
469
  # Execute before and after filters in a sequence instead of
@@ -512,7 +518,6 @@ module ActiveSupport
512
518
  end
513
519
  end
514
520
 
515
- # An Array with a compile method.
516
521
  class CallbackChain #:nodoc:#
517
522
  include Enumerable
518
523
 
@@ -598,7 +603,7 @@ module ActiveSupport
598
603
  Proc.new do |target, result_lambda|
599
604
  terminate = true
600
605
  catch(:abort) do
601
- result_lambda.call if result_lambda.is_a?(Proc)
606
+ result_lambda.call
602
607
  terminate = false
603
608
  end
604
609
  terminate
@@ -651,26 +656,17 @@ module ActiveSupport
651
656
  #
652
657
  # ===== Options
653
658
  #
654
- # * <tt>:if</tt> - A symbol, a string (deprecated) or an array of symbols,
655
- # each naming an instance method or a proc; the callback will be called
656
- # only when they all return a true value.
657
- # * <tt>:unless</tt> - A symbol, a string (deprecated) or an array of symbols,
658
- # each naming an instance method or a proc; the callback will be called
659
- # only when they all return a false value.
659
+ # * <tt>:if</tt> - A symbol or an array of symbols, each naming an instance
660
+ # method or a proc; the callback will be called only when they all return
661
+ # a true value.
662
+ # * <tt>:unless</tt> - A symbol or an array of symbols, each naming an
663
+ # instance method or a proc; the callback will be called only when they
664
+ # all return a false value.
660
665
  # * <tt>:prepend</tt> - If +true+, the callback will be prepended to the
661
666
  # existing chain rather than appended.
662
667
  def set_callback(name, *filter_list, &block)
663
668
  type, filters, options = normalize_callback_params(filter_list, block)
664
669
 
665
- if options[:if].is_a?(String) || options[:unless].is_a?(String)
666
- ActiveSupport::Deprecation.warn(<<-MSG.squish)
667
- Passing string to be evaluated in :if and :unless conditional
668
- options is deprecated and will be removed in Rails 5.2 without
669
- replacement. Pass a symbol for an instance method, or a lambda,
670
- proc or block, instead.
671
- MSG
672
- end
673
-
674
670
  self_chain = get_callbacks name
675
671
  mapped = filters.map do |filter|
676
672
  Callback.build(self_chain, filter, type, options)
@@ -695,13 +691,6 @@ module ActiveSupport
695
691
  def skip_callback(name, *filter_list, &block)
696
692
  type, filters, options = normalize_callback_params(filter_list, block)
697
693
 
698
- if options[:if].is_a?(String) || options[:unless].is_a?(String)
699
- ActiveSupport::Deprecation.warn(<<-MSG.squish)
700
- Passing string to :if and :unless conditional options is deprecated
701
- and will be removed in Rails 5.2 without replacement.
702
- MSG
703
- end
704
-
705
694
  options[:raise] = true unless options.key?(:raise)
706
695
 
707
696
  __update_callbacks(name) do |target, chain|
@@ -760,8 +749,8 @@ module ActiveSupport
760
749
  # * <tt>:skip_after_callbacks_if_terminated</tt> - Determines if after
761
750
  # callbacks should be terminated by the <tt>:terminator</tt> option. By
762
751
  # default after callbacks are executed no matter if callback chain was
763
- # terminated or not. This option makes sense only when <tt>:terminator</tt>
764
- # option is specified.
752
+ # terminated or not. This option has no effect if <tt>:terminator</tt>
753
+ # option is set to +nil+.
765
754
  #
766
755
  # * <tt>:scope</tt> - Indicates which methods should be executed when an
767
756
  # object is used as a callback.
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveSupport
2
4
  # A typical module looks like this:
3
5
  #
@@ -111,7 +113,7 @@ module ActiveSupport
111
113
  def append_features(base)
112
114
  if base.instance_variable_defined?(:@_dependencies)
113
115
  base.instance_variable_get(:@_dependencies) << self
114
- return false
116
+ false
115
117
  else
116
118
  return false if base < self
117
119
  @_dependencies.each { |dep| base.include(dep) }
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "thread"
2
4
  require "monitor"
3
5
 
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "active_support/concern"
2
4
  require "active_support/ordered_options"
3
5
  require "active_support/core_ext/array/extract_options"
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class Array
2
4
  # Returns the tail of the array from +position+.
3
5
  #
@@ -33,8 +35,8 @@ class Array
33
35
  # people.without "Aaron", "Todd"
34
36
  # # => ["David", "Rafael"]
35
37
  #
36
- # Note: This is an optimization of `Enumerable#without` that uses `Array#-`
37
- # instead of `Array#reject` for performance reasons.
38
+ # Note: This is an optimization of <tt>Enumerable#without</tt> that uses <tt>Array#-</tt>
39
+ # instead of <tt>Array#reject</tt> for performance reasons.
38
40
  def without(*elements)
39
41
  self - elements
40
42
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "active_support/xml_mini"
2
4
  require "active_support/core_ext/hash/keys"
3
5
  require "active_support/core_ext/string/inflections"
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class Hash
2
4
  # By default, only instances of Hash itself are extractable.
3
5
  # Subclasses of Hash may implement this method and return
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class Array
2
4
  # Splits or iterates over the array in groups of size +number+,
3
5
  # padding any remaining slots with +fill_with+ unless it is +false+.
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "active_support/array_inquirer"
2
4
 
3
5
  class Array
@@ -1,7 +1,9 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class Array
2
4
  # The human way of thinking about adding stuff to the end of a list is with append.
3
- alias_method :append, :<<
5
+ alias_method :append, :push unless [].respond_to?(:append)
4
6
 
5
7
  # The human way of thinking about adding stuff to the beginning of a list is with prepend.
6
- alias_method :prepend, :unshift
8
+ alias_method :prepend, :unshift unless [].respond_to?(:prepend)
7
9
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  class Array
2
4
  # Wraps its argument in an array unless it is already an array (or array-like).
3
5
  #