diff --git a/activesupport/lib/active_support/core_ext/object/with_options.rb b/activesupport/lib/active_support/core_ext/object/with_options.rb
index 11985fa828..3225bab4ca 100644
--- a/activesupport/lib/active_support/core_ext/object/with_options.rb
+++ b/activesupport/lib/active_support/core_ext/object/with_options.rb
@@ -5,9 +5,9 @@
class Object
# An elegant way to factor duplication out of options passed to a series of
# method calls. Each method called in the block, with the block variable as
- # the receiver, will have its options merged with the default +options+ hash
- # provided. Each method called on the block variable must take an options
- # hash as its final argument.
+ # the receiver, will have its options merged with the default +options+
+ # Hash or Hash-like object provided. Each method called on
+ # the block variable must take an options hash as its final argument.
#
# Without with_options, this code contains duplication:
#
diff --git a/activesupport/test/option_merger_test.rb b/activesupport/test/option_merger_test.rb
index bb66f51bab..54195024a9 100644
--- a/activesupport/test/option_merger_test.rb
+++ b/activesupport/test/option_merger_test.rb
@@ -114,6 +114,21 @@ def test_option_merger_implicit_receiver
assert_equal expected, @options
end
+ def test_with_options_hash_like
+ hash_like = Class.new do
+ delegate :to_hash, :deep_merge, to: :@hash
+
+ def initialize(hash)
+ @hash = hash
+ end
+ end
+ local_options = { "cool" => true }
+ scope = with_options(hash_like.new(@options))
+
+ assert_equal local_options, method_with_options(local_options)
+ assert_equal @options.merge(local_options), scope.method_with_options(local_options)
+ end
+
def test_with_options_no_block
local_options = { "cool" => true }
scope = with_options(@options)