Class: Hash
- Defined in:
- lib/y_support/core_ext/hash/misc.rb,
lib/y_support/typing/hash/typing.rb
Class Method Summary collapse
-
.method_added(sym) ⇒ Object
This kludge method guards against overwriting of the #slice method by ActiveSupport.
Instance Method Summary collapse
-
#aA_empty(what_is_receiver = "hash") ⇒ Object
Fails with
ArgumentError
unless the receiver’s ‘#empty?` returns true. -
#aA_has(key, options = {}, &b) ⇒ Object
This method behaves exactly like
#aT_has
, but it raisesArgumentError
instead ofTypeError
. -
#aA_not_empty(what_is_receiver = "hash") ⇒ Object
Fails with
ArgumentError
unless the receiver’s ‘#empty?` returns false. -
#aT_empty(what_is_receiver = "hash") ⇒ Object
Fails with
TypeError
unless the receiver’s#empty?
returns true. -
#aT_has(key, options = {}, &b) ⇒ Object
(also: #must_have)
This runtime assertion raises
TypeError
when: 1. -
#aT_not_empty(what_is_receiver = "hash") ⇒ Object
Fails with
TypeError
unless the receiver’s ‘#empty?` returns false. -
#change_keys ⇒ Object
The difference from #with_keys is that modify_keys expects block that takes 2 arguments (key: value pair) and returns the new key.
-
#dot!(overwrite_methods: false) ⇒ Object
Makes hash keys accessible as methods.
-
#has?(key, options = {}) ⇒ Boolean
This method behaves like
#may_have
, but it returns true/false value instead of the value under the specified key. -
#may_have(key, options = {}) ⇒ Object
Calls
#merge_synonym_keys!
first, then returns the value under the specified key. -
#merge_synonym_keys!(key, *synonyms) ⇒ Object
Merges the synonymous hash keys into a single key - useful for argument validation.
-
#modify ⇒ Object
Like #map that returns a hash.
-
#modify_values ⇒ Object
The difference from #with_values is that modify_values expects block that takes 2 arguments [ key, value ] and returns the new value.
-
#modify_values! ⇒ Object
Like #modify_values, but modifies the receiver.
-
#pretty_print_numeric_values(gap: 0, precision: 2) ⇒ Object
Pretty-prints the hash consisting of names as keys, and numeric values.
-
#slice(matcher) ⇒ Object
A bit like Array#slice, but only takes 1 argument, which is either a Range, or an Array, and returns the selection of the hash for the keys that match the range or are present in the array.
-
#with_keys ⇒ Object
Applies a block as a mapping on all keys, returning a new hash.
-
#with_keys! ⇒ Object
Like #with_keys, but modifies the receiver.
-
#with_values ⇒ Object
Applies a block as a mapping on all values, returning a new hash.
-
#with_values! ⇒ Object
Like #do_with_values, but modifies the receiver.
Class Method Details
.method_added(sym) ⇒ Object
This kludge method guards against overwriting of the #slice method by ActiveSupport.
8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
# File 'lib/y_support/core_ext/hash/misc.rb', line 8 def method_added( sym ) if sym == :slice then # Unless it is our method, overwrite it. unless instance_method( sym ).source_location.include? 'y_support' # Let's now make a cache of this very method being called ma = singleton_class.instance_method :method_added # Let's remove the :method_added hook, or otherwise infinite recursion # would ensue. singleton_class.class_exec { remove_method :method_added } # And let's redefine the +:slice+ method now: warn "Warning: Attempt to redefine Hash##{sym} occured, reverting." if YSupport::DEBUG class_exec do # A bit like Array#slice, but only takes 1 argument, which is either # a Range, or an Array, and returns the selection of the hash for # the keys that match the range or are present in the array. # define_method sym do |matcher| self.class[ case matcher when Array then select { |k, _| matcher.include? k } else select { |k, _| matcher === k } end ] end end # Finally, let's bind the +:method_added+ method to self again. singleton_class.class_exec do define_method :method_added do |sym| ma.bind( self ).call( sym ) end end end end end |
Instance Method Details
#aA_empty(what_is_receiver = "hash") ⇒ Object
Fails with ArgumentError
unless the receiver’s ‘#empty?` returns true.
85 86 87 |
# File 'lib/y_support/typing/hash/typing.rb', line 85 def aA_empty what_is_receiver="hash" tap { empty? or fail ArgumentError, "%s not empty".X!( what_is_receiver ) } end |
#aA_has(key, options = {}, &b) ⇒ Object
This method behaves exactly like #aT_has
, but it raises ArgumentError
instead of TypeError
.
63 64 65 66 67 68 69 |
# File 'lib/y_support/typing/hash/typing.rb', line 63 def aA_has key, ={}, &b fail ArgumentError, "Key '#{key}' absent!" unless has? key, self[key].tap do |val| fail ArgumentError, "Value for #{key} of wrong type!" unless ( b.arity == 0 ? val.instance_exec( &b ) : b.( val ) ) if b end end |
#aA_not_empty(what_is_receiver = "hash") ⇒ Object
Fails with ArgumentError
unless the receiver’s ‘#empty?` returns false.
91 92 93 |
# File 'lib/y_support/typing/hash/typing.rb', line 91 def aA_not_empty what_is_receiver="hash" tap { empty? and fail ArgumentError, "%s empty".X!( what_is_receiver ) } end |
#aT_empty(what_is_receiver = "hash") ⇒ Object
Fails with TypeError
unless the receiver’s #empty?
returns true.
73 74 75 |
# File 'lib/y_support/typing/hash/typing.rb', line 73 def aT_empty what_is_receiver="hash" tap { empty? or fail TypeError, "%s not empty".X!( what_is_receiver ) } end |
#aT_has(key, options = {}, &b) ⇒ Object Also known as: must_have
This runtime assertion raises TypeError
when:
-
Neither the required key nor any of its synonyms are present.
-
The supplied criterion block, if any, returns false when applied
to the value of the key in question. If the block takes an argument (or more arguments), the value is passed in. If the block takes no arguments (arity 0), it is executed inside the singleton class of the receiver (using #instance_exec
method).
51 52 53 54 55 56 57 |
# File 'lib/y_support/typing/hash/typing.rb', line 51 def aT_has key, ={}, &b fail TypeError, "Key '#{key}' absent!" unless has? key, self[key].tap do |val| fail TypeError, "Value for #{key} of wrong type!" unless ( b.arity == 0 ? val.instance_exec( &b ) : b.( val ) ) if b end end |
#aT_not_empty(what_is_receiver = "hash") ⇒ Object
Fails with TypeError
unless the receiver’s ‘#empty?` returns false.
79 80 81 |
# File 'lib/y_support/typing/hash/typing.rb', line 79 def aT_not_empty what_is_receiver="hash" tap { empty? and fail TypeError, "%s empty".X!( what_is_receiver ) } end |
#change_keys ⇒ Object
The difference from #with_keys is that modify_keys expects block that takes 2 arguments (key: value pair) and returns the new key.
64 65 66 67 68 |
# File 'lib/y_support/core_ext/hash/misc.rb', line 64 def change_keys each_with_object self.class.new do |pair, hsh| hsh[ yield pair ] = self[ pair[0] ] end end |
#dot!(overwrite_methods: false) ⇒ Object
Makes hash keys accessible as methods. If the hash keys collide with its methods, ArgumentError is raised, unless :overwrite_methods option == true.
132 133 134 135 136 137 138 139 140 141 |
# File 'lib/y_support/core_ext/hash/misc.rb', line 132 def dot! overwrite_methods: false each_pair do |key, _| fail ArgumentError, "key #{key} of #dot!-ted hash is not convertible " + "to a symbol" unless key.respond_to? :to_sym fail ArgumentError, "#dot!-ted hash must not have keys colliding with " + "its methods" if methods.include? key.to_sym unless overwrite_methods define_singleton_method key.to_sym do self[key] end define_singleton_method "#{key}=".to_sym do |val| self[key] = val end end end |
#has?(key, options = {}) ⇒ Boolean
This method behaves like #may_have
, but it returns true/false value instead of the value under the specified key.
39 40 41 |
# File 'lib/y_support/typing/hash/typing.rb', line 39 def has? key, ={} ! merge_synonym_keys!( key, *[:syn!] ).nil? end |
#may_have(key, options = {}) ⇒ Object
Calls #merge_synonym_keys!
first, then returns the value under the specified key. The first argument is the main key, synonym keys may be supplied as a named argument :syn!
. (Bang indicates that the synonym keys will be merged with the main key, thus modifying the hash.)
31 32 33 34 |
# File 'lib/y_support/typing/hash/typing.rb', line 31 def may_have key, ={} merge_synonym_keys!( key, *[:syn!] ).nil? return self[key] end |
#merge_synonym_keys!(key, *synonyms) ⇒ Object
Merges the synonymous hash keys into a single key - useful for argument validation. Returns nil if neither main key, nor synonyms are found. Returns false (no merging) if the main key was found, but no synonym keys. Returns true (yes merging) if any of the synonym keys is found and renamed/merged to the main key. Value collisions in synonym keys (detected by #==) raise ArgumentError
.
9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
# File 'lib/y_support/typing/hash/typing.rb', line 9 def merge_synonym_keys!( key, *synonyms ) synonyms.reduce has_key?( key ) ? false : nil do |acc, syn| next acc unless has_key? syn if acc.nil? then self[key] = self[syn] delete syn next true end if self[key] == self[syn] then delete syn next true else raise TypeError, "Value collision between #{key} and its synonym #{syn}!" end end end |
#modify ⇒ Object
Like #map that returns a hash.
103 104 105 106 107 108 |
# File 'lib/y_support/core_ext/hash/misc.rb', line 103 def modify each_with_object self.class.new do |pair, hsh| key, val = yield pair hsh[key] = val end end |
#modify_values ⇒ Object
The difference from #with_values is that modify_values expects block that takes 2 arguments [ key, value ] and returns the new value.
87 88 89 90 91 |
# File 'lib/y_support/core_ext/hash/misc.rb', line 87 def modify_values each_with_object self.class.new do |pair, hsh| hsh[ pair[0] ] = yield pair end end |
#modify_values! ⇒ Object
Like #modify_values, but modifies the receiver.
95 96 97 98 99 |
# File 'lib/y_support/core_ext/hash/misc.rb', line 95 def modify_values! each_with_object self do |pair, hsh| hsh[ pair[0] ] = yield pair end end |
#pretty_print_numeric_values(gap: 0, precision: 2) ⇒ Object
Pretty-prints the hash consisting of names as keys, and numeric values. Takes 2 named arguments: :gap
and :precision
.
146 147 148 149 150 151 152 153 154 |
# File 'lib/y_support/core_ext/hash/misc.rb', line 146 def pretty_print_numeric_values gap: 0, precision: 2 lmax = keys.map( &:to_s ).map( &:size ).max value_strings = values.map { |n| "%.#{precision}f" % n rescue "%s" % n } rmax = value_strings.map( &:size ).max lgap = gap / 2 rgap = gap - lgap line = "%- #{lmax+lgap+1}s%#{rmax+rgap+1}.#{precision}f" puts keys.zip( values ).map &line.method( :% ) end |
#slice(matcher) ⇒ Object
A bit like Array#slice, but only takes 1 argument, which is either a Range, or an Array, and returns the selection of the hash for the keys that match the range or are present in the array.
122 123 124 125 126 |
# File 'lib/y_support/core_ext/hash/misc.rb', line 122 def slice matcher self.class[ case matcher when Array then select { |key, _| matcher.include? key } else select { |key, _| matcher === key } end ] end |
#with_keys ⇒ Object
Applies a block as a mapping on all keys, returning a new hash.
46 47 48 49 50 |
# File 'lib/y_support/core_ext/hash/misc.rb', line 46 def with_keys keys.each_with_object self.class.new do |key, hsh| hsh[ yield key ] = self[ key ] end end |
#with_keys! ⇒ Object
Like #with_keys, but modifies the receiver.
54 55 56 57 58 |
# File 'lib/y_support/core_ext/hash/misc.rb', line 54 def with_keys! keys.each_with_object self do |key, hsh| hsh[ yield key ] = delete key end end |
#with_values ⇒ Object
Applies a block as a mapping on all values, returning a new hash.
73 74 75 |
# File 'lib/y_support/core_ext/hash/misc.rb', line 73 def with_values each_with_object self.class.new do |(k, v), hsh| hsh[ k ] = yield v end end |
#with_values! ⇒ Object
Like #do_with_values, but modifies the receiver.
79 80 81 |
# File 'lib/y_support/core_ext/hash/misc.rb', line 79 def with_values! each_with_object self do |(k, v), hsh| hsh[ k ] = yield v end end |