activesupport 5.2.4 → 6.0.2.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 (140) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +391 -395
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +3 -2
  5. data/lib/active_support.rb +2 -1
  6. data/lib/active_support/actionable_error.rb +48 -0
  7. data/lib/active_support/backtrace_cleaner.rb +28 -1
  8. data/lib/active_support/cache.rb +45 -23
  9. data/lib/active_support/cache/file_store.rb +22 -22
  10. data/lib/active_support/cache/mem_cache_store.rb +5 -0
  11. data/lib/active_support/cache/memory_store.rb +9 -2
  12. data/lib/active_support/cache/null_store.rb +5 -0
  13. data/lib/active_support/cache/redis_cache_store.rb +37 -10
  14. data/lib/active_support/callbacks.rb +16 -5
  15. data/lib/active_support/concern.rb +24 -1
  16. data/lib/active_support/configurable.rb +7 -11
  17. data/lib/active_support/core_ext/array.rb +1 -1
  18. data/lib/active_support/core_ext/array/access.rb +18 -6
  19. data/lib/active_support/core_ext/array/extract.rb +21 -0
  20. data/lib/active_support/core_ext/array/prepend_and_append.rb +2 -6
  21. data/lib/active_support/core_ext/class/attribute.rb +11 -16
  22. data/lib/active_support/core_ext/class/subclasses.rb +1 -1
  23. data/lib/active_support/core_ext/date/calculations.rb +6 -5
  24. data/lib/active_support/core_ext/date_and_time/calculations.rb +24 -47
  25. data/lib/active_support/core_ext/date_time/calculations.rb +1 -1
  26. data/lib/active_support/core_ext/enumerable.rb +97 -73
  27. data/lib/active_support/core_ext/hash.rb +1 -2
  28. data/lib/active_support/core_ext/hash/compact.rb +2 -26
  29. data/lib/active_support/core_ext/hash/deep_transform_values.rb +46 -0
  30. data/lib/active_support/core_ext/hash/except.rb +1 -1
  31. data/lib/active_support/core_ext/hash/keys.rb +0 -29
  32. data/lib/active_support/core_ext/hash/slice.rb +3 -25
  33. data/lib/active_support/core_ext/hash/transform_values.rb +2 -29
  34. data/lib/active_support/core_ext/integer/multiple.rb +1 -1
  35. data/lib/active_support/core_ext/kernel.rb +0 -1
  36. data/lib/active_support/core_ext/load_error.rb +1 -1
  37. data/lib/active_support/core_ext/module.rb +0 -1
  38. data/lib/active_support/core_ext/module/attribute_accessors.rb +7 -10
  39. data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +13 -19
  40. data/lib/active_support/core_ext/module/delegation.rb +33 -7
  41. data/lib/active_support/core_ext/module/introspection.rb +37 -13
  42. data/lib/active_support/core_ext/module/reachable.rb +1 -6
  43. data/lib/active_support/core_ext/module/redefine_method.rb +8 -17
  44. data/lib/active_support/core_ext/numeric.rb +0 -1
  45. data/lib/active_support/core_ext/numeric/conversions.rb +124 -128
  46. data/lib/active_support/core_ext/numeric/inquiry.rb +2 -25
  47. data/lib/active_support/core_ext/object/blank.rb +1 -2
  48. data/lib/active_support/core_ext/object/duplicable.rb +7 -114
  49. data/lib/active_support/core_ext/object/json.rb +1 -0
  50. data/lib/active_support/core_ext/object/try.rb +15 -7
  51. data/lib/active_support/core_ext/object/with_options.rb +1 -1
  52. data/lib/active_support/core_ext/range/compare_range.rb +28 -13
  53. data/lib/active_support/core_ext/range/conversions.rb +31 -29
  54. data/lib/active_support/core_ext/range/include_range.rb +6 -0
  55. data/lib/active_support/core_ext/range/include_time_with_zone.rb +2 -2
  56. data/lib/active_support/core_ext/regexp.rb +0 -4
  57. data/lib/active_support/core_ext/securerandom.rb +23 -3
  58. data/lib/active_support/core_ext/string/access.rb +8 -0
  59. data/lib/active_support/core_ext/string/filters.rb +42 -1
  60. data/lib/active_support/core_ext/string/inflections.rb +7 -2
  61. data/lib/active_support/core_ext/string/multibyte.rb +4 -3
  62. data/lib/active_support/core_ext/string/output_safety.rb +63 -5
  63. data/lib/active_support/core_ext/string/strip.rb +3 -1
  64. data/lib/active_support/core_ext/time/calculations.rb +31 -2
  65. data/lib/active_support/core_ext/uri.rb +1 -0
  66. data/lib/active_support/current_attributes.rb +8 -0
  67. data/lib/active_support/dependencies.rb +69 -16
  68. data/lib/active_support/dependencies/zeitwerk_integration.rb +118 -0
  69. data/lib/active_support/deprecation.rb +1 -1
  70. data/lib/active_support/deprecation/behaviors.rb +1 -1
  71. data/lib/active_support/deprecation/method_wrappers.rb +8 -20
  72. data/lib/active_support/deprecation/proxy_wrappers.rb +24 -5
  73. data/lib/active_support/descendants_tracker.rb +56 -9
  74. data/lib/active_support/duration.rb +6 -5
  75. data/lib/active_support/duration/iso8601_parser.rb +2 -3
  76. data/lib/active_support/duration/iso8601_serializer.rb +3 -4
  77. data/lib/active_support/encrypted_configuration.rb +0 -4
  78. data/lib/active_support/encrypted_file.rb +2 -1
  79. data/lib/active_support/evented_file_update_checker.rb +39 -9
  80. data/lib/active_support/execution_wrapper.rb +1 -0
  81. data/lib/active_support/gem_version.rb +4 -4
  82. data/lib/active_support/hash_with_indifferent_access.rb +22 -18
  83. data/lib/active_support/i18n.rb +1 -0
  84. data/lib/active_support/i18n_railtie.rb +13 -1
  85. data/lib/active_support/inflector/inflections.rb +1 -4
  86. data/lib/active_support/inflector/methods.rb +15 -27
  87. data/lib/active_support/inflector/transliterate.rb +47 -18
  88. data/lib/active_support/json/decoding.rb +23 -23
  89. data/lib/active_support/json/encoding.rb +6 -2
  90. data/lib/active_support/key_generator.rb +0 -32
  91. data/lib/active_support/lazy_load_hooks.rb +5 -1
  92. data/lib/active_support/locale/en.rb +31 -0
  93. data/lib/active_support/log_subscriber.rb +31 -8
  94. data/lib/active_support/logger.rb +0 -15
  95. data/lib/active_support/logger_silence.rb +28 -12
  96. data/lib/active_support/logger_thread_safe_level.rb +26 -4
  97. data/lib/active_support/message_encryptor.rb +3 -5
  98. data/lib/active_support/message_verifier.rb +3 -3
  99. data/lib/active_support/multibyte/chars.rb +29 -48
  100. data/lib/active_support/multibyte/unicode.rb +44 -281
  101. data/lib/active_support/notifications.rb +41 -4
  102. data/lib/active_support/notifications/fanout.rb +98 -13
  103. data/lib/active_support/notifications/instrumenter.rb +80 -8
  104. data/lib/active_support/number_helper.rb +7 -0
  105. data/lib/active_support/number_helper/number_to_currency_converter.rb +2 -2
  106. data/lib/active_support/number_helper/number_to_delimited_converter.rb +3 -1
  107. data/lib/active_support/number_helper/number_to_human_converter.rb +3 -1
  108. data/lib/active_support/number_helper/number_to_human_size_converter.rb +3 -1
  109. data/lib/active_support/number_helper/number_to_percentage_converter.rb +3 -1
  110. data/lib/active_support/number_helper/number_to_phone_converter.rb +2 -0
  111. data/lib/active_support/number_helper/number_to_rounded_converter.rb +5 -3
  112. data/lib/active_support/ordered_hash.rb +1 -1
  113. data/lib/active_support/ordered_options.rb +1 -1
  114. data/lib/active_support/parameter_filter.rb +129 -0
  115. data/lib/active_support/rails.rb +0 -6
  116. data/lib/active_support/reloader.rb +4 -5
  117. data/lib/active_support/security_utils.rb +1 -1
  118. data/lib/active_support/subscriber.rb +65 -26
  119. data/lib/active_support/tagged_logging.rb +13 -4
  120. data/lib/active_support/test_case.rb +91 -0
  121. data/lib/active_support/testing/assertions.rb +15 -1
  122. data/lib/active_support/testing/deprecation.rb +0 -1
  123. data/lib/active_support/testing/file_fixtures.rb +2 -0
  124. data/lib/active_support/testing/isolation.rb +2 -2
  125. data/lib/active_support/testing/method_call_assertions.rb +28 -1
  126. data/lib/active_support/testing/parallelization.rb +128 -0
  127. data/lib/active_support/testing/stream.rb +1 -1
  128. data/lib/active_support/testing/time_helpers.rb +7 -7
  129. data/lib/active_support/time_with_zone.rb +15 -5
  130. data/lib/active_support/values/time_zone.rb +12 -7
  131. data/lib/active_support/xml_mini.rb +2 -9
  132. data/lib/active_support/xml_mini/jdom.rb +2 -2
  133. data/lib/active_support/xml_mini/libxml.rb +2 -2
  134. data/lib/active_support/xml_mini/libxmlsax.rb +4 -4
  135. data/lib/active_support/xml_mini/nokogiri.rb +2 -2
  136. data/lib/active_support/xml_mini/nokogirisax.rb +3 -3
  137. data/lib/active_support/xml_mini/rexml.rb +2 -2
  138. metadata +30 -8
  139. data/lib/active_support/core_ext/kernel/agnostics.rb +0 -13
  140. data/lib/active_support/values/unicode_tables.dat +0 -0
