Created
November 30, 2012 23:32
-
-
Save jrunning/4179488 to your computer and use it in GitHub Desktop.
Hash#deep_exclude
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| require 'test/unit/assertions' | |
| include Test::Unit::Assertions | |
| class Hash | |
| # A convenience method for removing deeply-nested keys from a Hash | |
| # | |
| # Usage: | |
| # | |
| # hash = { :a => { :m => 13 }, :b => 2 } | |
| # | |
| # hash.deep_exclude(:a) # ⇒ { :b => 2 } | |
| # hash.deep_exclude(:a => :m) # ⇒ { :a => {}, :b => 2 } | |
| # hash.deep_exclude(:b, :a => :m) # ⇒ { :a => {} } | |
| # hash.deep_exclude(:a, :b) # ⇒ {} | |
| # | |
| # TODO: | |
| # | |
| # * Fix some edge cases (see tests) | |
| # | |
| def deep_exclude *excludes | |
| result = self.dup | |
| return result if excludes.empty? | |
| exclude = excludes.shift | |
| if exclude.is_a? Hash | |
| exclude.each do |key,val| | |
| if result.key?(key) && result[key].respond_to?(:deep_exclude) | |
| result[key] = result[key].deep_exclude *val | |
| end | |
| end | |
| else | |
| result.delete exclude | |
| end | |
| result.deep_exclude *excludes | |
| end | |
| end | |
| hash = { a: 1, b: 2 } | |
| assert_equal( { b: 2 }, hash.deep_exclude(:a) ) | |
| assert_equal( {}, hash.deep_exclude(:a, :b) ) | |
| assert_equal( { b: 2 }, hash.deep_exclude(:a, :z) ) | |
| # All values are compared only to the hash's keys (no match on values) | |
| assert_equal( { a: 1, b: 2 }, hash.deep_exclude(a: 1) ) | |
| # Falsy keys work too | |
| hash = { nil => 1, false => 2 } | |
| assert_equal( { nil => 1 }, hash.deep_exclude(false) ) | |
| assert_equal( { false => 2 }, hash.deep_exclude(nil) ) | |
| hash = { :a => { nil => 0 } } | |
| #assert_equal( { :a => {} }, hash.deep_exclude(:a => nil) ) | |
| # Keys that are arrays are allowed | |
| key = [:a, :b] | |
| hash = { key => 1, :b => 2, :c => 3 } | |
| assert_equal( { b: 2, c: 3}, hash.deep_exclude(key) ) | |
| # If the array contains the intended keys, expand it with splat first | |
| assert_equal( { key => 1, c: 3}, hash.deep_exclude(*key) ) | |
| hash = { a: { m: 13 }, b: { n: 14 } } | |
| # The entire subtree is removed from the given root | |
| assert_equal( { a: { m: 13 } }, | |
| hash.deep_exclude(:b) ) | |
| # A nested root can be given | |
| assert_equal( { a: { m: 13 }, b: {} }, | |
| hash.deep_exclude(:b => :n) ) | |
| # Nth-level arguments only match Nth level | |
| assert_equal( { a: { m: 13 } }, | |
| hash.deep_exclude(:b, :m) ) | |
| # Empty hashes are left in place | |
| assert_equal( { b: {} }, | |
| hash.deep_exclude(:a, :b => :n) ) | |
| # Only keys are matched (as above) | |
| assert_equal( { a: { m: 13 }, b: { n: 14 } }, | |
| hash.deep_exclude(:b => { :n => 14 }) ) | |
| hash = { a: { m: { z: 1 } } } | |
| assert_equal( { a: { m: {} } }, | |
| hash.deep_exclude(:a => { :m => :z }) ) | |
| hash = { a: 1, b: { m: 13, n: 14, o: { x: 24, y: 25 } } } | |
| # An array can be given for levels after the first | |
| assert_equal( { a: 1, b: { n: 14 } }, | |
| hash.deep_exclude(:b => [ :m, :o ]) ) | |
| assert_equal( { a: 1, b: { m: 13, n: 14, o: { y: 25 } } }, | |
| hash.deep_exclude(:b => [ { :o => :x } ] ) ) | |
| hash = { a: { m: 13, n: { x: 24, y: 25 } }, b: 2, c: { o: 15 } } | |
| # Arrays can contain hashes | |
| assert_equal( { a: { n: { x: 24 } }, b: 2 }, | |
| hash.deep_exclude(:c, { :a => [ :m, { :n => :y } ] }) ) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment