activesupport 6.0.4.1 → 6.1.0.rc1

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 (127) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +337 -513
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +1 -1
  5. data/lib/active_support.rb +13 -1
  6. data/lib/active_support/array_inquirer.rb +4 -2
  7. data/lib/active_support/backtrace_cleaner.rb +3 -3
  8. data/lib/active_support/benchmarkable.rb +1 -1
  9. data/lib/active_support/cache.rb +75 -34
  10. data/lib/active_support/cache/file_store.rb +2 -2
  11. data/lib/active_support/cache/mem_cache_store.rb +20 -14
  12. data/lib/active_support/cache/memory_store.rb +38 -26
  13. data/lib/active_support/cache/redis_cache_store.rb +25 -25
  14. data/lib/active_support/cache/strategy/local_cache.rb +13 -4
  15. data/lib/active_support/callbacks.rb +65 -56
  16. data/lib/active_support/concern.rb +46 -2
  17. data/lib/active_support/configurable.rb +3 -3
  18. data/lib/active_support/configuration_file.rb +46 -0
  19. data/lib/active_support/core_ext/benchmark.rb +2 -2
  20. data/lib/active_support/core_ext/class/attribute.rb +34 -44
  21. data/lib/active_support/core_ext/class/subclasses.rb +17 -38
  22. data/lib/active_support/core_ext/date/conversions.rb +2 -1
  23. data/lib/active_support/core_ext/date_and_time/calculations.rb +13 -0
  24. data/lib/active_support/core_ext/date_and_time/compatibility.rb +15 -0
  25. data/lib/active_support/core_ext/enumerable.rb +76 -4
  26. data/lib/active_support/core_ext/hash/conversions.rb +2 -2
  27. data/lib/active_support/core_ext/hash/deep_transform_values.rb +1 -1
  28. data/lib/active_support/core_ext/hash/keys.rb +1 -1
  29. data/lib/active_support/core_ext/hash/slice.rb +3 -2
  30. data/lib/active_support/core_ext/load_error.rb +1 -1
  31. data/lib/active_support/core_ext/marshal.rb +2 -0
  32. data/lib/active_support/core_ext/module/attr_internal.rb +2 -2
  33. data/lib/active_support/core_ext/module/attribute_accessors.rb +23 -29
  34. data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +8 -4
  35. data/lib/active_support/core_ext/module/concerning.rb +8 -2
  36. data/lib/active_support/core_ext/module/delegation.rb +38 -28
  37. data/lib/active_support/core_ext/module/introspection.rb +1 -25
  38. data/lib/active_support/core_ext/name_error.rb +29 -2
  39. data/lib/active_support/core_ext/numeric/conversions.rb +22 -18
  40. data/lib/active_support/core_ext/object/deep_dup.rb +1 -1
  41. data/lib/active_support/core_ext/object/json.rb +5 -1
  42. data/lib/active_support/core_ext/object/try.rb +2 -2
  43. data/lib/active_support/core_ext/range/compare_range.rb +9 -3
  44. data/lib/active_support/core_ext/range/include_time_with_zone.rb +8 -3
  45. data/lib/active_support/core_ext/string/access.rb +5 -24
  46. data/lib/active_support/core_ext/string/inflections.rb +38 -4
  47. data/lib/active_support/core_ext/string/inquiry.rb +1 -0
  48. data/lib/active_support/core_ext/string/multibyte.rb +2 -2
  49. data/lib/active_support/core_ext/string/output_safety.rb +8 -10
  50. data/lib/active_support/core_ext/string/starts_ends_with.rb +2 -2
  51. data/lib/active_support/core_ext/symbol.rb +3 -0
  52. data/lib/active_support/core_ext/symbol/starts_ends_with.rb +14 -0
  53. data/lib/active_support/core_ext/time/calculations.rb +16 -0
  54. data/lib/active_support/core_ext/time/conversions.rb +1 -0
  55. data/lib/active_support/core_ext/uri.rb +5 -1
  56. data/lib/active_support/current_attributes.rb +7 -2
  57. data/lib/active_support/current_attributes/test_helper.rb +13 -0
  58. data/lib/active_support/dependencies.rb +38 -24
  59. data/lib/active_support/deprecation.rb +6 -1
  60. data/lib/active_support/deprecation/behaviors.rb +15 -2
  61. data/lib/active_support/deprecation/disallowed.rb +56 -0
  62. data/lib/active_support/deprecation/instance_delegator.rb +0 -1
  63. data/lib/active_support/deprecation/method_wrappers.rb +3 -2
  64. data/lib/active_support/deprecation/proxy_wrappers.rb +2 -2
  65. data/lib/active_support/deprecation/reporting.rb +50 -7
  66. data/lib/active_support/descendants_tracker.rb +6 -2
  67. data/lib/active_support/duration.rb +71 -22
  68. data/lib/active_support/duration/iso8601_serializer.rb +15 -9
  69. data/lib/active_support/encrypted_file.rb +19 -2
  70. data/lib/active_support/environment_inquirer.rb +20 -0
  71. data/lib/active_support/evented_file_update_checker.rb +69 -133
  72. data/lib/active_support/fork_tracker.rb +58 -0
  73. data/lib/active_support/gem_version.rb +3 -3
  74. data/lib/active_support/hash_with_indifferent_access.rb +35 -22
  75. data/lib/active_support/i18n_railtie.rb +14 -19
  76. data/lib/active_support/inflector/inflections.rb +1 -2
  77. data/lib/active_support/inflector/methods.rb +35 -31
  78. data/lib/active_support/inflector/transliterate.rb +4 -4
  79. data/lib/active_support/json/decoding.rb +4 -4
  80. data/lib/active_support/json/encoding.rb +5 -1
  81. data/lib/active_support/key_generator.rb +1 -1
  82. data/lib/active_support/locale/en.yml +7 -3
  83. data/lib/active_support/log_subscriber.rb +8 -0
  84. data/lib/active_support/logger.rb +1 -1
  85. data/lib/active_support/logger_silence.rb +2 -26
  86. data/lib/active_support/logger_thread_safe_level.rb +34 -12
  87. data/lib/active_support/message_encryptor.rb +4 -7
  88. data/lib/active_support/message_verifier.rb +5 -5
  89. data/lib/active_support/messages/rotation_configuration.rb +2 -1
  90. data/lib/active_support/messages/rotator.rb +6 -5
  91. data/lib/active_support/multibyte/chars.rb +4 -42
  92. data/lib/active_support/multibyte/unicode.rb +9 -83
  93. data/lib/active_support/notifications.rb +31 -4
  94. data/lib/active_support/notifications/fanout.rb +23 -8
  95. data/lib/active_support/notifications/instrumenter.rb +6 -15
  96. data/lib/active_support/number_helper.rb +29 -14
  97. data/lib/active_support/number_helper/number_converter.rb +1 -1
  98. data/lib/active_support/number_helper/number_to_human_converter.rb +1 -1
  99. data/lib/active_support/number_helper/number_to_human_size_converter.rb +1 -1
  100. data/lib/active_support/number_helper/number_to_rounded_converter.rb +3 -3
  101. data/lib/active_support/number_helper/rounding_helper.rb +12 -28
  102. data/lib/active_support/option_merger.rb +2 -1
  103. data/lib/active_support/ordered_options.rb +8 -2
  104. data/lib/active_support/parameter_filter.rb +15 -10
  105. data/lib/active_support/per_thread_registry.rb +1 -1
  106. data/lib/active_support/rails.rb +1 -4
  107. data/lib/active_support/railtie.rb +23 -1
  108. data/lib/active_support/secure_compare_rotator.rb +51 -0
  109. data/lib/active_support/security_utils.rb +19 -12
  110. data/lib/active_support/string_inquirer.rb +4 -2
  111. data/lib/active_support/subscriber.rb +12 -7
  112. data/lib/active_support/tagged_logging.rb +29 -4
  113. data/lib/active_support/testing/assertions.rb +18 -11
  114. data/lib/active_support/testing/parallelization.rb +12 -95
  115. data/lib/active_support/testing/parallelization/server.rb +78 -0
  116. data/lib/active_support/testing/parallelization/worker.rb +100 -0
  117. data/lib/active_support/testing/time_helpers.rb +40 -3
  118. data/lib/active_support/time_with_zone.rb +66 -42
  119. data/lib/active_support/values/time_zone.rb +20 -10
  120. data/lib/active_support/xml_mini/rexml.rb +8 -1
  121. metadata +39 -41
  122. data/lib/active_support/core_ext/array/prepend_and_append.rb +0 -5
  123. data/lib/active_support/core_ext/hash/compact.rb +0 -5
  124. data/lib/active_support/core_ext/hash/transform_values.rb +0 -5
  125. data/lib/active_support/core_ext/module/reachable.rb +0 -6
  126. data/lib/active_support/core_ext/numeric/inquiry.rb +0 -5
  127. data/lib/active_support/core_ext/range/include_range.rb +0 -9
