diff --git a/activesupport/CHANGELOG b/activesupport/CHANGELOG index 307cc7f405ff258e8fab4f18e16eb23531d791ba..78978ac9817cdfca5e2fa123c2d3ded781167417 100644 --- a/activesupport/CHANGELOG +++ b/activesupport/CHANGELOG @@ -1,5 +1,7 @@ *SVN* +* Adding Hash#without Closes #7369 [eventualbuddha] + * TimeWithZone#method_missing: send to utc to advance with dst correctness, otherwise send to time. Adding tests for time calculations methods [Geoff Buesing] * Add config.active_support.use_standard_json_time_format setting so that Times and Dates export to ISO 8601 dates. [rick] diff --git a/activesupport/lib/active_support/core_ext/hash/slice.rb b/activesupport/lib/active_support/core_ext/hash/slice.rb index 6fe5e05330e282558023ff53fb5e26a47ff4c9d4..c270e3906ba343b759c50279c0fa11ddffac48aa 100644 --- a/activesupport/lib/active_support/core_ext/hash/slice.rb +++ b/activesupport/lib/active_support/core_ext/hash/slice.rb @@ -11,6 +11,11 @@ module Hash #:nodoc: # end # # search(options.slice(:mass, :velocity, :time)) + # + # Also allows leaving out certain keys. This is useful when duplicating + # a hash but omitting a certain subset: + # + # Event.new(event.attributes.without(:id, :user_id)) module Slice # Returns a new hash with only the given keys. def slice(*keys) @@ -22,6 +27,17 @@ def slice(*keys) def slice!(*keys) replace(slice(*keys)) end + + # Returns a new hash without the given keys. + def without(*keys) + allowed = self.keys - (respond_to?(:convert_key) ? keys.map { |key| convert_key(key) } : keys) + slice(*allowed) + end + + # Replaces the hash without the given keys. + def without!(*keys) + replace(without(*keys)) + 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 706e218abc7d47cac9567312b397c0d6f4f0041d..9d1d6ec33f41c3be85c6275af39f3ba5e6e4413a 100644 --- a/activesupport/test/core_ext/hash_ext_test.rb +++ b/activesupport/test/core_ext/hash_ext_test.rb @@ -310,6 +310,38 @@ def test_except assert_equal expected, original.except!(:c) assert_equal expected, original end + + def test_without + original = { :a => 'x', :b => 'y', :c => 10 } + expected = { :a => 'x' } + + # Should return a hash without the given keys. + assert_equal expected, original.without(:b, :c) + assert_not_equal expected, original + + # Should ignore non-existant keys. + assert_equal expected, original.without(:b, :c, :d) + + # Should replace the hash with the given keys taken away. + assert_equal expected, original.without!(:b, :c) + assert_equal expected, original + end + + def test_indifferent_without + original = { :a => 'x', :b => 'y', :c => 10 }.with_indifferent_access + expected = { :c => 10 }.with_indifferent_access + + [['a', 'b'], [:a, :b]].each do |keys| + # Should return a new hash without the given keys. + assert_equal expected, original.without(*keys), keys.inspect + assert_not_equal expected, original + + # Should replace the hash without the given keys. + copy = original.dup + assert_equal expected, copy.without!(*keys) + assert_equal expected, copy + end + end end class IWriteMyOwnXML