activesupport 5.1.1 → 6.1.1

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 (262) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +360 -442
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +5 -4
  5. data/lib/active_support/actionable_error.rb +48 -0
  6. data/lib/active_support/all.rb +2 -0
  7. data/lib/active_support/array_inquirer.rb +6 -2
  8. data/lib/active_support/backtrace_cleaner.rb +31 -3
  9. data/lib/active_support/benchmarkable.rb +3 -1
  10. data/lib/active_support/builder.rb +2 -0
  11. data/lib/active_support/cache/file_store.rb +37 -36
  12. data/lib/active_support/cache/mem_cache_store.rb +65 -53
  13. data/lib/active_support/cache/memory_store.rb +61 -33
  14. data/lib/active_support/cache/null_store.rb +10 -3
  15. data/lib/active_support/cache/redis_cache_store.rb +493 -0
  16. data/lib/active_support/cache/strategy/local_cache.rb +68 -22
  17. data/lib/active_support/cache/strategy/local_cache_middleware.rb +2 -0
  18. data/lib/active_support/cache.rb +305 -127
  19. data/lib/active_support/callbacks.rb +106 -98
  20. data/lib/active_support/concern.rb +79 -6
  21. data/lib/active_support/concurrency/load_interlock_aware_monitor.rb +35 -0
  22. data/lib/active_support/concurrency/share_lock.rb +2 -1
  23. data/lib/active_support/configurable.rb +12 -14
  24. data/lib/active_support/configuration_file.rb +46 -0
  25. data/lib/active_support/core_ext/array/access.rb +21 -7
  26. data/lib/active_support/core_ext/array/conversions.rb +7 -5
  27. data/lib/active_support/core_ext/array/extract.rb +21 -0
  28. data/lib/active_support/core_ext/array/extract_options.rb +2 -0
  29. data/lib/active_support/core_ext/array/grouping.rb +2 -0
  30. data/lib/active_support/core_ext/array/inquiry.rb +2 -0
  31. data/lib/active_support/core_ext/array/wrap.rb +2 -0
  32. data/lib/active_support/core_ext/array.rb +3 -1
  33. data/lib/active_support/core_ext/benchmark.rb +4 -2
  34. data/lib/active_support/core_ext/big_decimal/conversions.rb +2 -0
  35. data/lib/active_support/core_ext/big_decimal.rb +2 -0
  36. data/lib/active_support/core_ext/class/attribute.rb +50 -47
  37. data/lib/active_support/core_ext/class/attribute_accessors.rb +2 -0
  38. data/lib/active_support/core_ext/class/subclasses.rb +18 -40
  39. data/lib/active_support/core_ext/class.rb +2 -0
  40. data/lib/active_support/core_ext/date/acts_like.rb +2 -0
  41. data/lib/active_support/core_ext/date/blank.rb +2 -0
  42. data/lib/active_support/core_ext/date/calculations.rb +8 -5
  43. data/lib/active_support/core_ext/date/conversions.rb +12 -10
  44. data/lib/active_support/core_ext/date/zones.rb +2 -0
  45. data/lib/active_support/core_ext/date.rb +2 -0
  46. data/lib/active_support/core_ext/date_and_time/calculations.rb +61 -37
  47. data/lib/active_support/core_ext/date_and_time/compatibility.rb +18 -1
  48. data/lib/active_support/core_ext/date_and_time/zones.rb +2 -1
  49. data/lib/active_support/core_ext/date_time/acts_like.rb +2 -0
  50. data/lib/active_support/core_ext/date_time/blank.rb +2 -0
  51. data/lib/active_support/core_ext/date_time/calculations.rb +3 -1
  52. data/lib/active_support/core_ext/date_time/compatibility.rb +7 -5
  53. data/lib/active_support/core_ext/date_time/conversions.rb +2 -1
  54. data/lib/active_support/core_ext/date_time.rb +2 -0
  55. data/lib/active_support/core_ext/digest/uuid.rb +3 -1
  56. data/lib/active_support/core_ext/digest.rb +3 -0
  57. data/lib/active_support/core_ext/enumerable.rb +174 -71
  58. data/lib/active_support/core_ext/file/atomic.rb +3 -1
  59. data/lib/active_support/core_ext/file.rb +2 -0
  60. data/lib/active_support/core_ext/hash/conversions.rb +7 -5
  61. data/lib/active_support/core_ext/hash/deep_merge.rb +8 -12
  62. data/lib/active_support/core_ext/hash/deep_transform_values.rb +46 -0
  63. data/lib/active_support/core_ext/hash/except.rb +4 -2
  64. data/lib/active_support/core_ext/hash/indifferent_access.rb +2 -0
  65. data/lib/active_support/core_ext/hash/keys.rb +3 -30
  66. data/lib/active_support/core_ext/hash/reverse_merge.rb +5 -2
  67. data/lib/active_support/core_ext/hash/slice.rb +8 -29
  68. data/lib/active_support/core_ext/hash.rb +3 -2
  69. data/lib/active_support/core_ext/integer/inflections.rb +2 -0
  70. data/lib/active_support/core_ext/integer/multiple.rb +3 -1
  71. data/lib/active_support/core_ext/integer/time.rb +7 -14
  72. data/lib/active_support/core_ext/integer.rb +2 -0
  73. data/lib/active_support/core_ext/kernel/concern.rb +2 -0
  74. data/lib/active_support/core_ext/kernel/reporting.rb +2 -0
  75. data/lib/active_support/core_ext/kernel/singleton_class.rb +2 -0
  76. data/lib/active_support/core_ext/kernel.rb +2 -1
  77. data/lib/active_support/core_ext/load_error.rb +3 -8
  78. data/lib/active_support/core_ext/marshal.rb +4 -0
  79. data/lib/active_support/core_ext/module/aliasing.rb +2 -0
  80. data/lib/active_support/core_ext/module/anonymous.rb +2 -0
  81. data/lib/active_support/core_ext/module/attr_internal.rb +4 -2
  82. data/lib/active_support/core_ext/module/attribute_accessors.rb +44 -56
  83. data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +18 -18
  84. data/lib/active_support/core_ext/module/concerning.rb +15 -10
  85. data/lib/active_support/core_ext/module/delegation.rb +103 -58
  86. data/lib/active_support/core_ext/module/deprecation.rb +2 -0
  87. data/lib/active_support/core_ext/module/introspection.rb +18 -15
  88. data/lib/active_support/core_ext/module/redefine_method.rb +40 -0
  89. data/lib/active_support/core_ext/module/remove_method.rb +5 -23
  90. data/lib/active_support/core_ext/module.rb +3 -1
  91. data/lib/active_support/core_ext/name_error.rb +36 -2
  92. data/lib/active_support/core_ext/numeric/bytes.rb +2 -0
  93. data/lib/active_support/core_ext/numeric/conversions.rb +131 -129
  94. data/lib/active_support/core_ext/numeric/time.rb +7 -15
  95. data/lib/active_support/core_ext/numeric.rb +2 -1
  96. data/lib/active_support/core_ext/object/acts_like.rb +12 -1
  97. data/lib/active_support/core_ext/object/blank.rb +13 -3
  98. data/lib/active_support/core_ext/object/conversions.rb +2 -0
  99. data/lib/active_support/core_ext/object/deep_dup.rb +3 -1
  100. data/lib/active_support/core_ext/object/duplicable.rb +6 -101
  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 +22 -2
  104. data/lib/active_support/core_ext/object/to_param.rb +2 -0
  105. data/lib/active_support/core_ext/object/to_query.rb +7 -2
  106. data/lib/active_support/core_ext/object/try.rb +19 -7
  107. data/lib/active_support/core_ext/object/with_options.rb +4 -2
  108. data/lib/active_support/core_ext/object.rb +2 -0
  109. data/lib/active_support/core_ext/range/compare_range.rb +82 -0
  110. data/lib/active_support/core_ext/range/conversions.rb +35 -25
  111. data/lib/active_support/core_ext/range/each.rb +5 -2
  112. data/lib/active_support/core_ext/range/include_time_with_zone.rb +28 -0
  113. data/lib/active_support/core_ext/range/overlaps.rb +2 -0
  114. data/lib/active_support/core_ext/range.rb +4 -1
  115. data/lib/active_support/core_ext/regexp.rb +10 -5
  116. data/lib/active_support/core_ext/securerandom.rb +25 -3
  117. data/lib/active_support/core_ext/string/access.rb +7 -16
  118. data/lib/active_support/core_ext/string/behavior.rb +2 -0
  119. data/lib/active_support/core_ext/string/conversions.rb +3 -0
  120. data/lib/active_support/core_ext/string/exclude.rb +2 -0
  121. data/lib/active_support/core_ext/string/filters.rb +44 -1
  122. data/lib/active_support/core_ext/string/indent.rb +2 -0
  123. data/lib/active_support/core_ext/string/inflections.rb +69 -16
  124. data/lib/active_support/core_ext/string/inquiry.rb +3 -0
  125. data/lib/active_support/core_ext/string/multibyte.rb +9 -4
  126. data/lib/active_support/core_ext/string/output_safety.rb +76 -20
  127. data/lib/active_support/core_ext/string/starts_ends_with.rb +4 -2
  128. data/lib/active_support/core_ext/string/strip.rb +5 -1
  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/symbol/starts_ends_with.rb +14 -0
  132. data/lib/active_support/core_ext/symbol.rb +3 -0
  133. data/lib/active_support/core_ext/time/acts_like.rb +2 -0
  134. data/lib/active_support/core_ext/time/calculations.rb +73 -18
  135. data/lib/active_support/core_ext/time/compatibility.rb +4 -2
  136. data/lib/active_support/core_ext/time/conversions.rb +4 -0
  137. data/lib/active_support/core_ext/time/zones.rb +6 -4
  138. data/lib/active_support/core_ext/time.rb +2 -0
  139. data/lib/active_support/core_ext/uri.rb +11 -6
  140. data/lib/active_support/core_ext.rb +3 -1
  141. data/lib/active_support/current_attributes/test_helper.rb +13 -0
  142. data/lib/active_support/current_attributes.rb +208 -0
  143. data/lib/active_support/dependencies/autoload.rb +2 -0
  144. data/lib/active_support/dependencies/interlock.rb +2 -0
  145. data/lib/active_support/dependencies/zeitwerk_integration.rb +117 -0
  146. data/lib/active_support/dependencies.rb +135 -60
  147. data/lib/active_support/deprecation/behaviors.rb +43 -11
  148. data/lib/active_support/deprecation/constant_accessor.rb +4 -2
  149. data/lib/active_support/deprecation/disallowed.rb +56 -0
  150. data/lib/active_support/deprecation/instance_delegator.rb +2 -1
  151. data/lib/active_support/deprecation/method_wrappers.rb +30 -15
  152. data/lib/active_support/deprecation/proxy_wrappers.rb +32 -6
  153. data/lib/active_support/deprecation/reporting.rb +54 -9
  154. data/lib/active_support/deprecation.rb +9 -2
  155. data/lib/active_support/descendants_tracker.rb +61 -9
  156. data/lib/active_support/digest.rb +20 -0
  157. data/lib/active_support/duration/iso8601_parser.rb +6 -6
  158. data/lib/active_support/duration/iso8601_serializer.rb +20 -14
  159. data/lib/active_support/duration.rb +179 -41
  160. data/lib/active_support/encrypted_configuration.rb +45 -0
  161. data/lib/active_support/encrypted_file.rb +117 -0
  162. data/lib/active_support/environment_inquirer.rb +20 -0
  163. data/lib/active_support/evented_file_update_checker.rb +84 -117
  164. data/lib/active_support/execution_wrapper.rb +3 -0
  165. data/lib/active_support/executor.rb +2 -0
  166. data/lib/active_support/file_update_checker.rb +2 -1
  167. data/lib/active_support/fork_tracker.rb +62 -0
  168. data/lib/active_support/gem_version.rb +3 -1
  169. data/lib/active_support/gzip.rb +2 -0
  170. data/lib/active_support/hash_with_indifferent_access.rb +134 -37
  171. data/lib/active_support/i18n.rb +4 -1
  172. data/lib/active_support/i18n_railtie.rb +20 -11
  173. data/lib/active_support/inflections.rb +2 -0
  174. data/lib/active_support/inflector/inflections.rb +19 -8
  175. data/lib/active_support/inflector/methods.rb +87 -77
  176. data/lib/active_support/inflector/transliterate.rb +56 -18
  177. data/lib/active_support/inflector.rb +2 -0
  178. data/lib/active_support/json/decoding.rb +27 -26
  179. data/lib/active_support/json/encoding.rb +13 -3
  180. data/lib/active_support/json.rb +2 -0
  181. data/lib/active_support/key_generator.rb +3 -33
  182. data/lib/active_support/lazy_load_hooks.rb +33 -10
  183. data/lib/active_support/locale/en.rb +33 -0
  184. data/lib/active_support/locale/en.yml +7 -3
  185. data/lib/active_support/log_subscriber/test_helper.rb +2 -0
  186. data/lib/active_support/log_subscriber.rb +46 -13
  187. data/lib/active_support/logger.rb +4 -17
  188. data/lib/active_support/logger_silence.rb +13 -20
  189. data/lib/active_support/logger_thread_safe_level.rb +54 -7
  190. data/lib/active_support/message_encryptor.rb +101 -33
  191. data/lib/active_support/message_verifier.rb +85 -14
  192. data/lib/active_support/messages/metadata.rb +80 -0
  193. data/lib/active_support/messages/rotation_configuration.rb +23 -0
  194. data/lib/active_support/messages/rotator.rb +57 -0
  195. data/lib/active_support/multibyte/chars.rb +12 -68
  196. data/lib/active_support/multibyte/unicode.rb +17 -327
  197. data/lib/active_support/multibyte.rb +2 -0
  198. data/lib/active_support/notifications/fanout.rb +118 -16
  199. data/lib/active_support/notifications/instrumenter.rb +73 -9
  200. data/lib/active_support/notifications.rb +74 -8
  201. data/lib/active_support/number_helper/number_converter.rb +7 -6
  202. data/lib/active_support/number_helper/number_to_currency_converter.rb +6 -9
  203. data/lib/active_support/number_helper/number_to_delimited_converter.rb +5 -2
  204. data/lib/active_support/number_helper/number_to_human_converter.rb +8 -7
  205. data/lib/active_support/number_helper/number_to_human_size_converter.rb +6 -3
  206. data/lib/active_support/number_helper/number_to_percentage_converter.rb +5 -1
  207. data/lib/active_support/number_helper/number_to_phone_converter.rb +5 -2
  208. data/lib/active_support/number_helper/number_to_rounded_converter.rb +16 -53
  209. data/lib/active_support/number_helper/rounding_helper.rb +50 -0
  210. data/lib/active_support/number_helper.rb +41 -12
  211. data/lib/active_support/option_merger.rb +24 -3
  212. data/lib/active_support/ordered_hash.rb +3 -1
  213. data/lib/active_support/ordered_options.rb +17 -5
  214. data/lib/active_support/parameter_filter.rb +133 -0
  215. data/lib/active_support/per_thread_registry.rb +3 -1
  216. data/lib/active_support/proxy_object.rb +2 -0
  217. data/lib/active_support/rails.rb +3 -10
  218. data/lib/active_support/railtie.rb +60 -9
  219. data/lib/active_support/reloader.rb +11 -10
  220. data/lib/active_support/rescuable.rb +7 -6
  221. data/lib/active_support/secure_compare_rotator.rb +51 -0
  222. data/lib/active_support/security_utils.rb +26 -15
  223. data/lib/active_support/string_inquirer.rb +6 -3
  224. data/lib/active_support/subscriber.rb +74 -24
  225. data/lib/active_support/tagged_logging.rb +44 -8
  226. data/lib/active_support/test_case.rb +94 -2
  227. data/lib/active_support/testing/assertions.rb +58 -20
  228. data/lib/active_support/testing/autorun.rb +2 -4
  229. data/lib/active_support/testing/constant_lookup.rb +2 -0
  230. data/lib/active_support/testing/declarative.rb +2 -0
  231. data/lib/active_support/testing/deprecation.rb +2 -1
  232. data/lib/active_support/testing/file_fixtures.rb +4 -0
  233. data/lib/active_support/testing/isolation.rb +8 -4
  234. data/lib/active_support/testing/method_call_assertions.rb +30 -1
  235. data/lib/active_support/testing/parallelization/server.rb +78 -0
  236. data/lib/active_support/testing/parallelization/worker.rb +100 -0
  237. data/lib/active_support/testing/parallelization.rb +51 -0
  238. data/lib/active_support/testing/setup_and_teardown.rb +12 -7
  239. data/lib/active_support/testing/stream.rb +3 -2
  240. data/lib/active_support/testing/tagged_logging.rb +2 -0
  241. data/lib/active_support/testing/time_helpers.rb +78 -13
  242. data/lib/active_support/time.rb +2 -0
  243. data/lib/active_support/time_with_zone.rb +113 -41
  244. data/lib/active_support/values/time_zone.rb +55 -25
  245. data/lib/active_support/version.rb +2 -0
  246. data/lib/active_support/xml_mini/jdom.rb +5 -4
  247. data/lib/active_support/xml_mini/libxml.rb +4 -2
  248. data/lib/active_support/xml_mini/libxmlsax.rb +6 -4
  249. data/lib/active_support/xml_mini/nokogiri.rb +4 -2
  250. data/lib/active_support/xml_mini/nokogirisax.rb +5 -3
  251. data/lib/active_support/xml_mini/rexml.rb +12 -3
  252. data/lib/active_support/xml_mini.rb +5 -11
  253. data/lib/active_support.rb +18 -13
  254. metadata +81 -35
  255. data/lib/active_support/core_ext/array/prepend_and_append.rb +0 -7
  256. data/lib/active_support/core_ext/hash/compact.rb +0 -27
  257. data/lib/active_support/core_ext/hash/transform_values.rb +0 -30
  258. data/lib/active_support/core_ext/kernel/agnostics.rb +0 -11
  259. data/lib/active_support/core_ext/module/reachable.rb +0 -8
  260. data/lib/active_support/core_ext/numeric/inquiry.rb +0 -26
  261. data/lib/active_support/core_ext/range/include_range.rb +0 -23
  262. data/lib/active_support/values/unicode_tables.dat +0 -0