@@ -1,4 +1,4 @@
1
- Copyright (c) 2005-2018 David Heinemeier Hansson
1
+ Copyright (c) 2005-2019 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
@@ -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
 
@@ -14,7 +15,7 @@ The latest version of Active Support can be installed with RubyGems:
14
15
 
15
16
  Source code can be downloaded as part of the Rails project on GitHub:
16
17
 
17
- * https://github.com/rails/rails/tree/5-2-stable/activesupport
18
+ * https://github.com/rails/rails/tree/master/activesupport
18
19
 
19
20
 
20
21
  == License
@@ -28,7 +29,7 @@ Active Support is released under the MIT license:
28
29
 
29
30
  API documentation is at:
30
31
 
31
- * http://api.rubyonrails.org
32
+ * https://api.rubyonrails.org
32
33
 
33
34
  Bug reports for the Ruby on Rails project can be filed here:
34
35
 
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  #--
4
- # Copyright (c) 2005-2018 David Heinemeier Hansson
4
+ # Copyright (c) 2005-2019 David Heinemeier Hansson
5
5
  #
6
6
  # Permission is hereby granted, free of charge, to any person obtaining
7
7
  # a copy of this software and associated documentation files (the
@@ -34,6 +34,7 @@ module ActiveSupport
34
34
  extend ActiveSupport::Autoload