data/MIT-LICENSE CHANGED
@@ -1,4 +1,4 @@
1
- Copyright (c) 2005-2019 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
@@ -15,7 +15,7 @@ The latest version of Active Support can be installed with RubyGems:
15
15
 
16
16
  Source code can be downloaded as part of the Rails project on GitHub:
17
17
 
18
- * https://github.com/rails/rails/tree/main/activesupport
18
+ * https://github.com/rails/rails/tree/master/activesupport
19
19
 
20
20
 
21
21
  == License
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  #--
4
- # Copyright (c) 2005-2019 David Heinemeier Hansson
4
+ # Copyright (c) 2005-2020 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
@@ -35,6 +35,7 @@ module ActiveSupport
35
35
 
36
36
  autoload :Concern
37
37
  autoload :ActionableError
38
+ autoload :ConfigurationFile
38
39
  autoload :CurrentAttributes
39
40
  autoload :Dependencies
40
41
  autoload :DescendantsTracker
@@ -42,9 +43,11 @@ module ActiveSupport
42
43
  autoload :Executor
43
44
  autoload :FileUpdateChecker
44
45
  autoload :EventedFileUpdateChecker
46
+ autoload :ForkTracker
45
47
  autoload :LogSubscriber
46
48
  autoload :Notifications
47
49
  autoload :Reloader
