Module: Gorillib::Hashlike
- Includes:
- Serialization
- Defined in:
- lib/gorillib/hashlike.rb,
lib/gorillib/hashlike/keys.rb,
lib/gorillib/hashlike/slice.rb,
lib/gorillib/hashlike/compact.rb,
lib/gorillib/hashlike/deep_dup.rb,
lib/gorillib/hashlike/deep_hash.rb,
lib/gorillib/hashlike/deep_merge.rb,
lib/gorillib/hashlike/deep_compact.rb,
lib/gorillib/serialization/to_wire.rb,
lib/gorillib/serialization/to_wire.rb,
lib/gorillib/hashlike/reverse_merge.rb,
lib/gorillib/hashlike/hashlike_via_accessors.rb
Overview
Your class must provide #[], #[]=, #delete, and #keys --
- hsh[key] Element Reference -- Retrieves the value stored for +key+.
- hsh[key] = val Element Assignment -- Associates +val+ with +key+.
- hsh.delete(key) Deletes & returns the value whose key is equal to +key+.
- hsh.keys Returns a new array populated with the keys.
(see Hashlike::HashlikeViaAccessors for example)
Given the above, hashlike will provide the rest, defining the methods
:each_pair, :each, :each_key, :each_value, :values_at, :values_of, :values,
:size, :length, :has_key?, :include?, :key?, :member?, :has_value?, :value?,
:fetch, :key, :assoc, :rassoc, :empty?, :merge, :update, :merge!, :reject!,
:select!, :delete_if, :keep_if, :reject, :clear, :store, :to_hash, :invert,
:flatten
and these methods added by Enumerable:
:each_cons, :each_entry, :each_slice, :each_with_index, :each_with_object,
:entries, :to_a, :map, :collect, :collect_concat, :group_by, :flat_map,
:inject, :reduce, :chunk, :reverse_each, :slice_before, :drop, :drop_while,
:take, :take_while, :detect, :find, :find_all, :select, :find_index, :grep,
:all?, :any?, :none?, :one?, :first, :count, :zip, :max, :max_by, :min,
:min_by, :minmax, :minmax_by, :sort, :sort_by, :cycle, :partition,
It does not define these methods that do exist on hash:
:default, :default=, :default_proc, :default_proc=,
:compare_by_identity, :compare_by_identity?,
:replace, :rehash, :shift
=== Chinese wall
With a few exceptions, all methods are defined only in terms of
#[], #[]=, #delete, #keys, #each_pair and #has_key?
(exceptions: merge family depend on #update; the reject/select/xx_if family depend on each other; #invert & #flatten call #to_hash; #rassoc calls #key)
=== custom iterators
Hashlike typically defines the following fundamental iterators by including Gorillib::Hashlike::EnumerateFromKeys:
:each_pair, :each, :values, :values_at, :length
However, if the #each_pair method already exists on the class (as it does for Struct), those methods will not be defined. The class is held responsible for the implementation of all five. (Of these, #each_pair is the only method called from elsewhere in Hashlike, while #each is the only method called from Enumerable).
=== #convert_key (Indifferent Access)
If you define #convert_key the #values_at, #has_key?, #fetch, and #assoc methods will use it to sanitize keys coming in from the outside. It's assumed that you will do the same with #[], #[]= and #delete. (see Gorillib::HashWithIndifferentAccess for an example).
Defined Under Namespace
Modules: Compact, DeepCompact, DeepDup, DeepHash, DeepMerge, EnumerateFromKeys, HashlikeViaAccessors, Keys, OverrideEnumerable, ReverseMerge, Serialization, Slice
Class Method Summary collapse
Instance Method Summary collapse
-
#assoc(key) ⇒ Array?
Searches through the hashlike comparing obj with the key using ==.
-
#clear ⇒ Hashlike
Removes all key-value pairs from +hsh+.
-
#delete_if(&block) ⇒ Object
Deletes every key-value pair from +hsh+ for which +block+ evaluates truthy.
-
#each_key ⇒ Object
Hashlike#each_key.
-
#each_value ⇒ Object
Calls +block+ once for each key in +hsh+, passing the value as a parameter.
-
#empty? ⇒ true, false
Returns true if the hashlike contains no key-value pairs, false otherwise.
-
#fetch(key, default = nil) {|key| ... } ⇒ Object
Returns a value from the hashlike for the given key.
-
#flatten(*args) ⇒ Array
Returns a new array that is a one-dimensional flattening of this hashlike.
-
#has_key?(key) ⇒ true, false
Returns true if the given key is present in +hsh+.
-
#has_value?(target) ⇒ true, false
Returns true if the given value is present for some key in +hsh+.
-
#invert ⇒ Hash
Returns a new hash created by using +hsh+'s values as keys, and the keys as values.
-
#keep_if(&block) ⇒ Object
Deletes every key-value pair from +hsh+ for which +block+ evaluates falsy.
-
#key(val) ⇒ Object?
Searches the hash for an entry whose value == +val+, returning the corresponding key.
-
#merge(*args, &block) ⇒ Object
Returns a new hashlike containing the contents of +other_hash+ and the contents of +hsh+.
-
#rassoc(val) ⇒ Array?
Searches through the hashlike comparing obj with the value using ==.
-
#reject!(&block) ⇒ Object
Deletes every key-value pair from +hsh+ for which +block+ evaluates truthy (equivalent to Hashlike#delete_if), but returns nil if no changes were made.
-
#select!(&block) ⇒ Object
Deletes every key-value pair from +hsh+ for which +block+ evaluates falsy (equivalent to Hashlike#keep_if), but returns nil if no changes were made.
-
#store(key, val) ⇒ Object
alias for #[]=.
-
#to_hash ⇒ Hash
Returns a hash with each key set to its associated value.
-
#update(other_hash) ⇒ Object
Adds the contents of +other_hash+ to +hsh+.
-
#values_of(*allowed_keys) ⇒ Array
Array containing the values associated with the given keys.
Methods included from Serialization
Class Method Details
.included(base) ⇒ Object
806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 |
# File 'lib/gorillib/hashlike.rb', line 806 def self.included(base) base.class_eval do include EnumerateFromKeys unless method_defined?(:each_pair) unless include?(Enumerable) include Enumerable include OverrideEnumerable end # included here so they win out over Enumerable alias_method :include?, :has_key? alias_method :key?, :has_key? alias_method :member?, :has_key? alias_method :value?, :has_value? alias_method :merge!, :update alias_method :size, :length end end |
Instance Method Details
#assoc(key) ⇒ Array?
Searches through the hashlike comparing obj with the key using ==. Returns the key-value pair (two elements array) or nil if no match is found.
427 428 429 430 431 |
# File 'lib/gorillib/hashlike.rb', line 427 def assoc(key) key = convert_key(key) if respond_to?(:convert_key) return unless has_key?(key) [key, self[key]] end |
#clear ⇒ Hashlike
Removes all key-value pairs from +hsh+.
730 731 732 |
# File 'lib/gorillib/hashlike.rb', line 730 def clear each_pair{|k,v| delete(k) } end |
#hsh.delete_if ⇒ Hashlike #hsh.delete_if(->an_enumerator) ⇒ Enumerator
Deletes every key-value pair from +hsh+ for which +block+ evaluates truthy.
If no block is given, an enumerator is returned instead.
625 626 627 628 629 |
# File 'lib/gorillib/hashlike.rb', line 625 def delete_if(&block) return enum_for(:delete_if) unless block_given? reject!(&block) self end |
#hsh.each_key {|key| ... } ⇒ Hashlike #hsh.each_key(->an_enumerator) ⇒ Enumerator
Hashlike#each_key
Calls +block+ once for each key in +hsh+, passing the key as a parameter.
If no block is given, an enumerator is returned instead.
250 251 252 253 254 |
# File 'lib/gorillib/hashlike.rb', line 250 def each_key return enum_for(:each_key) unless block_given? each_pair{|k,v| yield k } self end |
#hsh.each_value {|val| ... } ⇒ Hashlike #hsh.each_value(->an_enumerator) ⇒ Enumerator
Calls +block+ once for each key in +hsh+, passing the value as a parameter.
If no block is given, an enumerator is returned instead.
287 288 289 290 291 |
# File 'lib/gorillib/hashlike.rb', line 287 def each_value return enum_for(:each_value) unless block_given? each_pair{|k,v| yield v } self end |
#empty? ⇒ true, false
Returns true if the hashlike contains no key-value pairs, false otherwise.
461 462 463 |
# File 'lib/gorillib/hashlike.rb', line 461 def empty? keys.empty? end |
#fetch(key, default = nil) {|key| ... } ⇒ Object
Returns a value from the hashlike for the given key. If the key can't be found, there are several options:
- With no other arguments, it will raise a +KeyError+ exception;
- if default is given, then that will be returned;
- if the optional code block is specified, then that will be run and its result returned.
382 383 384 385 386 387 388 389 390 |
# File 'lib/gorillib/hashlike.rb', line 382 def fetch(key, default=nil, &block) key = convert_key(key) if respond_to?(:convert_key) warn "#{caller[0]}: warning: block supersedes default value argument" if default && block_given? if has_key?(key) then self[key] elsif block_given? then yield(key) elsif default then default else raise KeyError, "key not found: #{key.inspect}" end end |
#flatten ⇒ Array #flatten(level) ⇒ Array
Returns a new array that is a one-dimensional flattening of this hashlike. That is, for every key or value that is an array, extract its elements into the new array. Unlike Array#flatten, this method does not flatten recursively by default; pass +nil+ explicitly to flatten recursively. The optional level argument determines the level of recursion to flatten.
802 803 804 |
# File 'lib/gorillib/hashlike.rb', line 802 def flatten(*args) to_hash.flatten(*args) end |
#has_key?(key) ⇒ true, false
Returns true if the given key is present in +hsh+.
328 329 330 331 |
# File 'lib/gorillib/hashlike.rb', line 328 def has_key?(key) key = convert_key(key) if respond_to?(:convert_key) keys.include?(key) end |
#has_value?(target) ⇒ true, false
Returns true if the given value is present for some key in +hsh+.
344 345 346 347 348 |
# File 'lib/gorillib/hashlike.rb', line 344 def has_value?(target) # don't refactor this to any? -- Struct's #any is weird each_pair{|key, val| return true if (val == target) } false end |
#invert ⇒ Hash
Returns a new hash created by using +hsh+'s values as keys, and the keys as values. If +hsh+ has duplicate values, the result will contain only one of them as a key -- which one is not predictable.
759 760 761 |
# File 'lib/gorillib/hashlike.rb', line 759 def invert to_hash.invert end |
#hsh.keep_if ⇒ Hashlike #hsh.keep_if(->an_enumerator) ⇒ Enumerator
Deletes every key-value pair from +hsh+ for which +block+ evaluates falsy.
If no block is given, an enumerator is returned instead.
651 652 653 654 655 |
# File 'lib/gorillib/hashlike.rb', line 651 def keep_if(&block) return enum_for(:keep_if) unless block_given? select!(&block) self end |
#key(val) ⇒ Object?
Searches the hash for an entry whose value == +val+, returning the corresponding key. If not found, returns +nil+.
You are guaranteed that the first matching key in #keys will be the one returned.
407 408 409 |
# File 'lib/gorillib/hashlike.rb', line 407 def key(val) keys.find{|key| self[key] == val } end |
#hsh.merge(other_hash) ⇒ Hashlike #hsh.merge(other_hash) {|Object, Object, Object| ... } ⇒ Hashlike
Returns a new hashlike containing the contents of +other_hash+ and the contents of +hsh+. If no block is specified, the value for entries with duplicate keys will be that of +other_hash+. Otherwise the value for each duplicate key is determined by calling the block with the key, its value in +hsh+ and its value in +other_hash+.
539 540 541 |
# File 'lib/gorillib/hashlike.rb', line 539 def merge(*args, &block) self.dup.update(*args, &block) end |
#rassoc(val) ⇒ Array?
Searches through the hashlike comparing obj with the value using ==. Returns the first key-value pair (two-element array) that matches, or nil if no match is found.
448 449 450 451 |
# File 'lib/gorillib/hashlike.rb', line 448 def rassoc(val) key = key(val) or return [key, self[key]] end |
#hsh.reject! ⇒ Hashlike? #hsh.reject!(->an_enumerator) ⇒ Enumerator
Deletes every key-value pair from +hsh+ for which +block+ evaluates truthy (equivalent to Hashlike#delete_if), but returns nil if no changes were made.
562 563 564 565 566 567 568 569 570 571 572 |
# File 'lib/gorillib/hashlike.rb', line 562 def reject!(&block) return enum_for(:reject!) unless block_given? changed = false each_pair do |key, val| if yield(*[key, val].take(block.arity)) changed = true delete(key) end end changed ? self : nil end |
#hsh.select! ⇒ Hashlike #hsh.select!(->an_enumerator) ⇒ Enumerator
Deletes every key-value pair from +hsh+ for which +block+ evaluates falsy (equivalent to Hashlike#keep_if), but returns nil if no changes were made.
593 594 595 596 597 598 599 600 601 602 603 |
# File 'lib/gorillib/hashlike.rb', line 593 def select!(&block) return enum_for(:select!) unless block_given? changed = false each_pair do |key, val| if not yield(*[key, val].take(block.arity)) changed = true delete(key) end end changed ? self : nil end |
#store(key, val) ⇒ Object
alias for #[]=
214 215 216 |
# File 'lib/gorillib/hashlike.rb', line 214 def store(key, val) self[key] = val end |
#to_hash ⇒ Hash
Returns a hash with each key set to its associated value.
744 745 746 |
# File 'lib/gorillib/hashlike.rb', line 744 def to_hash {}.tap{|hsh| each_pair{|key, val| hsh[key] = val } } end |
#hsh.update(other_hash) ⇒ Hashlike #hsh.update(other_hash) {|Object, Object, Object| ... } ⇒ Hashlike
Adds the contents of +other_hash+ to +hsh+. If no block is specified, entries with duplicate keys are overwritten with the values from +other_hash+, otherwise the value of each duplicate key is determined by calling the block with the key, its value in +hsh+ and its value in +other_hash+.
497 498 499 500 501 502 503 504 505 506 |
# File 'lib/gorillib/hashlike.rb', line 497 def update(other_hash) raise TypeError, "can't convert #{other_hash.nil? ? 'nil' : other_hash.class} into Hash" unless other_hash.respond_to?(:each_pair) other_hash.each_pair do |key, val| if block_given? && has_key?(key) val = yield(key, val, self[key]) end self[key] = val end self end |
#values_of(*allowed_keys) ⇒ Array
Array containing the values associated with the given keys.
310 311 312 313 314 315 |
# File 'lib/gorillib/hashlike.rb', line 310 def values_of(*allowed_keys) allowed_keys.map do |key| key = convert_key(key) if respond_to?(:convert_key) self[key] if has_key?(key) end end |