35
35
 
36
36
  autoload :Concern
37
+ autoload :ActionableError
37
38
  autoload :CurrentAttributes
38
39
  autoload :Dependencies
39
40
  autoload :DescendantsTracker
@@ -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
@@ -31,6 +31,9 @@ module ActiveSupport
31
31
  class BacktraceCleaner
32
32
  def initialize
33
33
  @filters, @silencers = [], []
34
+ add_gem_filter
35
+ add_gem_silencer
36
+ add_stdlib_silencer
34
37
  end
35
38
 
36
39
  # Returns the backtrace after all filters and silencers have been run
@@ -82,6 +85,26 @@ module ActiveSupport
82
85
  end
83
86
 
84
87
  private
88
+
89
+ FORMATTED_GEMS_PATTERN = /\A[^\/]+ \([\w.]+\) /
90
+
91
+ def add_gem_filter
92
+ gems_paths = (Gem.path | [Gem.default_dir]).map { |p| Regexp.escape(p) }
93
+ return if gems_paths.empty?
94
+
95
+ gems_regexp = %r{(#{gems_paths.join('|')})/(bundler/)?gems/([^/]+)-([\w.]+)/(.*)}
96
+ gems_result = '\3 (\4) \5'
97
+ add_filter { |line| line.sub(gems_regexp, gems_result) }
98
+ end
99
+
100
+ def add_gem_silencer
101
+ add_silencer { |line| FORMATTED_GEMS_PATTERN.match?(line) }
102
+ end
103
+
104
+ def add_stdlib_silencer
105
+ add_silencer { |line| line.start_with?(RbConfig::CONFIG["rubylibdir"]) }
106
+ end
107
+
85
108
  def filter_backtrace(backtrace)
86
109
  @filters.each do |f|
87
110
  backtrace = backtrace.map { |line| f.call(line) }
@@ -99,7 +122,11 @@ module ActiveSupport
99
122
  end
100
123
 
101
124
  def noise(backtrace)
102
- backtrace - silence(backtrace)
125
+ backtrace.select do |line|
126
+ @silencers.any? do |s|
127
+ s.call(line)
128
+ end
129
+ end
103
130
  end
104
131
  end
105
132
  end
@@ -229,6 +229,14 @@ module ActiveSupport
229
229
  # ask whether you should force a cache write. Otherwise, it's clearer to
230
230
  # just call <tt>Cache#write</tt>.
231
231
  #
232
+ # Setting <tt>skip_nil: true</tt> will not cache nil result:
233
+ #
234
+ # cache.fetch('foo') { nil }
235
+ # cache.fetch('bar', skip_nil: true) { nil }
236
+ # cache.exist?('foo') # => true
237
+ # cache.exist?('bar') # => false
238
+ #
239
+ #
232
240
  # Setting <tt>compress: false</tt> disables compression of the cache entry.
233
241
  #
234
242
  # Setting <tt>:expires_in</tt> will set an expiration time on the cache.
@@ -333,8 +341,9 @@ module ActiveSupport
333
341
  # the cache with the given key, then that data is returned. Otherwise,
334
342
  # +nil+ is returned.
335
343
  #
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.
344
+ # Note, if data was written with the <tt>:expires_in</tt> or
345
+ # <tt>:version</tt> options, both of these conditions are applied before
346
+ # the data is returned.
338
347
  #
339
348
  # Options are passed to the underlying cache implementation.
340
349
  def read(name, options = nil)
@@ -402,8 +411,6 @@ module ActiveSupport
402
411
  # to the cache. If you do not want to write the cache when the cache is
403
412
  # not found, use #read_multi.
404
413
  #
405
- # Options are passed to the underlying cache implementation.
406
- #
407
414
  # Returns a hash with the data for each of the names. For example:
408
415
  #
409
416
  # cache.write("bim", "bam")
@@ -413,6 +420,17 @@ module ActiveSupport
413
420
  # # => { "bim" => "bam",
414
421
  # # "unknown_key" => "Fallback value for key: unknown_key" }
415
422
  #
423
+ # Options are passed to the underlying cache implementation. For example:
424
+ #
425
+ # cache.fetch_multi("fizz", expires_in: 5.seconds) do |key|
426
+ # "buzz"
427
+ # end
428
+ # # => {"fizz"=>"buzz"}
429
+ # cache.read("fizz")
430
+ # # => "buzz"
431
+ # sleep(6)
432
+ # cache.read("fizz")
433
+ # # => nil
416
434
  def fetch_multi(*names)
417
435
  raise ArgumentError, "Missing block: `Cache#fetch_multi` requires a block." unless block_given?
418
436
 
@@ -420,18 +438,18 @@ module ActiveSupport
420
438
  options = merged_options(options)
421
439
 
422
440
  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
441
+ reads = read_multi_entries(names, options)
442
+ writes = {}
443
+ ordered = names.each_with_object({}) do |name, hash|
444
+ hash[name] = reads.fetch(name) { writes[name] = yield(name) }
445
+ end
426
446
 
427
- writes = {}
447
+ payload[:hits] = reads.keys
448
+ payload[:super_operation] = :fetch_multi
428
449
 
429
- (names - results.keys).each do |name|
430
- results[name] = writes[name] = yield(name)
431
- end
450
+ write_multi(writes, options)
432
451
 
433
- write_multi writes, options
434
- end
452
+ ordered
435
453
  end
436
454
  end
437
455
 
@@ -474,7 +492,7 @@ module ActiveSupport
474
492
  #
475
493
  # Options are passed to the underlying cache implementation.
476
494
  #
477
- # All implementations may not support this method.
495
+ # Some implementations may not support this method.
478
496
  def delete_matched(matcher, options = nil)
479
497
  raise NotImplementedError.new("#{self.class.name} does not support delete_matched")
480
498
  end
@@ -483,7 +501,7 @@ module ActiveSupport
483
501
  #
484
502
  # Options are passed to the underlying cache implementation.
485
503
  #
486
- # All implementations may not support this method.
504
+ # Some implementations may not support this method.
487
505
  def increment(name, amount = 1, options = nil)
488
506
  raise NotImplementedError.new("#{self.class.name} does not support increment")
489
507
  end
@@ -492,7 +510,7 @@ module ActiveSupport
492
510
  #
493
511
  # Options are passed to the underlying cache implementation.
494
512
  #
495
- # All implementations may not support this method.
513
+ # Some implementations may not support this method.
496
514
  def decrement(name, amount = 1, options = nil)
497
515
  raise NotImplementedError.new("#{self.class.name} does not support decrement")
498
516
  end
@@ -501,7 +519,7 @@ module ActiveSupport
501
519
  #
502
520
  # Options are passed to the underlying cache implementation.
503
521
  #
504
- # All implementations may not support this method.
522
+ # Some implementations may not support this method.
505
523
  def cleanup(options = nil)
506
524
  raise NotImplementedError.new("#{self.class.name} does not support cleanup")
507
525
  end
@@ -511,7 +529,7 @@ module ActiveSupport
511
529
  #
512
530
  # The options hash is passed to the underlying cache implementation.
513
531
  #
514
- # All implementations may not support this method.
532
+ # Some implementations may not support this method.
515
533
  def clear(options = nil)
516
534
  raise NotImplementedError.new("#{self.class.name} does not support clear")
517
535
  end
@@ -587,9 +605,13 @@ module ActiveSupport
587
605
  # Merges the default options with ones specific to a method call.
588
606
  def merged_options(call_options)
589
607
  if call_options
590
- options.merge(call_options)
608
+ if options.empty?
609
+ call_options
610
+ else
611
+ options.merge(call_options)
612
+ end
591
613
  else
592
- options.dup
614
+ options
593
615
  end
594
616
  end
595
617
 
@@ -634,7 +656,7 @@ module ActiveSupport
634
656
  if key.size > 1
635
657
  key = key.collect { |element| expanded_key(element) }
636
658
  else
637
- key = key.first
659
+ key = expanded_key(key.first)
638
660
  end
639
661
  when Hash
640
662
  key = key.sort_by { |k, _| k.to_s }.collect { |k, v| "#{k}=#{v}" }
@@ -685,7 +707,7 @@ module ActiveSupport
685
707
  end
686
708
 
687
709
  def get_entry_value(entry, name, options)
688
- instrument(:fetch_hit, name, options) {}
710
+ instrument(:fetch_hit, name, options) { }
689
711
  entry.value
690
712
  end
691
713
 
@@ -694,7 +716,7 @@ module ActiveSupport
694
716
  yield(name)
695
717
  end
696
718
 
697
- write(name, result, options)
719
+ write(name, result, options) unless result.nil? && options[:skip_nil]
698
720
  result
699
721
  end
700
722
  end
@@ -18,7 +18,6 @@ module ActiveSupport
18
18
  DIR_FORMATTER = "%03X"
19
19
  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)
20
20
  FILEPATH_MAX_SIZE = 900 # max is 1024, plus some room
21
- EXCLUDED_DIRS = [".", ".."].freeze
22
21
  GITKEEP_FILES = [".gitkeep", ".keep"].freeze
23
22
 
24
23
  def initialize(cache_path, options = nil)
@@ -26,11 +25,16 @@ module ActiveSupport
26
25
  @cache_path = cache_path.to_s
27
26
  end
28
27
 
28
+ # Advertise cache versioning support.
29
+ def self.supports_cache_versioning?
30
+ true
31
+ end
32
+
29
33
  # Deletes all items from the cache. In this case it deletes all the entries in the specified
30
34
  # file store directory except for .keep or .gitkeep. Be careful which directory is specified in your
31
35
  # config file when using +FileStore+ because everything in that directory will be deleted.
32
36
  def clear(options = nil)
33
- root_dirs = exclude_from(cache_path, EXCLUDED_DIRS + GITKEEP_FILES)
37
+ root_dirs = (Dir.children(cache_path) - GITKEEP_FILES)
34
38
  FileUtils.rm_r(root_dirs.collect { |f| File.join(cache_path, f) })
35
39
  rescue Errno::ENOENT
36
40
  end
@@ -103,12 +107,10 @@ module ActiveSupport
103
107
  def lock_file(file_name, &block)
104
108
  if File.exist?(file_name)
105
109
  File.open(file_name, "r+") do |f|
106
- begin
107
- f.flock File::LOCK_EX
108
- yield
109
- ensure
110
- f.flock File::LOCK_UN
111
- end
110
+ f.flock File::LOCK_EX
111
+ yield
112
+ ensure
113
+ f.flock File::LOCK_UN
112
114
  end
113
115
  else
114
116
  yield
@@ -127,15 +129,19 @@ module ActiveSupport
127
129
  hash = Zlib.adler32(fname)
128
130
  hash, dir_1 = hash.divmod(0x1000)
129
131
  dir_2 = hash.modulo(0x1000)
130
- fname_paths = []
131
132
 
132
133
  # Make sure file name doesn't exceed file system limits.
133
- begin
134
- fname_paths << fname[0, FILENAME_MAX_SIZE]
135
- fname = fname[FILENAME_MAX_SIZE..-1]
136
- 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
137
143
 
138
- 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)
139
145
  end