50
+ autoload :SecureCompareRotator
48
51
 
49
52
  eager_autoload do
50
53
  autoload :BacktraceCleaner
@@ -67,6 +70,7 @@ module ActiveSupport
67
70
  autoload :OrderedHash
68
71
  autoload :OrderedOptions
69
72
  autoload :StringInquirer
73
+ autoload :EnvironmentInquirer
70
74
  autoload :TaggedLogging
71
75
  autoload :XmlMini
72
76
  autoload :ArrayInquirer
@@ -91,6 +95,14 @@ module ActiveSupport
91
95
  def self.to_time_preserves_timezone=(value)
92
96
  DateAndTime::Compatibility.preserve_timezone = value
93
97
  end
98
+
99
+ def self.utc_to_local_returns_utc_offset_times
100
+ DateAndTime::Compatibility.utc_to_local_returns_utc_offset_times
101
+ end
102
+
103
+ def self.utc_to_local_returns_utc_offset_times=(value)
104
+ DateAndTime::Compatibility.utc_to_local_returns_utc_offset_times = value
105
+ end
94
106
  end
95
107
 
96
108
  autoload :I18n, "active_support/i18n"
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "active_support/core_ext/symbol/starts_ends_with"
4
+
3
5
  module ActiveSupport
4
6
  # Wrapping an array in an +ArrayInquirer+ gives a friendlier way to check
5
7
  # its string-like contents:
@@ -34,11 +36,11 @@ module ActiveSupport
34
36
 
35
37
  private
36
38
  def respond_to_missing?(name, include_private = false)
37
- (name[-1] == "?") || super
39
+ name.end_with?("?") || super
38
40
  end
39
41
 
40
42
  def method_missing(name, *args)
41
- if name[-1] == "?"
43
+ if name.end_with?("?")
42
44
  any?(name[0..-2])
43
45
  else
44
46
  super
@@ -16,7 +16,7 @@ module ActiveSupport
16
16
  #
17
17
  # bc = ActiveSupport::BacktraceCleaner.new
