mirror of
https://github.com/rails/rails.git
synced 2022-11-09 12:12:34 -05:00
Limit Array#extract_options! to directl instances of Hash and HWIA. Add extractable_options? to Hash so that subclasses of Hash can opt-into extractable behavior. This fixes an issue where respond_with wasn't working with subclasses of Hash that were provided by other libraries (such as CouchDB or Mashie) [#4145 state:resolved]
This commit is contained in:
parent
b081948bb3
commit
a24a888afe
3 changed files with 54 additions and 1 deletions
|
@ -1,3 +1,14 @@
|
|||
class Hash
|
||||
# By default, only instances of Hash itself are extractable.
|
||||
# Subclasses of Hash may implement this method and return
|
||||
# true to declare themselves as extractable. If a Hash
|
||||
# is extractable, Array#extract_options! pops it from
|
||||
# the Array when it is the last element of the Array.
|
||||
def extractable_options?
|
||||
instance_of?(Hash)
|
||||
end
|
||||
end
|
||||
|
||||
class Array
|
||||
# Extracts options from a set of arguments. Removes and returns the last
|
||||
# element in the array if it's a hash, otherwise returns a blank hash.
|
||||
|
@ -9,6 +20,10 @@ class Array
|
|||
# options(1, 2) # => {}
|
||||
# options(1, 2, :a => :b) # => {:a=>:b}
|
||||
def extract_options!
|
||||
last.is_a?(::Hash) ? pop : {}
|
||||
if last.is_a?(Hash) && last.extractable_options?
|
||||
pop
|
||||
else
|
||||
{}
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -4,6 +4,10 @@
|
|||
|
||||
module ActiveSupport
|
||||
class HashWithIndifferentAccess < Hash
|
||||
def extractable_options?
|
||||
true
|
||||
end
|
||||
|
||||
def initialize(constructor = {})
|
||||
if constructor.is_a?(Hash)
|
||||
super()
|
||||
|
|
|
@ -4,6 +4,7 @@ require 'active_support/core_ext/big_decimal'
|
|||
require 'active_support/core_ext/object/conversions'
|
||||
|
||||
require 'active_support/core_ext' # FIXME: pulling in all to_xml extensions
|
||||
require 'active_support/hash_with_indifferent_access'
|
||||
|
||||
class ArrayExtAccessTests < Test::Unit::TestCase
|
||||
def test_from
|
||||
|
@ -294,12 +295,45 @@ class ArrayToXmlTests < Test::Unit::TestCase
|
|||
end
|
||||
|
||||
class ArrayExtractOptionsTests < Test::Unit::TestCase
|
||||
class HashSubclass < Hash
|
||||
end
|
||||
|
||||
class ExtractableHashSubclass < Hash
|
||||
def extractable_options?
|
||||
true
|
||||
end
|
||||
end
|
||||
|
||||
def test_extract_options
|
||||
assert_equal({}, [].extract_options!)
|
||||
assert_equal({}, [1].extract_options!)
|
||||
assert_equal({:a=>:b}, [{:a=>:b}].extract_options!)
|
||||
assert_equal({:a=>:b}, [1, {:a=>:b}].extract_options!)
|
||||
end
|
||||
|
||||
def test_extract_options_doesnt_extract_hash_subclasses
|
||||
hash = HashSubclass.new
|
||||
hash[:foo] = 1
|
||||
array = [hash]
|
||||
options = array.extract_options!
|
||||
assert_equal({}, options)
|
||||
assert_equal [hash], array
|
||||
end
|
||||
|
||||
def test_extract_options_extracts_extractable_subclass
|
||||
hash = ExtractableHashSubclass.new
|
||||
hash[:foo] = 1
|
||||
array = [hash]
|
||||
options = array.extract_options!
|
||||
assert_equal({:foo => 1}, options)
|
||||
assert_equal [], array
|
||||
end
|
||||
|
||||
def test_extract_options_extracts_hwia
|
||||
hash = [{:foo => 1}.with_indifferent_access]
|
||||
options = hash.extract_options!
|
||||
assert_equal 1, options[:foo]
|
||||
end
|
||||
end
|
||||
|
||||
class ArrayUniqByTests < Test::Unit::TestCase
|
||||
|
|
Loading…
Reference in a new issue