140
146
 
141
147
  # Translate a file path into a key.
@@ -147,7 +153,7 @@ module ActiveSupport
147
153
  # Delete empty directories in the cache.
148
154
  def delete_empty_directories(dir)
149
155
  return if File.realpath(dir) == File.realpath(cache_path)
150
- if exclude_from(dir, EXCLUDED_DIRS).empty?
156
+ if Dir.children(dir).empty?
151
157
  Dir.delete(dir) rescue nil
152
158
  delete_empty_directories(File.dirname(dir))
153
159
  end
@@ -160,8 +166,7 @@ module ActiveSupport
160
166
 
161
167
  def search_dir(dir, &callback)
162
168
  return if !File.exist?(dir)
163
- Dir.foreach(dir) do |d|
164
- next if EXCLUDED_DIRS.include?(d)
169
+ Dir.each_child(dir) do |d|
165
170
  name = File.join(dir, d)
166
171
  if File.directory?(name)
167
172
  search_dir(name, &callback)
@@ -186,11 +191,6 @@ module ActiveSupport
186
191
  end
187
192
  end
188
193
  end
189
-
190
- # Exclude entries from source directory
191
- def exclude_from(source, excludes)
192
- Dir.entries(source).reject { |f| excludes.include?(f) }
193
- end
194
194
  end