18
18
  # bc.add_filter { |line| line.gsub(Rails.root.to_s, '') } # strip the Rails.root prefix
19
- # 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
20
20
  # bc.clean(exception.backtrace) # perform the cleanup
21
21
  #
22
22
  # To reconfigure an existing BacktraceCleaner (like the default one in Rails)
@@ -65,7 +65,7 @@ module ActiveSupport
65
65
  # for a given line, it will be excluded from the clean backtrace.
66
66
  #
67
67
  # # Will reject all lines that include the word "puma", like "/gems/puma/server.rb" or "/app/my_puma_server/rb"
68
- # backtrace_cleaner.add_silencer { |line| line =~ /puma/ }
68
+ # backtrace_cleaner.add_silencer { |line| /puma/.match?(line) }
69
69
  def add_silencer(&block)
70
70
  @silencers << block
71
71
  end
@@ -91,7 +91,7 @@ module ActiveSupport
91
91
  gems_paths = (Gem.path | [Gem.default_dir]).map { |p| Regexp.escape(p) }
92
92
  return if gems_paths.empty?
93
93
 
94
- gems_regexp = %r{(#{gems_paths.join('|')})/(bundler/)?gems/([^/]+)-([\w.]+)/(.*)}
94
+ gems_regexp = %r{\A(#{gems_paths.join('|')})/(bundler/)?gems/([^/]+)-([\w.]+)/(.*)}
95
95
  gems_result = '\3 (\4) \5'
96
96
  add_filter { |line| line.sub(gems_regexp, gems_result) }
97
97
  end
@@ -41,7 +41,7 @@ module ActiveSupport
41
41
 
42
42
  result = nil
43
43
  ms = Benchmark.ms { result = options[:silence] ? logger.silence { yield } : yield }
44
- logger.send(options[:level], "%s (%.1fms)" % [ message, ms ])
44
+ logger.public_send(options[:level], "%s (%.1fms)" % [ message, ms ])
45
45
  result
46
46
  else
47
47
  yield
@@ -3,10 +3,12 @@
3
3
  require "zlib"
4
4
  require "active_support/core_ext/array/extract_options"
5
5
  require "active_support/core_ext/array/wrap"
6
+ require "active_support/core_ext/enumerable"
6
7
  require "active_support/core_ext/module/attribute_accessors"
7
8
  require "active_support/core_ext/numeric/bytes"
8
9
  require "active_support/core_ext/numeric/time"
9
10
  require "active_support/core_ext/object/to_param"
11
+ require "active_support/core_ext/object/try"
10
12
  require "active_support/core_ext/string/inflections"
11
13
 
12
14
  module ActiveSupport
@@ -20,7 +22,7 @@ module ActiveSupport
20
22
 
21
23
  # These options mean something to all cache implementations. Individual cache
22
24
  # implementations may support additional options.
23
- UNIVERSAL_OPTIONS = [:namespace, :compress, :compress_threshold, :expires_in, :race_condition_ttl]
25
+ UNIVERSAL_OPTIONS = [:namespace, :compress, :compress_threshold, :expires_in, :race_condition_ttl, :coder]
24
26
 
25
27
  module Strategy
26
28
  autoload :LocalCache, "active_support/cache/strategy/local_cache"
@@ -79,7 +81,7 @@ module ActiveSupport
79
81
  #
80
82
  # The +key+ argument can also respond to +cache_key+ or +to_param+.
81
83
  def expand_cache_key(key, namespace = nil)
82
- expanded_cache_key = (namespace ? "#{namespace}/" : "").dup
84
+ expanded_cache_key = namespace ? +"#{namespace}/" : +""
83
85
 
84
86
  if prefix = ENV["RAILS_CACHE_ID"] || ENV["RAILS_APP_VERSION"]
85
87
  expanded_cache_key << "#{prefix}/"
@@ -156,6 +158,8 @@ module ActiveSupport
156
158
  # threshold is configurable with the <tt>:compress_threshold</tt> option,
157
159
  # specified in bytes.
158
160
  class Store
161
+ DEFAULT_CODER = Marshal
162
+
159
163
  cattr_accessor :logger, instance_writer: true
160
164
 
161
165
  attr_reader :silence, :options
@@ -183,6 +187,7 @@ module ActiveSupport
183
187
  # namespace for the cache.
184
188
  def initialize(options = nil)
185
189
  @options = options ? options.dup : {}
190
+ @coder = @options.delete(:coder) { self.class::DEFAULT_CODER } || NullCoder
186
191
  end
187
192
 
188
193
  # Silences the logger.
@@ -441,8 +446,8 @@ module ActiveSupport
441
446
  instrument :read_multi, names, options do |payload|
442
447
  reads = read_multi_entries(names, **options)
443
448
  writes = {}
444
- ordered = names.each_with_object({}) do |name, hash|
445
- hash[name] = reads.fetch(name) { writes[name] = yield(name) }
449
+ ordered = names.index_with do |name|
450
+ reads.fetch(name) { writes[name] = yield(name) }
446
451
  end
447
452
 
448
453
  payload[:hits] = reads.keys
@@ -477,6 +482,18 @@ module ActiveSupport
477
482
  end
478
483
  end
479
484
 
485
+ # Deletes multiple entries in the cache.
486
+ #
487
+ # Options are passed to the underlying cache implementation.
488
+ def delete_multi(names, options = nil)
489
+ options = merged_options(options)
490
+ names.map! { |key| normalize_key(key, options) }
491
+
492
+ instrument :delete_multi, names do
493
+ delete_multi_entries(names, **options)
494
+ end
495
+ end
496
+
480
497
  # Returns +true+ if the cache contains an entry for the given key.
481
498
  #
482
499
  # Options are passed to the underlying cache implementation.
@@ -567,26 +584,31 @@ module ActiveSupport
567
584
  raise NotImplementedError.new
568
585
  end
569
586
 
587
+ def serialize_entry(entry)
588
+ @coder.dump(entry)
589
+ end
590
+
591
+ def deserialize_entry(payload)
592
+ payload.nil? ? nil : @coder.load(payload)
593
+ end
594
+
570
595
  # Reads multiple entries from the cache implementation. Subclasses MAY
571
596
  # implement this method.
572
597
  def read_multi_entries(names, **options)
573
- results = {}
574
- names.each do |name|
575
- key = normalize_key(name, options)
598
+ names.each_with_object({}) do |name, results|
599
+ key = normalize_key(name, options)
600
+ entry = read_entry(key, **options)
601
+
602
+ next unless entry
603
+
576
604
  version = normalize_version(name, options)
577
- entry = read_entry(key, **options)
578
-
579
- if entry
580
- if entry.expired?
581
- delete_entry(key, **options)
582
- elsif entry.mismatched?(version)
583
- # Skip mismatched versions
584
- else
585
- results[name] = entry.value
586
- end
605
+
606
+ if entry.expired?
607
+ delete_entry(key, **options)
608
+ elsif !entry.mismatched?(version)
609
+ results[name] = entry.value
587
610
  end
588
611
  end
589
- results
590
612
  end
591
613
 
592
614
  # Writes multiple entries to the cache implementation. Subclasses MAY
@@ -603,6 +625,12 @@ module ActiveSupport
603
625
  raise NotImplementedError.new
604
626
  end
605
627
 
628
+ # Deletes multiples entries in the cache implementation. Subclasses MAY
629
+ # implement this method.
630
+ def delete_multi_entries(entries, **options)
631
+ entries.count { |key| delete_entry(key, **options) }
632
+ end
633
+
606
634
  # Merges the default options with ones specific to a method call.
607
635
  def merged_options(call_options)
608
636
  if call_options
@@ -639,6 +667,10 @@ module ActiveSupport
639
667
  namespace = namespace.call
640
668
  end
641
669
 
670
+ if key && key.encoding != Encoding::UTF_8
671
+ key = key.dup.force_encoding(Encoding::UTF_8)
672
+ end
673
+
642
674
  if namespace
643
675
  "#{namespace}:#{key}"
644
676
  else
@@ -655,15 +687,15 @@ module ActiveSupport
655
687
  case key
656
688
  when Array
657
689
  if key.size > 1
658
- key = key.collect { |element| expanded_key(element) }
690
+ key.collect { |element| expanded_key(element) }
659
691
  else
660
- key = expanded_key(key.first)
692
+ expanded_key(key.first)
661
693
  end
662
694
  when Hash
663
- key = key.sort_by { |k, _| k.to_s }.collect { |k, v| "#{k}=#{v}" }
664
- end
665
-
666
- key.to_param
695
+ key.collect { |k, v| "#{k}=#{v}" }.sort!
696
+ else
697
+ key
698
+ end.to_param
667
699
  end
668
700
 
669
701
  def normalize_version(key, options = nil)
@@ -673,24 +705,21 @@ module ActiveSupport
673
705
  def expanded_version(key)
674
706
  case
675
707
  when key.respond_to?(:cache_version) then key.cache_version.to_param
676
- when key.is_a?(Array) then key.map { |element| expanded_version(element) }.compact.to_param
708
+ when key.is_a?(Array) then key.map { |element| expanded_version(element) }.tap(&:compact!).to_param
677
709
  when key.respond_to?(:to_a) then expanded_version(key.to_a)
678
710
  end
679
711
  end
680
712
 
681
713
  def instrument(operation, key, options = nil)
682
- log { "Cache #{operation}: #{normalize_key(key, options)}#{options.blank? ? "" : " (#{options.inspect})"}" }
714
+ if logger && logger.debug? && !silence?
715
+ logger.debug "Cache #{operation}: #{normalize_key(key, options)}#{options.blank? ? "" : " (#{options.inspect})"}"
716
+ end
683
717
 
684
- payload = { key: key }
718
+ payload = { key: key, store: self.class.name }
685
719
  payload.merge!(options) if options.is_a?(Hash)
686
720
  ActiveSupport::Notifications.instrument("cache_#{operation}.active_support", payload) { yield(payload) }
687
721
  end
688
722
 
689
- def log
690
- return unless logger && logger.debug? && !silence?
691
- logger.debug(yield)
692
- end
693
-
694
723
  def handle_expired_entry(entry, key, options)
695
724
  if entry && entry.expired?
696
725
  race_ttl = options[:race_condition_ttl].to_i
@@ -722,6 +751,18 @@ module ActiveSupport
722
751
  end
723
752
  end
724
753
 
754
+ module NullCoder # :nodoc:
755
+ class << self
756
+ def load(payload)
757
+ payload
758
+ end
759
+
760
+ def dump(entry)
761
+ entry
762
+ end
763
+ end
764
+ end
765
+
725
766
  # This class is used to represent cache entries. Cache entries have a value, an optional
726
767
  # expiration time, and an optional version. The expiration time is used to support the :race_condition_ttl option
727
768
  # on the cache. The version is used to support the :version option on the cache for rejecting
@@ -772,8 +813,8 @@ module ActiveSupport
772
813
  end
773
814
 
774
815
  # Returns the size of the cached value. This could be less than
775
- # <tt>value.size</tt> if the data is compressed.
776
- def size
816
+ # <tt>value.bytesize</tt> if the data is compressed.
817
+ def bytesize
777
818
  case value
778
819
  when NilClass
779
820
  0
@@ -74,7 +74,7 @@ module ActiveSupport
74
74
  private
75
75
  def read_entry(key, **options)
76
76
  if File.exist?(key)
77
- entry = File.open(key) { |f| Marshal.load(f) }
77
+ entry = File.open(key) { |f| deserialize_entry(f.read) }
78
78
  entry if entry.is_a?(Cache::Entry)
79
79
  end
80
80
  rescue => e
@@ -85,7 +85,7 @@ module ActiveSupport
85
85
  def write_entry(key, entry, **options)
86
86
  return false if options[:unless_exist] && File.exist?(key)
87
87
  ensure_cache_path(File.dirname(key))
88
- File.atomic_write(key, cache_path) { |f| Marshal.dump(entry, f) }
88
+ File.atomic_write(key, cache_path) { |f| f.write(serialize_entry(entry)) }
89
89
  true
90
90
  end
91
91
 
@@ -7,6 +7,7 @@ rescue LoadError => e
7
7
  raise e
8
8
  end
9
9
 
10
+ require "active_support/core_ext/enumerable"
10
11
  require "active_support/core_ext/marshal"
11
12
  require "active_support/core_ext/array/extract_options"
12
13
 
@@ -25,6 +26,8 @@ module ActiveSupport
25
26
  # MemCacheStore implements the Strategy::LocalCache strategy which implements
26
27
  # an in-memory cache inside of a block.
27
28
  class MemCacheStore < Store
29
+ DEFAULT_CODER = NullCoder # Dalli automatically Marshal values
30
+
28
31
  # Provide support for raw values in the local cache strategy.
29
32
  module LocalCacheWithRaw # :nodoc:
30
33
  private
@@ -50,16 +53,18 @@ module ActiveSupport
50
53
  ESCAPE_KEY_CHARS = /[\x00-\x20%\x7F-\xFF]/n
51
54
 
52
55
  # Creates a new Dalli::Client instance with specified addresses and options.
53
- # 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)
54
59
  #
55
60
  # ActiveSupport::Cache::MemCacheStore.build_mem_cache
56
- # # => #<Dalli::Client:0x007f98a47d2028 @servers=["localhost:11211"], @options={}, @ring=nil>
61
+ # # => #<Dalli::Client:0x007f98a47d2028 @servers=["127.0.0.1:11211"], @options={}, @ring=nil>
57
62
  # ActiveSupport::Cache::MemCacheStore.build_mem_cache('localhost:10290')
58
63
  # # => #<Dalli::Client:0x007f98a47b3a60 @servers=["localhost:10290"], @options={}, @ring=nil>
59
64
  def self.build_mem_cache(*addresses) # :nodoc:
60
65
  addresses = addresses.flatten
61
66
  options = addresses.extract_options!
62
- addresses = ["localhost:11211"] if addresses.empty?
67
+ addresses = nil if addresses.empty?
63
68
  pool_options = retrieve_pool_options(options)
64
69
 
65
70
  if pool_options.empty?
@@ -76,8 +81,8 @@ module ActiveSupport
76
81
  #
77
82
  # ActiveSupport::Cache::MemCacheStore.new("localhost", "server-downstairs.localnetwork:8229")
78
83
  #
79
- # If no addresses are specified, then MemCacheStore will connect to
80
- # 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).
81
86
  def initialize(*addresses)
82
87
  addresses = addresses.flatten
83
88
  options = addresses.extract_options!
@@ -140,21 +145,22 @@ module ActiveSupport
140
145
 
141
146
  # Write an entry to the cache.
142
147
  def write_entry(key, entry, **options)
143
- method = options && options[:unless_exist] ? :add : :set
144
- value = options[:raw] ? entry.value.to_s : entry
148
+ method = options[:unless_exist] ? :add : :set
149
+ value = options[:raw] ? entry.value.to_s : serialize_entry(entry)
145
150
  expires_in = options[:expires_in].to_i
146
- if expires_in > 0 && !options[:raw]
151
+ if options[:race_condition_ttl] && expires_in > 0 && !options[:raw]
147
152
  # Set the memcache expire a few minutes in the future to support race condition ttls on read
148
153
  expires_in += 5.minutes
149
154
  end
150
155
  rescue_error_with false do
151
- @data.with { |c| c.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) }
152
158
  end
153
159
  end
154
160
 
155
161
  # Reads multiple entries from the cache implementation.
156
162
  def read_multi_entries(names, **options)
157
- keys_to_names = Hash[names.map { |name| [normalize_key(name, options), name] }]
163
+ keys_to_names = names.index_by { |name| normalize_key(name, options) }
158
164
 
159
165
  raw_values = @data.with { |c| c.get_multi(keys_to_names.keys) }
160
166
  values = {}
@@ -186,10 +192,10 @@ module ActiveSupport
186
192
  key
187
193
  end
188
194
 
189
- def deserialize_entry(entry)
190
- if entry
191
- entry.is_a?(Entry) ? entry : Entry.new(entry)
192
- end
195
+ def deserialize_entry(payload)
196
+ entry = super
197
+ entry = Entry.new(entry, compress: false) if entry && !entry.is_a?(Entry)
198
+ entry
193
199
  end
194
200
 
195
201
  def rescue_error_with(fallback)