data/MIT-LICENSE CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2005-2017 David Heinemeier Hansson
1
+ Copyright (c) 2005-2020 David Heinemeier Hansson
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining
4
4
  a copy of this software and associated documentation files (the
data/README.rdoc CHANGED
@@ -5,6 +5,7 @@ extensions that were found useful for the Rails framework. These additions
5
5
  reside in this package so they can be loaded as needed in Ruby projects
6
6
  outside of Rails.
7
7
 
8
+ You can read more about the extensions in the {Active Support Core Extensions}[https://edgeguides.rubyonrails.org/active_support_core_extensions.html] guide.
8
9
 
9
10
  == Download and installation
10
11
 
@@ -21,19 +22,19 @@ Source code can be downloaded as part of the Rails project on GitHub:
21
22
 
22
23
  Active Support is released under the MIT license:
23
24
 
24
- * http://www.opensource.org/licenses/MIT
25
+ * https://opensource.org/licenses/MIT
25
26
 
26
27
 
27
28
  == Support
28
29
 
29
30
  API documentation is at:
30
31
 
31
- * http://api.rubyonrails.org
32
+ * https://api.rubyonrails.org
32
33
 
33
- Bug reports can be filed for the Ruby on Rails project here:
34
+ Bug reports for the Ruby on Rails project can be filed here:
34
35
 
35
36
  * https://github.com/rails/rails/issues
36
37
 
37
38
  Feature requests should be discussed on the rails-core mailing list here:
38
39
 
39
- * https://groups.google.com/forum/?fromgroups#!forum/rubyonrails-core
40
+ * https://discuss.rubyonrails.org/c/rubyonrails-core
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveSupport
4
+ # Actionable errors let's you define actions to resolve an error.
5
+ #
6
+ # To make an error actionable, include the <tt>ActiveSupport::ActionableError</tt>
7
+ # module and invoke the +action+ class macro to define the action. An action
8
+ # needs a name and a block to execute.
9
+ module ActionableError
10
+ extend Concern
11
+
12
+ class NonActionable < StandardError; end
13
+
14
+ included do
15
+ class_attribute :_actions, default: {}
16
+ end
17
+
18
+ def self.actions(error) # :nodoc:
19
+ case error
20
+ when ActionableError, -> it { Class === it && it < ActionableError }
21
+ error._actions
22
+ else
23
+ {}
24
+ end
25
+ end
26
+
27
+ def self.dispatch(error, name) # :nodoc:
28
+ actions(error).fetch(name).call
29
+ rescue KeyError
30
+ raise NonActionable, "Cannot find action \"#{name}\""
31
+ end
32
+
33
+ module ClassMethods
34
+ # Defines an action that can resolve the error.
35
+ #
36
+ # class PendingMigrationError < MigrationError
37
+ # include ActiveSupport::ActionableError
38
+ #
39
+ # action "Run pending migrations" do
40
+ # ActiveRecord::Tasks::DatabaseTasks.migrate
41
+ # end
42
+ # end
43
+ def action(name, &block)
44
+ _actions[name] = block
45
+ end
46
+ end
47
+ end
48
+ end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "active_support"
2
4
  require "active_support/time"
3
5
  require "active_support/core_ext"
@@ -1,3 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/core_ext/symbol/starts_ends_with"
4
+
1
5
  module ActiveSupport
2
6
  # Wrapping an array in an +ArrayInquirer+ gives a friendlier way to check
3
7
  # its string-like contents:
@@ -32,11 +36,11 @@ module ActiveSupport
32
36
 
33
37
  private
34
38
  def respond_to_missing?(name, include_private = false)
35
- (name[-1] == "?") || super
39
+ name.end_with?("?") || super
36
40
  end
37
41
 
38
42
  def method_missing(name, *args)
39
- if name[-1] == "?"
43
+ if name.end_with?("?")
40
44
  any?(name[0..-2])
41
45
  else
42
46
  super
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module ActiveSupport
2
4
  # Backtraces often include many lines that are not relevant for the context
3
5
  # under review. This makes it hard to find the signal amongst the backtrace
@@ -14,7 +16,7 @@ module ActiveSupport
14
16
  #
15
17
  # bc = ActiveSupport::BacktraceCleaner.new
16
18
  # bc.add_filter { |line| line.gsub(Rails.root.to_s, '') } # strip the Rails.root prefix
17
- # bc.add_silencer { |line| line =~ /puma|rubygems/ } # skip any lines from puma or rubygems
19
+ # bc.add_silencer { |line| /puma|rubygems/.match?(line) } # skip any lines from puma or rubygems
18
20
  # bc.clean(exception.backtrace) # perform the cleanup
19
21
  #
20
22
  # To reconfigure an existing BacktraceCleaner (like the default one in Rails)
@@ -29,6 +31,9 @@ module ActiveSupport
29
31
  class BacktraceCleaner
30
32
  def initialize
31
33
  @filters, @silencers = [], []
34
+ add_gem_filter
35
+ add_gem_silencer
36
+ add_stdlib_silencer
32
37
  end
33
38
 
34
39
  # Returns the backtrace after all filters and silencers have been run
@@ -60,7 +65,7 @@ module ActiveSupport
60
65
  # for a given line, it will be excluded from the clean backtrace.
61
66
  #
62
67
  # # Will reject all lines that include the word "puma", like "/gems/puma/server.rb" or "/app/my_puma_server/rb"
63
- # backtrace_cleaner.add_silencer { |line| line =~ /puma/ }
68
+ # backtrace_cleaner.add_silencer { |line| /puma/.match?(line) }
64
69
  def add_silencer(&block)
65
70
  @silencers << block
66
71
  end
@@ -80,6 +85,25 @@ module ActiveSupport
80
85
  end
81
86
 
82
87
  private
88
+ FORMATTED_GEMS_PATTERN = /\A[^\/]+ \([\w.]+\) /
89
+
90
+ def add_gem_filter
91
+ gems_paths = (Gem.path | [Gem.default_dir]).map { |p| Regexp.escape(p) }
92
+ return if gems_paths.empty?
93
+
94
+ gems_regexp = %r{\A(#{gems_paths.join('|')})/(bundler/)?gems/([^/]+)-([\w.]+)/(.*)}
95
+ gems_result = '\3 (\4) \5'
96
+ add_filter { |line| line.sub(gems_regexp, gems_result) }
97
+ end
98
+
99
+ def add_gem_silencer
100
+ add_silencer { |line| FORMATTED_GEMS_PATTERN.match?(line) }
101
+ end
102
+
103
+ def add_stdlib_silencer
104
+ add_silencer { |line| line.start_with?(RbConfig::CONFIG["rubylibdir"]) }
105
+ end
106
+
83
107
  def filter_backtrace(backtrace)
84
108
  @filters.each do |f|
85
109
  backtrace = backtrace.map { |line| f.call(line) }
@@ -97,7 +121,11 @@ module ActiveSupport
97
121
  end
98
122
 
99
123
  def noise(backtrace)
100
- backtrace - silence(backtrace)
124
+ backtrace.select do |line|
125
+ @silencers.any? do |s|
126
+ s.call(line)
127
+ end
128
+ end
101
129
  end
102
130
  end
103
131
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "active_support/core_ext/benchmark"
2
4
  require "active_support/core_ext/hash/keys"
3
5
 
@@ -39,7 +41,7 @@ module ActiveSupport
39
41
 
40
42
  result = nil
41
43
  ms = Benchmark.ms { result = options[:silence] ? logger.silence { yield } : yield }
42
- logger.send(options[:level], "%s (%.1fms)" % [ message, ms ])
44
+ logger.public_send(options[:level], "%s (%.1fms)" % [ message, ms ])
43
45
  result
44
46
  else
45
47
  yield
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  begin
2
4
  require "builder"
3
5
  rescue LoadError => e
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "active_support/core_ext/marshal"
2
4
  require "active_support/core_ext/file/atomic"
3
5
  require "active_support/core_ext/string/conversions"
@@ -14,9 +16,8 @@ module ActiveSupport
14
16
  attr_reader :cache_path
15
17
 
16
18
  DIR_FORMATTER = "%03X"
17
- FILENAME_MAX_SIZE = 228 # max filename size on file system is 255, minus room for timestamp and random characters appended by Tempfile (used by atomic write)
19
+ FILENAME_MAX_SIZE = 226 # max filename size on file system is 255, minus room for timestamp, pid, and random characters appended by Tempfile (used by atomic write)
18
20
  FILEPATH_MAX_SIZE = 900 # max is 1024, plus some room
19
- EXCLUDED_DIRS = [".", ".."].freeze
20
21
  GITKEEP_FILES = [".gitkeep", ".keep"].freeze
21
22
 
22
23
  def initialize(cache_path, options = nil)
@@ -24,22 +25,26 @@ module ActiveSupport
24
25
  @cache_path = cache_path.to_s
25
26
  end
26
27
 
28
+ # Advertise cache versioning support.
29
+ def self.supports_cache_versioning?
30
+ true
31
+ end
32
+
27
33
  # Deletes all items from the cache. In this case it deletes all the entries in the specified
28
34
  # file store directory except for .keep or .gitkeep. Be careful which directory is specified in your
29
35
  # config file when using +FileStore+ because everything in that directory will be deleted.
30
- def clear
31
- root_dirs = exclude_from(cache_path, EXCLUDED_DIRS + GITKEEP_FILES)
36
+ def clear(options = nil)
37
+ root_dirs = (Dir.children(cache_path) - GITKEEP_FILES)
32
38
  FileUtils.rm_r(root_dirs.collect { |f| File.join(cache_path, f) })
33
- rescue Errno::ENOENT
39
+ rescue Errno::ENOENT, Errno::ENOTEMPTY
34
40
  end
35
41
 
36
42
  # Preemptively iterates through all stored keys and removes the ones which have expired.
37
43
  def cleanup(options = nil)
38
44
  options = merged_options(options)
39
45
  search_dir(cache_path) do |fname|
40
- key = file_path_key(fname)
41
- entry = read_entry(key, options)
42
- delete_entry(key, options) if entry && entry.expired?
46
+ entry = read_entry(fname, **options)
47
+ delete_entry(fname, **options) if entry && entry.expired?
43
48
  end
44
49
  end
45
50
 
@@ -61,30 +66,30 @@ module ActiveSupport
61
66
  matcher = key_matcher(matcher, options)
62
67
  search_dir(cache_path) do |path|
63
68
  key = file_path_key(path)
64
- delete_entry(path, options) if key.match(matcher)
69
+ delete_entry(path, **options) if key.match(matcher)
65
70
  end
66
71
  end
67
72
  end
68
73
 
69
74
  private
70
-
71
- def read_entry(key, options)
75
+ def read_entry(key, **options)
72
76
  if File.exist?(key)
73
- File.open(key) { |f| Marshal.load(f) }
77
+ entry = File.open(key) { |f| deserialize_entry(f.read) }
78
+ entry if entry.is_a?(Cache::Entry)
74
79
  end
75
80
  rescue => e
76
81
  logger.error("FileStoreError (#{e}): #{e.message}") if logger
77
82
  nil
78
83
  end
79
84
 
80
- def write_entry(key, entry, options)
85
+ def write_entry(key, entry, **options)
81
86
  return false if options[:unless_exist] && File.exist?(key)
82
87
  ensure_cache_path(File.dirname(key))
83
- File.atomic_write(key, cache_path) { |f| Marshal.dump(entry, f) }
88
+ File.atomic_write(key, cache_path) { |f| f.write(serialize_entry(entry)) }
84
89
  true
85
90
  end
86
91
 
87
- def delete_entry(key, options)
92
+ def delete_entry(key, **options)
88
93
  if File.exist?(key)
89
94
  begin
90
95
  File.delete(key)
@@ -102,12 +107,10 @@ module ActiveSupport
102
107
  def lock_file(file_name, &block)
103
108
  if File.exist?(file_name)
104
109
  File.open(file_name, "r+") do |f|
105
- begin
106
- f.flock File::LOCK_EX
107
- yield
108
- ensure
109
- f.flock File::LOCK_UN
110
- end
110
+ f.flock File::LOCK_EX
111
+ yield
112
+ ensure
113
+ f.flock File::LOCK_UN
111
114
  end
112
115
  else
113
116
  yield
@@ -120,21 +123,25 @@ module ActiveSupport
120
123
  fname = URI.encode_www_form_component(key)
121
124
 
122
125
  if fname.size > FILEPATH_MAX_SIZE
123
- fname = Digest::MD5.hexdigest(key)
126
+ fname = ActiveSupport::Digest.hexdigest(key)
124
127
  end
125
128
 
126
129
  hash = Zlib.adler32(fname)
127
130
  hash, dir_1 = hash.divmod(0x1000)
128
131
  dir_2 = hash.modulo(0x1000)
129
- fname_paths = []
130
132
 
131
133
  # Make sure file name doesn't exceed file system limits.
132
- begin
133
- fname_paths << fname[0, FILENAME_MAX_SIZE]
134
- fname = fname[FILENAME_MAX_SIZE..-1]
135
- end until fname.blank?
134
+ if fname.length < FILENAME_MAX_SIZE
135
+ fname_paths = fname
136
+ else
137
+ fname_paths = []
138
+ begin
139
+ fname_paths << fname[0, FILENAME_MAX_SIZE]
140
+ fname = fname[FILENAME_MAX_SIZE..-1]
141
+ end until fname.blank?
142
+ end
136
143
 
137
- File.join(cache_path, DIR_FORMATTER % dir_1, DIR_FORMATTER % dir_2, *fname_paths)
144
+ File.join(cache_path, DIR_FORMATTER % dir_1, DIR_FORMATTER % dir_2, fname_paths)
138
145
  end
139
146
 
140
147
  # Translate a file path into a key.
@@ -146,7 +153,7 @@ module ActiveSupport
146
153
  # Delete empty directories in the cache.
147
154
  def delete_empty_directories(dir)
148
155
  return if File.realpath(dir) == File.realpath(cache_path)
149
- if exclude_from(dir, EXCLUDED_DIRS).empty?
156
+ if Dir.children(dir).empty?
150
157
  Dir.delete(dir) rescue nil
151
158
  delete_empty_directories(File.dirname(dir))
152
159
  end
@@ -159,8 +166,7 @@ module ActiveSupport
159
166
 
160
167
  def search_dir(dir, &callback)
161
168
  return if !File.exist?(dir)
162
- Dir.foreach(dir) do |d|
163
- next if EXCLUDED_DIRS.include?(d)
169
+ Dir.each_child(dir) do |d|
164
170
  name = File.join(dir, d)
165
171
  if File.directory?(name)
166
172
  search_dir(name, &callback)
@@ -185,11 +191,6 @@ module ActiveSupport
185
191
  end
186
192
  end
187
193
  end
188
-
189
- # Exclude entries from source directory
190
- def exclude_from(source, excludes)
191
- Dir.entries(source).reject { |f| excludes.include?(f) }
192
- end
193
194
  end
194
195
  end
195
196
  end
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  begin
2
4
  require "dalli"
3
5
  rescue LoadError => e
@@ -5,14 +7,14 @@ rescue LoadError => e
5
7
  raise e
6
8
  end
7
9
 
8
- require "digest/md5"
10
+ require "active_support/core_ext/enumerable"
9
11
  require "active_support/core_ext/marshal"
10
12
  require "active_support/core_ext/array/extract_options"
11
13
 
12
14
  module ActiveSupport
13
15
  module Cache
14
16
  # A cache store implementation which stores data in Memcached:
15
- # http://memcached.org/
17
+ # https://memcached.org
16
18
  #
17
19
  # This is currently the most popular cache store for production websites.
18
20
  #
@@ -24,45 +26,53 @@ module ActiveSupport
24
26
  # MemCacheStore implements the Strategy::LocalCache strategy which implements
25
27
  # an in-memory cache inside of a block.
26
28
  class MemCacheStore < Store
29
+ DEFAULT_CODER = NullCoder # Dalli automatically Marshal values
30
+
27
31
  # Provide support for raw values in the local cache strategy.
28
32
  module LocalCacheWithRaw # :nodoc:
29
33
  private
30
- def read_entry(key, options)
31
- entry = super
32
- if options[:raw] && local_cache && entry
33
- entry = deserialize_entry(entry.value)
34
- end
35
- entry
36
- end
37
-
38
- def write_entry(key, entry, options)
34
+ def write_entry(key, entry, **options)
39
35
  if options[:raw] && local_cache
40
36
  raw_entry = Entry.new(entry.value.to_s)
41
37
  raw_entry.expires_at = entry.expires_at
42
- super(key, raw_entry, options)
38
+ super(key, raw_entry, **options)
43
39
  else
44
40
  super
45
41
  end
46
42
  end
47
43
  end
48
44
 
45
+ # Advertise cache versioning support.
46
+ def self.supports_cache_versioning?
47
+ true
48
+ end
49
+
49
50
  prepend Strategy::LocalCache
50
51
  prepend LocalCacheWithRaw
51
52
 
52
53
  ESCAPE_KEY_CHARS = /[\x00-\x20%\x7F-\xFF]/n
53
54
 
54
55
  # Creates a new Dalli::Client instance with specified addresses and options.
55
- # By default address is equal localhost:11211.
56
+ # If no addresses are provided, we give nil to Dalli::Client, so it uses its fallbacks:
57
+ # - ENV["MEMCACHE_SERVERS"] (if defined)
58
+ # - "127.0.0.1:11211" (otherwise)
56
59
  #
57
60
  # ActiveSupport::Cache::MemCacheStore.build_mem_cache
58
- # # => #<Dalli::Client:0x007f98a47d2028 @servers=["localhost:11211"], @options={}, @ring=nil>
61
+ # # => #<Dalli::Client:0x007f98a47d2028 @servers=["127.0.0.1:11211"], @options={}, @ring=nil>
59
62
  # ActiveSupport::Cache::MemCacheStore.build_mem_cache('localhost:10290')
60
63
  # # => #<Dalli::Client:0x007f98a47b3a60 @servers=["localhost:10290"], @options={}, @ring=nil>
61
64
  def self.build_mem_cache(*addresses) # :nodoc:
62
65
  addresses = addresses.flatten
63
66
  options = addresses.extract_options!
64
- addresses = ["localhost:11211"] if addresses.empty?
65
- Dalli::Client.new(addresses, options)
67
+ addresses = nil if addresses.empty?
68
+ pool_options = retrieve_pool_options(options)
69
+
70
+ if pool_options.empty?
71
+ Dalli::Client.new(addresses, options)
72
+ else
73
+ ensure_connection_pool_added!
74
+ ConnectionPool.new(pool_options) { Dalli::Client.new(addresses, options.merge(threadsafe: false)) }
75
+ end
66
76
  end
67
77
 
68
78
  # Creates a new MemCacheStore object, with the given memcached server
@@ -71,8 +81,8 @@ module ActiveSupport
71
81
  #
72
82
  # ActiveSupport::Cache::MemCacheStore.new("localhost", "server-downstairs.localnetwork:8229")
73
83
  #
74
- # If no addresses are specified, then MemCacheStore will connect to
75
- # localhost port 11211 (the default memcached port).
84
+ # If no addresses are provided, but ENV['MEMCACHE_SERVERS'] is defined, it will be used instead. Otherwise,
85
+ # MemCacheStore will connect to localhost:11211 (the default memcached port).
76
86
  def initialize(*addresses)
77
87
  addresses = addresses.flatten
78
88
  options = addresses.extract_options!
@@ -90,22 +100,6 @@ module ActiveSupport
90
100
  end
91
101
  end
92
102
 
93
- # Reads multiple values from the cache using a single call to the
94
- # servers for all keys. Options can be passed in the last argument.
95
- def read_multi(*names)
96
- options = names.extract_options!
97
- options = merged_options(options)
98
-
99
- keys_to_names = Hash[names.map { |name| [normalize_key(name, options), name] }]
100
- raw_values = @data.get_multi(keys_to_names.keys)
101
- values = {}
102
- raw_values.each do |key, value|
103
- entry = deserialize_entry(value)
104
- values[keys_to_names[key]] = entry.value unless entry.expired?
105
- end
106
- values
107
- end
108
-
109
103
  # Increment a cached value. This method uses the memcached incr atomic
110
104
  # operator and can only be used on values written with the :raw option.
111
105
  # Calling it on a value not stored with :raw will initialize that value
@@ -114,7 +108,7 @@ module ActiveSupport
114
108
  options = merged_options(options)
115
109
  instrument(:increment, name, amount: amount) do
116
110
  rescue_error_with nil do
117
- @data.incr(normalize_key(name, options), amount)
111
+ @data.with { |c| c.incr(normalize_key(name, options), amount, options[:expires_in]) }
118
112
  end
119
113
  end
120
114
  end
@@ -127,7 +121,7 @@ module ActiveSupport
127
121
  options = merged_options(options)
128
122
  instrument(:decrement, name, amount: amount) do
129
123
  rescue_error_with nil do
130
- @data.decr(normalize_key(name, options), amount)
124
+ @data.with { |c| c.decr(normalize_key(name, options), amount, options[:expires_in]) }
131
125
  end
132
126
  end
133
127
  end
@@ -135,37 +129,56 @@ module ActiveSupport
135
129
  # Clear the entire cache on all memcached servers. This method should
136
130
  # be used with care when shared cache is being used.
137
131
  def clear(options = nil)
138
- rescue_error_with(nil) { @data.flush_all }
132
+ rescue_error_with(nil) { @data.with { |c| c.flush_all } }
139
133
  end
140
134
 
141
135
  # Get the statistics from the memcached servers.
142
136
  def stats
143
- @data.stats
137
+ @data.with { |c| c.stats }
144
138
  end
145
139
 
146
140
  private
147
141
  # Read an entry from the cache.
148
- def read_entry(key, options)
149
- rescue_error_with(nil) { deserialize_entry(@data.get(key, options)) }
142
+ def read_entry(key, **options)
143
+ rescue_error_with(nil) { deserialize_entry(@data.with { |c| c.get(key, options) }) }
150
144
  end
151
145
 
152
146
  # Write an entry to the cache.
153
- def write_entry(key, entry, options)
154
- method = options && options[:unless_exist] ? :add : :set
155
- value = options[:raw] ? entry.value.to_s : entry
147
+ def write_entry(key, entry, **options)
148
+ method = options[:unless_exist] ? :add : :set
149
+ value = options[:raw] ? entry.value.to_s : serialize_entry(entry)
156
150
  expires_in = options[:expires_in].to_i
157
- if expires_in > 0 && !options[:raw]
151
+ if options[:race_condition_ttl] && expires_in > 0 && !options[:raw]
158
152
  # Set the memcache expire a few minutes in the future to support race condition ttls on read
159
153
  expires_in += 5.minutes
160
154
  end
161
155
  rescue_error_with false do
162
- @data.send(method, key, value, expires_in, options)
156
+ # The value "compress: false" prevents duplicate compression within Dalli.
157
+ @data.with { |c| c.send(method, key, value, expires_in, **options, compress: false) }
158
+ end
159
+ end
160
+
161
+ # Reads multiple entries from the cache implementation.
162
+ def read_multi_entries(names, **options)
163
+ keys_to_names = names.index_by { |name| normalize_key(name, options) }
164
+
165
+ raw_values = @data.with { |c| c.get_multi(keys_to_names.keys) }
166
+ values = {}
167
+
168
+ raw_values.each do |key, value|
169
+ entry = deserialize_entry(value)
170
+
171
+ unless entry.expired? || entry.mismatched?(normalize_version(keys_to_names[key], options))
172
+ values[keys_to_names[key]] = entry.value
173
+ end
163
174
  end
175
+
176
+ values
164
177
  end
165
178
 
166
179
  # Delete an entry from the cache.
167
- def delete_entry(key, options)
168
- rescue_error_with(false) { @data.delete(key) }
180
+ def delete_entry(key, **options)
181
+ rescue_error_with(false) { @data.with { |c| c.delete(key) } }
169
182
  end
170
183
 
171
184
  # Memcache keys are binaries. So we need to force their encoding to binary
@@ -175,15 +188,14 @@ module ActiveSupport
175
188
  key = super.dup
176
189
  key = key.force_encoding(Encoding::ASCII_8BIT)
177
190
  key = key.gsub(ESCAPE_KEY_CHARS) { |match| "%#{match.getbyte(0).to_s(16).upcase}" }
178
- key = "#{key[0, 213]}:md5:#{Digest::MD5.hexdigest(key)}" if key.size > 250
191
+ key = "#{key[0, 213]}:md5:#{ActiveSupport::Digest.hexdigest(key)}" if key.size > 250
179
192
  key
180
193
  end
181
194
 
182
- def deserialize_entry(raw_value)
183
- if raw_value
184
- entry = Marshal.load(raw_value) rescue raw_value
185
- entry.is_a?(Entry) ? entry : Entry.new(entry)
186
- end
195
+ def deserialize_entry(payload)
196
+ entry = super
197
+ entry = Entry.new(entry, compress: false) if entry && !entry.is_a?(Entry)
198
+ entry
187
199
  end
188
200
 
189
201
  def rescue_error_with(fallback)