195
195
  end
196
196
  end
@@ -47,6 +47,11 @@ module ActiveSupport
47
47
  end
48
48
  end
49
49
 
50
+ # Advertise cache versioning support.
51
+ def self.supports_cache_versioning?
52
+ true
53
+ end
54
+
50
55
  prepend Strategy::LocalCache
51
56
  prepend LocalCacheWithRaw
52
57
 
@@ -30,6 +30,11 @@ module ActiveSupport
30
30
  @pruning = false
31
31
  end
32
32
 
33
+ # Advertise cache versioning support.
34
+ def self.supports_cache_versioning?
35
+ true
36
+ end
37
+
33
38
  # Delete all data stored in a given cache store.
34
39
  def clear(options = nil)
35
40
  synchronize do
@@ -57,13 +62,13 @@ module ActiveSupport
57
62
  return if pruning?
58
63
  @pruning = true
59
64
  begin
60
- start_time = Time.now
65
+ start_time = Concurrent.monotonic_time
61
66
  cleanup
62
67
  instrument(:prune, target_size, from: @cache_size) do
63
68
  keys = synchronize { @key_access.keys.sort { |a, b| @key_access[a].to_f <=> @key_access[b].to_f } }
64
69
  keys.each do |key|
65
70
  delete_entry(key, options)
66
- return if @cache_size <= target_size || (max_time && Time.now - start_time > max_time)
71
+ return if @cache_size <= target_size || (max_time && Concurrent.monotonic_time - start_time > max_time)
67
72
  end
68
73
  end
69
74
  ensure
@@ -120,6 +125,8 @@ module ActiveSupport
120
125
  entry = @data[key]
121
126
  synchronize do
122
127
  if entry
128
+ entry = entry.dup
129
+ entry.dup_value!
123
130
  @key_access[key] = Time.now.to_f
124
131
  else
125
132
  @key_access.delete(key)