diff --git a/activesupport/lib/active_support/cache.rb b/activesupport/lib/active_support/cache.rb
index f1cfe5e81a..246692837a 100644
--- a/activesupport/lib/active_support/cache.rb
+++ b/activesupport/lib/active_support/cache.rb
@@ -22,7 +22,12 @@ module ActiveSupport
# These options mean something to all cache implementations. Individual cache
# implementations may support additional options.
- UNIVERSAL_OPTIONS = [:namespace, :compress, :compress_threshold, :expires_in, :race_condition_ttl, :coder, :skip_nil]
+ UNIVERSAL_OPTIONS = [:namespace, :compress, :compress_threshold, :expires_in, :expire_in, :expired_in, :race_condition_ttl, :coder, :skip_nil]
+
+ # Mapping of canonical option names to aliases that a store will recognize.
+ OPTION_ALIASES = {
+ expires_in: [:expire_in, :expired_in]
+ }.freeze
module Strategy
autoload :LocalCache, "active_support/cache/strategy/local_cache"
@@ -186,7 +191,7 @@ module ActiveSupport
# except for :namespace which can be used to set the global
# namespace for the cache.
def initialize(options = nil)
- @options = options ? options.dup : {}
+ @options = options ? normalize_options(options) : {}
@coder = @options.delete(:coder) { self.class::DEFAULT_CODER } || NullCoder
end
@@ -249,7 +254,9 @@ module ActiveSupport
# All caches support auto-expiring content after a specified number of
# seconds. This value can be specified as an option to the constructor
# (in which case all entries will be affected), or it can be supplied to
- # the +fetch+ or +write+ method to effect just one entry.
+ # the +fetch+ or +write+ method to affect just one entry.
+ # :expire_in and :expired_in are aliases for
+ # :expires_in.
#
# cache = ActiveSupport::Cache::MemoryStore.new(expires_in: 5.minutes)
# cache.write(key, value, expires_in: 1.minute) # Set a lower value for one entry
@@ -634,6 +641,7 @@ module ActiveSupport
# Merges the default options with ones specific to a method call.
def merged_options(call_options)
if call_options
+ call_options = normalize_options(call_options)
if options.empty?
call_options
else
@@ -644,6 +652,17 @@ module ActiveSupport
end
end
+ # Normalize aliased options to their canonical form
+ def normalize_options(options)
+ options = options.dup
+ OPTION_ALIASES.each do |canonical_name, aliases|
+ alias_key = aliases.detect { |key| options.key?(key) }
+ options[canonical_name] ||= options[alias_key] if alias_key
+ options.except!(*aliases)
+ end
+ options
+ end
+
# Expands and namespaces the cache key. May be overridden by
# cache stores to do additional normalization.
def normalize_key(key, options = nil)
diff --git a/activesupport/test/cache/behaviors/cache_store_behavior.rb b/activesupport/test/cache/behaviors/cache_store_behavior.rb
index a44b9696ee..429d5e106f 100644
--- a/activesupport/test/cache/behaviors/cache_store_behavior.rb
+++ b/activesupport/test/cache/behaviors/cache_store_behavior.rb
@@ -406,6 +406,40 @@ module CacheStoreBehavior
end
end
+ def test_expire_in_is_alias_for_expires_in
+ time = Time.local(2008, 4, 24)
+
+ Time.stub(:now, time) do
+ @cache.write("foo", "bar", expire_in: 20)
+ assert_equal "bar", @cache.read("foo")
+ end
+
+ Time.stub(:now, time + 10) do
+ assert_equal "bar", @cache.read("foo")
+ end
+
+ Time.stub(:now, time + 21) do
+ assert_nil @cache.read("foo")
+ end
+ end
+
+ def test_expired_in_is_alias_for_expires_in
+ time = Time.local(2008, 4, 24)
+
+ Time.stub(:now, time) do
+ @cache.write("foo", "bar", expired_in: 20)
+ assert_equal "bar", @cache.read("foo")
+ end
+
+ Time.stub(:now, time + 10) do
+ assert_equal "bar", @cache.read("foo")
+ end
+
+ Time.stub(:now, time + 21) do
+ assert_nil @cache.read("foo")
+ end
+ end
+
def test_race_condition_protection_skipped_if_not_defined
@cache.write("foo", "bar")
time = @cache.send(:read_entry, @cache.send(:normalize_key, "foo", {}), **{}).expires_at