Class: Hash
- Defined in:
- motion/core_ext/hash/keys.rb,
motion/core_ext/hash/slice.rb,
motion/core_ext/hash/except.rb,
motion/core_ext/object/blank.rb,
motion/core_ext/object/to_json.rb,
motion/core_ext/hash/deep_merge.rb,
motion/core_ext/object/deep_dup.rb,
motion/core_ext/hash/reverse_merge.rb,
motion/core_ext/hash/deep_delete_if.rb,
motion/core_ext/hash/indifferent_access.rb
Direct Known Subclasses
Instance Method Summary collapse
-
#as_json ⇒ Object
Ensure there are valid keys/values.
-
#assert_valid_keys(*valid_keys) ⇒ Object
Validate all keys in a hash match
*valid_keys
, raising ArgumentError on a mismatch. -
#deep_delete_if(&block) ⇒ Object
Returns a new hash with keys deleted if they match a criteria h1 = { x: { y: [ { z: 4, y: 1 }, 5, 6] }, a: { b: 2 } }.
-
#deep_dup ⇒ Object
Returns a deep copy of hash.
-
#deep_merge(other_hash, &block) ⇒ Object
Returns a new hash with
self
andother_hash
merged recursively. -
#deep_merge!(other_hash, &block) ⇒ Object
Same as
deep_merge
, but modifiesself
. -
#deep_stringify_keys ⇒ Object
Return a new hash with all keys converted to strings.
-
#deep_stringify_keys! ⇒ Object
Destructively convert all keys to strings.
-
#deep_symbolize_keys ⇒ Object
Return a new hash with all keys converted to symbols, as long as they respond to
to_sym
. -
#deep_symbolize_keys! ⇒ Object
Destructively convert all keys to symbols, as long as they respond to
to_sym
. -
#deep_transform_keys(&block) ⇒ Object
Return a new hash with all keys converted by the block operation.
-
#deep_transform_keys!(&block) ⇒ Object
Destructively convert all keys by using the block operation.
-
#except(*keys) ⇒ Object
Return a hash that includes everything but the given keys.
-
#except!(*keys) ⇒ Object
Replaces the hash without the given keys.
-
#extract!(*keys) ⇒ Object
Removes and returns the key/value pairs matching the given keys.
-
#reverse_merge(other_hash) ⇒ Object
Merges the caller into
other_hash
. -
#reverse_merge!(other_hash) ⇒ Object
(also: #reverse_update)
Destructive
reverse_merge
. -
#slice(*keys) ⇒ Object
Slice a hash to include only the given keys.
-
#slice!(*keys) ⇒ Object
Replaces the hash with only the given keys.
-
#stringify_keys ⇒ Object
Return a new hash with all keys converted to strings.
-
#stringify_keys! ⇒ Object
Destructively convert all keys to strings.
-
#symbolize_keys ⇒ Object
(also: #to_options)
Return a new hash with all keys converted to symbols, as long as they respond to
to_sym
. -
#symbolize_keys! ⇒ Object
(also: #to_options!)
Destructively convert all keys to symbols, as long as they respond to
to_sym
. -
#to_json ⇒ Object
Serializes the hash object using Cocoa’s NSJSONSerialization.
-
#to_param(namespace = nil) ⇒ Object
(also: #to_query)
Returns a string representation of the receiver suitable for use as a URL query string:.
-
#transform_keys ⇒ Object
Return a new hash with all keys converted using the block operation.
-
#transform_keys! ⇒ Object
Destructively convert all keys using the block operations.
-
#with_indifferent_access ⇒ Object
(also: #nested_under_indifferent_access)
Returns an
MotionSupport::HashWithIndifferentAccess
out of its receiver:.
Instance Method Details
#as_json ⇒ Object
Ensure there are valid keys/values
137 138 139 |
# File 'motion/core_ext/object/to_json.rb', line 137 def as_json Hash[map { |k,v| [k.to_s, (v.respond_to?(:as_json) ? v.as_json : v)] }] end |
#assert_valid_keys(*valid_keys) ⇒ Object
Validate all keys in a hash match *valid_keys
, raising ArgumentError on a mismatch. Note that keys are NOT treated indifferently, meaning if you use strings for keys but assert symbols as keys, this will fail.
{ name: 'Rob', years: '28' }.assert_valid_keys(:name, :age) # => raises "ArgumentError: Unknown key: years"
{ name: 'Rob', age: '28' }.assert_valid_keys('name', 'age') # => raises "ArgumentError: Unknown key: name"
{ name: 'Rob', age: '28' }.assert_valid_keys(:name, :age) # => passes, raises nothing
67 68 69 70 71 72 |
# File 'motion/core_ext/hash/keys.rb', line 67 def assert_valid_keys(*valid_keys) valid_keys.flatten! each_key do |k| raise ArgumentError.new("Unknown key: #{k}") unless valid_keys.include?(k) end end |
#deep_delete_if(&block) ⇒ Object
Returns a new hash with keys deleted if they match a criteria
h1 = { x: { y: [ { z: 4, y: 1 }, 5, 6] }, a: { b: 2 } }
h1.deep_delete { |k,v| k == :z } #=> { x: { y: [ { y: 1 }, 5, 6] }, a: { b: 2 } }
h1.deep_delete { |k,v| k == :y } #=> { x: {}, a: { b: 2 } }
7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
# File 'motion/core_ext/hash/deep_delete_if.rb', line 7 def deep_delete_if(&block) result = {} each do |key, value| next if block.call(key, value) result[key] = if value.is_a?(Hash) value.deep_delete_if(&block) elsif value.is_a?(Array) value.map { |v| v.is_a?(Hash) ? v.deep_delete_if(&block) : v } else value end end result end |
#deep_dup ⇒ Object
Returns a deep copy of hash.
hash = { a: { b: 'b' } }
dup = hash.deep_dup
dup[:a][:c] = 'c'
hash[:a][:c] #=> nil
dup[:a][:c] #=> "c"
39 40 41 42 43 |
# File 'motion/core_ext/object/deep_dup.rb', line 39 def deep_dup each_with_object(dup) do |(key, value), hash| hash[key.deep_dup] = value.deep_dup end end |
#deep_merge(other_hash, &block) ⇒ Object
Returns a new hash with self
and other_hash
merged recursively.
h1 = { x: { y: [4,5,6] }, z: [7,8,9] }
h2 = { x: { y: [7,8,9] }, z: 'xyz' }
h1.deep_merge(h2) #=> {x: {y: [7, 8, 9]}, z: "xyz"}
h2.deep_merge(h1) #=> {x: {y: [4, 5, 6]}, z: [7, 8, 9]}
h1.deep_merge(h2) { |key, old, new| Array.wrap(old) + Array.wrap(new) }
#=> {:x=>{:y=>[4, 5, 6, 7, 8, 9]}, :z=>[7, 8, 9, "xyz"]}
11 12 13 |
# File 'motion/core_ext/hash/deep_merge.rb', line 11 def deep_merge(other_hash, &block) dup.deep_merge!(other_hash, &block) end |
#deep_merge!(other_hash, &block) ⇒ Object
Same as deep_merge
, but modifies self
.
16 17 18 19 20 21 22 23 24 25 26 |
# File 'motion/core_ext/hash/deep_merge.rb', line 16 def deep_merge!(other_hash, &block) other_hash.each_pair do |k,v| tv = self[k] if tv.is_a?(Hash) && v.is_a?(Hash) self[k] = tv.deep_merge(v, &block) else self[k] = block && tv ? block.call(k, tv, v) : v end end self end |
#deep_stringify_keys ⇒ Object
Return a new hash with all keys converted to strings. This includes the keys from the root hash and from all nested hashes.
hash = { person: { name: 'Rob', age: '28' } }
hash.deep_stringify_keys
# => { "person" => { "name" => "Rob", "age" => "28" } }
121 122 123 |
# File 'motion/core_ext/hash/keys.rb', line 121 def deep_stringify_keys deep_transform_keys{ |key| key.to_s } end |
#deep_stringify_keys! ⇒ Object
Destructively convert all keys to strings. This includes the keys from the root hash and from all nested hashes.
128 129 130 |
# File 'motion/core_ext/hash/keys.rb', line 128 def deep_stringify_keys! deep_transform_keys!{ |key| key.to_s } end |
#deep_symbolize_keys ⇒ Object
Return a new hash with all keys converted to symbols, as long as they respond to to_sym
. This includes the keys from the root hash and from all nested hashes.
hash = { 'person' => { 'name' => 'Rob', 'age' => '28' } }
hash.deep_symbolize_keys
# => { person: { name: "Rob", age: "28" } }
140 141 142 |
# File 'motion/core_ext/hash/keys.rb', line 140 def deep_symbolize_keys deep_transform_keys{ |key| key.to_sym rescue key } end |
#deep_symbolize_keys! ⇒ Object
Destructively convert all keys to symbols, as long as they respond to to_sym
. This includes the keys from the root hash and from all nested hashes.
147 148 149 |
# File 'motion/core_ext/hash/keys.rb', line 147 def deep_symbolize_keys! deep_transform_keys!{ |key| key.to_sym rescue key } end |
#deep_transform_keys(&block) ⇒ Object
Return a new hash with all keys converted by the block operation. This includes the keys from the root hash and from all nested hashes.
hash = { person: { name: 'Rob', age: '28' } }
hash.deep_transform_keys{ |key| key.to_s.upcase }
# => { "PERSON" => { "NAME" => "Rob", "AGE" => "28" } }
82 83 84 85 86 87 88 89 90 91 92 93 94 |
# File 'motion/core_ext/hash/keys.rb', line 82 def deep_transform_keys(&block) result = {} each do |key, value| result[yield(key)] = if value.is_a?(Hash) value.deep_transform_keys(&block) elsif value.is_a?(Array) value.map { |v| v.is_a?(Hash) ? v.deep_transform_keys(&block) : v } else value end end result end |
#deep_transform_keys!(&block) ⇒ Object
Destructively convert all keys by using the block operation. This includes the keys from the root hash and from all nested hashes.
99 100 101 102 103 104 105 106 107 108 109 110 111 |
# File 'motion/core_ext/hash/keys.rb', line 99 def deep_transform_keys!(&block) keys.each do |key| value = delete(key) self[yield(key)] = if value.is_a?(Hash) value.deep_transform_keys(&block) elsif value.is_a?(Array) value.map { |v| v.is_a?(Hash) ? v.deep_transform_keys(&block) : v } else value end end self end |
#except(*keys) ⇒ Object
Return a hash that includes everything but the given keys. This is useful for limiting a set of parameters to everything but a few known toggles:
@person.update(params[:person].except(:admin))
6 7 8 |
# File 'motion/core_ext/hash/except.rb', line 6 def except(*keys) dup.except!(*keys) end |
#except!(*keys) ⇒ Object
Replaces the hash without the given keys.
11 12 13 14 |
# File 'motion/core_ext/hash/except.rb', line 11 def except!(*keys) keys.each { |key| delete(key) } self end |
#extract!(*keys) ⇒ Object
Removes and returns the key/value pairs matching the given keys.
{ a: 1, b: 2, c: 3, d: 4 }.extract!(:a, :b) # => {:a=>1, :b=>2}
{ a: 1, b: 2 }.extract!(:a, :x) # => {:a=>1}
37 38 39 |
# File 'motion/core_ext/hash/slice.rb', line 37 def extract!(*keys) keys.each_with_object(self.class.new) { |key, result| result[key] = delete(key) if has_key?(key) } end |
#reverse_merge(other_hash) ⇒ Object
Merges the caller into other_hash
. For example,
= .reverse_merge(size: 25, velocity: 10)
is equivalent to
= { size: 25, velocity: 10 }.merge()
This is particularly useful for initializing an options hash with default values.
12 13 14 |
# File 'motion/core_ext/hash/reverse_merge.rb', line 12 def reverse_merge(other_hash) other_hash.merge(self) end |
#reverse_merge!(other_hash) ⇒ Object Also known as: reverse_update
Destructive reverse_merge
.
17 18 19 20 |
# File 'motion/core_ext/hash/reverse_merge.rb', line 17 def reverse_merge!(other_hash) # right wins if there is no left merge!( other_hash ){|key,left,right| left } end |
#slice(*keys) ⇒ Object
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 = {})
criteria.assert_valid_keys(:mass, :velocity, :time)
end
search(.slice(:mass, :velocity, :time))
If you have an array of keys you want to limit to, you should splat them:
valid_keys = [:mass, :velocity, :time]
search(.slice(*valid_keys))
15 16 17 18 |
# File 'motion/core_ext/hash/slice.rb', line 15 def slice(*keys) keys.map! { |key| convert_key(key) } if respond_to?(:convert_key, true) keys.each_with_object(self.class.new) { |k, hash| hash[k] = self[k] if has_key?(k) } end |
#slice!(*keys) ⇒ Object
Replaces the hash with only the given keys. Returns a hash containing the removed key/value pairs.
{ a: 1, b: 2, c: 3, d: 4 }.slice!(:a, :b)
# => {:c=>3, :d=>4}
25 26 27 28 29 30 31 |
# File 'motion/core_ext/hash/slice.rb', line 25 def slice!(*keys) keys.map! { |key| convert_key(key) } if respond_to?(:convert_key, true) omit = slice(*self.keys - keys) hash = slice(*keys) replace(hash) omit end |
#stringify_keys ⇒ Object
Return a new hash with all keys converted to strings.
hash = { name: 'Rob', age: '28' }
hash.stringify_keys
#=> { "name" => "Rob", "age" => "28" }
31 32 33 |
# File 'motion/core_ext/hash/keys.rb', line 31 def stringify_keys transform_keys{ |key| key.to_s } end |
#stringify_keys! ⇒ Object
Destructively convert all keys to strings. Same as stringify_keys
, but modifies self
.
37 38 39 |
# File 'motion/core_ext/hash/keys.rb', line 37 def stringify_keys! transform_keys!{ |key| key.to_s } end |
#symbolize_keys ⇒ Object Also known as: to_options
Return a new hash with all keys converted to symbols, as long as they respond to to_sym
.
hash = { 'name' => 'Rob', 'age' => '28' }
hash.symbolize_keys
#=> { name: "Rob", age: "28" }
48 49 50 |
# File 'motion/core_ext/hash/keys.rb', line 48 def symbolize_keys transform_keys{ |key| key.to_sym rescue key } end |
#symbolize_keys! ⇒ Object Also known as: to_options!
Destructively convert all keys to symbols, as long as they respond to to_sym
. Same as symbolize_keys
, but modifies self
.
55 56 57 |
# File 'motion/core_ext/hash/keys.rb', line 55 def symbolize_keys! transform_keys!{ |key| key.to_sym rescue key } end |
#to_json ⇒ Object
Serializes the hash object using Cocoa’s NSJSONSerialization
142 143 144 145 |
# File 'motion/core_ext/object/to_json.rb', line 142 def to_json # JSON keys must be strings, and any sub-objects also serialized NSJSONSerialization.dataWithJSONObject(as_json, options: 0, error: nil).to_s end |
#to_param(namespace = nil) ⇒ Object Also known as: to_query
Returns a string representation of the receiver suitable for use as a URL query string:
{name: 'David', nationality: 'Danish'}.to_param
# => "name=David&nationality=Danish"
An optional namespace can be passed to enclose the param names:
{name: 'David', nationality: 'Danish'}.to_param('user')
# => "user[name]=David&user[nationality]=Danish"
The string pairs “key=value” that conform the query string are sorted lexicographically in ascending order.
This method is also aliased as to_query
.
166 167 168 169 170 |
# File 'motion/core_ext/hash/keys.rb', line 166 def to_param(namespace = nil) collect do |key, value| value.to_query(namespace ? "#{namespace}[#{key}]" : key) end.sort * '&' end |
#transform_keys ⇒ Object
Return a new hash with all keys converted using the block operation.
hash = { name: 'Rob', age: '28' }
hash.transform_keys{ |key| key.to_s.upcase }
# => { "NAME" => "Rob", "AGE" => "28" }
8 9 10 11 12 13 14 |
# File 'motion/core_ext/hash/keys.rb', line 8 def transform_keys result = {} each_key do |key| result[yield(key)] = self[key] end result end |
#transform_keys! ⇒ Object
Destructively convert all keys using the block operations. Same as transform_keys but modifies self
.
18 19 20 21 22 23 |
# File 'motion/core_ext/hash/keys.rb', line 18 def transform_keys! keys.each do |key| self[yield(key)] = delete(key) end self end |
#with_indifferent_access ⇒ Object Also known as: nested_under_indifferent_access
Returns an MotionSupport::HashWithIndifferentAccess
out of its receiver:
{ a: 1 }.with_indifferent_access['a'] # => 1
5 6 7 |
# File 'motion/core_ext/hash/indifferent_access.rb', line 5 def with_indifferent_access MotionSupport::HashWithIndifferentAccess.(self) end |