aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--activesupport/CHANGELOG2
-rw-r--r--activesupport/lib/active_support/core_ext/hash.rb9
-rw-r--r--activesupport/lib/active_support/core_ext/hash/slice.rb28
-rw-r--r--activesupport/test/core_ext/hash_ext_test.rb29
4 files changed, 63 insertions, 5 deletions
diff --git a/activesupport/CHANGELOG b/activesupport/CHANGELOG
index 9f5c98a1cd..a97cba31ee 100644
--- a/activesupport/CHANGELOG
+++ b/activesupport/CHANGELOG
@@ -1,5 +1,7 @@
*SVN*
+* Hash#slice(*keys) returns a new hash with only the given keys. #slice! replaces the hash with only the given keys. Works with HashWithIndifferentAccess also. [Jeremy Kemper]
+
* HashWithIndifferentAccess#to_hash converts to a Hash with String keys and the same default value. [Jeremy Kemper]
* Fix remove_constant to correctly handle constant names of the form "::A::...". References #6720. [Nicholas Seckar]
diff --git a/activesupport/lib/active_support/core_ext/hash.rb b/activesupport/lib/active_support/core_ext/hash.rb
index 7d94d70910..2a99468b4e 100644
--- a/activesupport/lib/active_support/core_ext/hash.rb
+++ b/activesupport/lib/active_support/core_ext/hash.rb
@@ -1,8 +1,6 @@
-require File.dirname(__FILE__) + '/hash/keys'
-require File.dirname(__FILE__) + '/hash/indifferent_access'
-require File.dirname(__FILE__) + '/hash/reverse_merge'
-require File.dirname(__FILE__) + '/hash/conversions'
-require File.dirname(__FILE__) + '/hash/diff'
+%w(keys indifferent_access reverse_merge conversions diff slice).each do |ext|
+ require "#{File.dirname(__FILE__)}/hash/#{ext}"
+end
class Hash #:nodoc:
include ActiveSupport::CoreExtensions::Hash::Keys
@@ -10,4 +8,5 @@ class Hash #:nodoc:
include ActiveSupport::CoreExtensions::Hash::ReverseMerge
include ActiveSupport::CoreExtensions::Hash::Conversions
include ActiveSupport::CoreExtensions::Hash::Diff
+ include ActiveSupport::CoreExtensions::Hash::Slice
end
diff --git a/activesupport/lib/active_support/core_ext/hash/slice.rb b/activesupport/lib/active_support/core_ext/hash/slice.rb
new file mode 100644
index 0000000000..6fe5e05330
--- /dev/null
+++ b/activesupport/lib/active_support/core_ext/hash/slice.rb
@@ -0,0 +1,28 @@
+require 'set'
+
+module ActiveSupport #:nodoc:
+ module CoreExtensions #:nodoc:
+ module Hash #:nodoc:
+ # Slice a hash to include only the given keys. This is useful for
+ # limiting an options hash to valid keys before passing to a method:
+ #
+ # def search(criteria = {})
+ # assert_valid_keys(:mass, :velocity, :time)
+ # end
+ #
+ # search(options.slice(:mass, :velocity, :time))
+ module Slice
+ # Returns a new hash with only the given keys.
+ def slice(*keys)
+ allowed = Set.new(respond_to?(:convert_key) ? keys.map { |key| convert_key(key) } : keys)
+ reject { |key,| !allowed.include?(key) }
+ end
+
+ # Replaces the hash with only the given keys.
+ def slice!(*keys)
+ replace(slice(*keys))
+ end
+ end
+ end
+ end
+end
diff --git a/activesupport/test/core_ext/hash_ext_test.rb b/activesupport/test/core_ext/hash_ext_test.rb
index 8e20f15518..90468fd5a9 100644
--- a/activesupport/test/core_ext/hash_ext_test.rb
+++ b/activesupport/test/core_ext/hash_ext_test.rb
@@ -243,6 +243,35 @@ class HashExtTest < Test::Unit::TestCase
def test_diff
assert_equal({ :a => 2 }, { :a => 2, :b => 5 }.diff({ :a => 1, :b => 5 }))
end
+
+ def test_slice
+ original = { :a => 'x', :b => 'y', :c => 10 }
+ expected = { :a => 'x', :b => 'y' }
+
+ # Should return a new hash with only the given keys.
+ assert_equal expected, original.slice(:a, :b)
+ assert_not_equal expected, original
+
+ # Should replace the hash with only the given keys.
+ assert_equal expected, original.slice!(:a, :b)
+ assert_equal expected, original
+ end
+
+ def test_indifferent_slice
+ original = { :a => 'x', :b => 'y', :c => 10 }.with_indifferent_access
+ expected = { :a => 'x', :b => 'y' }.with_indifferent_access
+
+ [['a', 'b'], [:a, :b]].each do |keys|
+ # Should return a new hash with only the given keys.
+ assert_equal expected, original.slice(*keys), keys.inspect
+ assert_not_equal expected, original
+
+ # Should replace the hash with only the given keys.
+ copy = original.dup
+ assert_equal expected, copy.slice!(*keys)
+ assert_equal expected, copy
+ end
+ end
end
class IWriteMyOwnXML