Module: Jinx::Hasher

Includes:
Enumerable, Collection
Included in:
Hash, Filter, KeyFilter, MultiHash, SortedHash, Hashinator, KeyTransformerHash, ValueTransformerHash
Defined in:
lib/jinx/helpers/hasher.rb,
lib/jinx/helpers/pretty_print.rb

Overview

Hasher is a mix-in that adds utility methods to a Hash. This Hasher module can be included by any class or module which implements an each method with arguments key and value.

Defined Under Namespace

Classes: Filter, KeyFilter, MultiHash, SortedHash

Instance Method Summary collapse

Methods included from Enumerable

#enumerate, #pp_s, #to_enum, #transitive_closure

Methods included from Collection

#compact_map, #detect_with_value, #empty?, #first, #hashify, #intersect, #last, #partial_sort, #partial_sort!, #partial_sort_by, #size, #to_compact_hash, #to_compact_hash_with_index, #to_series, #transform

Instance Method Details

#==(other) ⇒ Object



383
384
385
# File 'lib/jinx/helpers/hasher.rb', line 383

def ==(other)
  to_hash == other.to_hash rescue super
end

#[](key) ⇒ Object

See Also:

  • Hash#[]


83
84
85
# File 'lib/jinx/helpers/hasher.rb', line 83

def [](key)
  detect_value { |k, v| v if k.eql?(key) }
end

#assoc_values(*others) ⇒ Hash

Returns a hash which associates each key in this hash with the value mapped by the others.

Examples:

{:a => 1, :b => 2}.assoc_values({:a => 3, :c => 4}) #=> {:a => [1, 3], :b => [2, nil], :c => [nil, 4]}
{:a => 1, :b => 2}.assoc_values({:a => 3}, {:a => 4, :b => 5}) #=> {:a => [1, 3, 4], :b => [2, nil, 5]}

Parameters:

  • others (<Hasher>)

    the other Hashers to associate with this Hasher

Returns:

  • (Hash)

    the association hash



225
226
227
228
229
230
231
# File 'lib/jinx/helpers/hasher.rb', line 225

def assoc_values(*others)
  all_keys = keys
  others.each { |hash| all_keys.concat(hash.keys) }
  all_keys.to_compact_hash do |k|
    others.map { |other| other[k] }.unshift(self[k])
  end
end

#compactHash

Returns a #filter of this Hasher which excludes the entries with a null value.

Returns:

  • (Hash)

    a #filter of this Hasher which excludes the entries with a null value



182
183
184
# File 'lib/jinx/helpers/hasher.rb', line 182

def compact
  filter_on_value { |v| not v.nil? }
end

#compose(other) ⇒ Hasher

Returns a Hasher which composes each value in this Hasher with the key of the other Hasher, e.g.:

x = {:a => :c, :b => :d}
y = {:c => 1}
z = x.compose(y)
z[:a] #=> {:c => 1}
z[:b] #=> nil

The accessor reflects changes to the underlying hashes, e.g. given the above example:

x[:b] = 2
z[:b] #=> {:c => 1}

Update operations on the result are not supported.

Parameters:

  • other (Hasher)

    the Hasher to compose with this Hasher

Returns:

  • (Hasher)

    the composed result



103
104
105
# File 'lib/jinx/helpers/hasher.rb', line 103

def compose(other)
  transform_value { |v| {v => other[v]} if other.has_key?(v) }
end

#copy_recursiveHash

Returns a new Hash that recursively copies this hash’s values. Values of type hash are copied using copy_recursive. Other values are unchanged.

This method is useful for preserving and restoring hash associations.

Returns:

  • (Hash)

    a deep copy of this Hasher



316
317
318
319
320
321
322
323
# File 'lib/jinx/helpers/hasher.rb', line 316

def copy_recursive
  copy = Hash.new
  keys.each do |k|
    value = self[k]
    copy[k] = Hash === value ? value.copy_recursive : value
  end
  copy
end

#detect_hash_value {|value| ... } ⇒ Object

Returns a hash value for which the detector block returns a non-nil, non-false result, or nil if none.

Examples:

{:a => 1, :b => 2}.detect_hash_value { |v| v > 1 } #=> 2

Yields:

  • (value)

    the detector block

Yield Parameters:

  • value

    the hash value

Returns:

  • a hash value for which the detector block returns a non-nil, non-false result, or nil if none



77
78
79
80
# File 'lib/jinx/helpers/hasher.rb', line 77

def detect_hash_value
  each_value { |v| return v if yield v }
  nil
end

#detect_key {|key| ... } ⇒ Object

Returns the hash key for which the detector block returns a non-nil, non-false result, or nil if none.

Examples:

{1 => :a, 2 => :b, 3 => :c}.detect_key { |k| k > 1 } #=> 2

Yields:

  • (key)

    the detector block

Yield Parameters:

  • key

    the hash key

Returns:

  • the hash key for which the detector block returns a non-nil, non-false result, or nil if none



27
28
29
30
# File 'lib/jinx/helpers/hasher.rb', line 27

def detect_key
  each_key { |k| return k if yield k }
  nil
end

#detect_key_with_value {|value| ... } ⇒ Object

Returns the key for which the detector block returns a non-nil, non-false value, or nil if none.

Examples:

{:a => 1, :b => 2, :c => 3}.detect_key_with_value { |v| v > 1 } #=> :b

Yields:

  • (value)

    the detector block

Yield Parameters:

  • value

    the hash value

Returns:

  • the key for which the detector block returns a non-nil, non-false value, or nil if none



60
61
62
63
# File 'lib/jinx/helpers/hasher.rb', line 60

def detect_key_with_value
  each { |k, v| return k if yield v }
  nil
end

#detect_valueObject

Examples:

{1 => 2, 3 => 4}.detect_value { |k, v| v if k > 1 } #=> 4

See Also:

  • Jinx::Hasher.{Enumerable{Enumerable#hash_value}


45
46
47
48
49
50
51
# File 'lib/jinx/helpers/hasher.rb', line 45

def detect_value
  each do |k, v|
    value = yield(k, v)
    return value if value
  end
  nil
end

#difference(other) {|key, v1, v2| ... } ⇒ {Object => (Object,Object)} Also known as: diff

Returns the difference between this Hasher and the other Hasher in a Hash of the form:

key => [mine, theirs]

where:

  • key is the key of association which differs

  • mine is the value for key in this hash

  • theirs is the value for key in the other hash

Parameters:

  • other (Hasher)

    the Hasher to subtract

Yields:

  • (key, v1, v2)

    the optional block which determines whether values differ (default is equality)

Yield Parameters:

  • key

    the key for which values are compared

  • v1

    the value for key from this Hasher

  • v2

    the value for key from the other Hasher

Returns:



201
202
203
204
205
206
207
# File 'lib/jinx/helpers/hasher.rb', line 201

def difference(other)
  (keys.to_set + other.keys).to_compact_hash do |k|
     mine = self[k]
     yours = other[k]
     [mine, yours] unless block_given? ? yield(k, mine, yours) : mine == yours
  end
end

#each_keyObject

See Also:

  • Hash#each_key


16
17
18
# File 'lib/jinx/helpers/hasher.rb', line 16

def each_key
  each { |k, v| yield k }
end

#each_pair(&block) ⇒ Object

See Also:

  • Hash#each_pair


11
12
13
# File 'lib/jinx/helpers/hasher.rb', line 11

def each_pair(&block)
  each(&block)
end

#each_valueObject

See Also:

  • Hash#each_value


66
67
68
# File 'lib/jinx/helpers/hasher.rb', line 66

def each_value
  each { |k, v| yield v }
end

#enum_keysEnumerable

Returns Enumerable over this Hasher’s keys.

Returns:

  • (Enumerable)

    Enumerable over this Hasher’s keys



245
246
247
# File 'lib/jinx/helpers/hasher.rb', line 245

def enum_keys
  Enumerable::Enumerator.new(self, :each_key)
end

#enum_keys_with_value(target_value = nil) {|value| ... } ⇒ Enumerable

Returns an Enumerable whose each block is called on each key which maps to a value which either equals the given target_value or satisfies the filter block.

Parameters:

  • target_value (defaults to: nil)

    the filter value

Yields:

  • (value)

    the filter block

Returns:



239
240
241
242
# File 'lib/jinx/helpers/hasher.rb', line 239

def enum_keys_with_value(target_value=nil, &filter) # :yields: value
  return enum_keys_with_value { |v| v == target_value } if target_value
  filter_on_value(&filter).keys
end

#enum_valuesEnumerable

Returns an Enumerable over this Hasher’s values.

Returns:

  • (Enumerable)

    an Enumerable over this Hasher’s values



255
256
257
# File 'lib/jinx/helpers/hasher.rb', line 255

def enum_values
  Enumerable::Enumerator.new(self, :each_value)
end

#filter {|key, value| ... } ⇒ Hasher

Returns a new Hasher that iterates over the base Hasher <key, value> pairs for which the block given to this method evaluates to a non-nil, non-false value, e.g.:

{:a => 1, :b => 2, :c => 3}.filter { |k, v| k != :b }.to_hash #=> {:a => 1, :c => 3}

The default filter block tests the value, e.g.:

{:a => 1, :b => nil}.filter.to_hash #=> {:a => 1}

Yields:

  • (key, value)

    the filter block

Returns:

  • (Hasher)

    the filtered result



157
158
159
# File 'lib/jinx/helpers/hasher.rb', line 157

def filter(&block)
  Filter.new(self, &block)
end

#filter_on_key {|key| ... } ⇒ Hasher

Optimization of #filter for a block that only uses the key.

Examples:

{:a => 1, :b => 2, :c => 3}.filter_on_key { |k| k != :b }.to_hash #=> {:a => 1, :c => 3}

Yields:

  • (key)

    the filter block

Yield Parameters:

  • key

    the hash key to filter

Returns:

  • (Hasher)

    the filtered result



169
170
171
# File 'lib/jinx/helpers/hasher.rb', line 169

def filter_on_key(&block)
  KeyFilter.new(self, &block)
end

#filter_on_value {|value| ... } ⇒ Hasher

Yields:

  • (value)

    the filter block

Yield Parameters:

  • value

    the hash value to filter

Returns:



177
178
179
# File 'lib/jinx/helpers/hasher.rb', line 177

def filter_on_value
  filter { |k, v| yield v }
end

#flattenArray

Returns a flattened Array of this Hash.

Examples:

{:a => {:b => :c}, :d => :e, :f => [:g]} #=> [:a, :b, :c, :d, :e, :f, :g]

Returns:

  • (Array)

    a flattened Array of this Hash



297
298
299
# File 'lib/jinx/helpers/hasher.rb', line 297

def flatten
  Flattener.new(self).to_a
end

#has_key?(key) ⇒ Boolean Also known as: include?

Returns whether this Hasher has the given key.

Parameters:

  • key

    the search target

Returns:

  • (Boolean)

    whether this Hasher has the given key



34
35
36
37
# File 'lib/jinx/helpers/hasher.rb', line 34

def has_key?(key)
  each_key { |k| return true if k.eql?(key) }
  false
end

#has_value?(value) ⇒ Boolean

Returns whether this Hasher has the given value.

Parameters:

  • value

    search target

Returns:

  • (Boolean)

    whether this Hasher has the given value



290
291
292
# File 'lib/jinx/helpers/hasher.rb', line 290

def has_value?(value)
  enum_values.include?(value)
end

#inspectObject



379
380
381
# File 'lib/jinx/helpers/hasher.rb', line 379

def inspect
  to_hash.inspect
end

#join(other) ⇒ Hasher

Returns a Hasher which joins each value in this Hasher with the key of the other Hasher, e.g.:

x = {:a => :c, :b => :d}
y = {:c => 1}
z = x.join(y)
z[:a] #=> 1
z[:b] #=> nil

The accessor reflects changes to the underlying hashes, e.g. given the above example:

x[:b] = 2
z[:b] #=> 2

Update operations on the result are not supported.

Parameters:

  • other (Hasher)

    the Hasher to join with this Hasher

Returns:

  • (Hasher)

    the joined result



123
124
125
# File 'lib/jinx/helpers/hasher.rb', line 123

def join(other)
  transform_value { |v| other[v] }
end

#keysArray

Returns this Hasher’s keys.

Returns:

  • (Array)

    this Hasher’s keys



250
251
252
# File 'lib/jinx/helpers/hasher.rb', line 250

def keys
  enum_keys.to_a
end

#pretty_print(q) ⇒ Object



167
168
169
# File 'lib/jinx/helpers/pretty_print.rb', line 167

def pretty_print(q)
  Hash === self ? q.pp_hash(self) : q.pp_hash(to_hash)
end

#pretty_print_cycle(q) ⇒ Object



171
172
173
# File 'lib/jinx/helpers/pretty_print.rb', line 171

def pretty_print_cycle(q)
  q.text(empty? ? '{}' : '{...}')
end

#qpString

qp, short for quick-print, prints this Hasher with a filter that calls qp on each key and value.

Returns:

  • (String)

    the quick-print result



161
162
163
164
165
# File 'lib/jinx/helpers/pretty_print.rb', line 161

def qp
  qph = {}
  each { |k, v| qph[k.qp] = v.qp }
  qph.pp_s
end

#reject_keys {|key| ... } ⇒ Enumerable

Returns the keys which do not satisfy the block given to this method.

Yields:

  • (key)

    the key rejector

Returns:

  • (Enumerable)

    the keys which do not satisfy the block given to this method



267
268
269
# File 'lib/jinx/helpers/hasher.rb', line 267

def reject_keys(&block)
  enum_keys.reject(&block)
end

#reject_values {|value| ... } ⇒ Enumerable

Returns the values which do not satisfy the block given to this method.

Yields:

  • (value)

    the value rejector

Returns:

  • (Enumerable)

    the values which do not satisfy the block given to this method



279
280
281
# File 'lib/jinx/helpers/hasher.rb', line 279

def reject_values(&block)
  enum_values.reject(&block)
end

#select_keys {|key| ... } ⇒ Enumerable

Returns the keys which satisfy the block given to this method.

Yields:

  • (key)

    the key selector

Returns:

  • (Enumerable)

    the keys which satisfy the block given to this method



261
262
263
# File 'lib/jinx/helpers/hasher.rb', line 261

def select_keys(&block)
  enum_keys.select(&block)
end

#select_values {|value| ... } ⇒ Enumerable

Returns the values which satisfy the block given to this method.

Yields:

  • (value)

    the value selector

Returns:

  • (Enumerable)

    the values which satisfy the block given to this method



273
274
275
# File 'lib/jinx/helpers/hasher.rb', line 273

def select_values(&block)
  enum_values.select(&block)
end

#sort {|key1, key2| ... } ⇒ Hasher

Returns a hash whose #each and #each_pair enumerations are sorted by key.

Yields:

  • (key1, key2)

    the key sort block

Returns:



213
214
215
# File 'lib/jinx/helpers/hasher.rb', line 213

def sort(&sorter)
  SortedHash.new(self, &sorter)
end

#split {|key, value| ... } ⇒ (Hash, Hash)

Returns two hashes split by whether calling the block on the entry returns a non-nil, non-false value.

Examples:

{:a => 1, :b => 2}.split { |k, v| v < 2 } #=> [{:a => 1}, {:b => 2}]

Yields:

  • (key, value)

    hash splitter

Returns:

  • ((Hash, Hash))

    two hashes split by whether calling the block on the entry returns a non-nil, non-false value



306
307
308
# File 'lib/jinx/helpers/hasher.rb', line 306

def split(&block)
  partition(&block).map { |pairs| pairs.to_assoc_hash }
end

#to_hashHash

Returns a new Hash created from this Hasher’s content.

Returns:

  • (Hash)

    a new Hash created from this Hasher’s content



365
366
367
368
369
# File 'lib/jinx/helpers/hasher.rb', line 365

def to_hash
  hash = {}
  each { |k, v| hash[k] = v }
  hash
end

#to_sObject



375
376
377
# File 'lib/jinx/helpers/hasher.rb', line 375

def to_s
  to_hash.to_s
end

#to_setObject



371
372
373
# File 'lib/jinx/helpers/hasher.rb', line 371

def to_set
  to_a.to_set
end

#transform_key {|key| ... } ⇒ Hasher

Returns a new Hasher which applies a transformer block to each key in this base Hasher. The result reflects changes to this underlying base Hasher.

Examples:

h = {1 => :a, 2 => :b}
xfm = h.transform_key { |n| n * 2 }
xfm.keys #=> [2, 4]
xfm[2] #=> :a
xfm[3] #=> nil
xfm[4] #=> :b
h[3] = :c
xfm[6] #=> :c

Yields:

  • (key)

    transforms the given key

Yield Parameters:

  • key

    the key to transform

Returns:

  • (Hasher)

    a new Hasher that transforms each key



360
361
362
# File 'lib/jinx/helpers/hasher.rb', line 360

def transform_key(&transformer)
  KeyTransformerHash.new(self, &transformer)
end

#transform_value {|value| ... } ⇒ Hasher

Returns a new Hasher which applies a transformer block to each value in this base Hasher. The result reflects changes to this underlying base Hasher.

Examples:

h = {:a => 1, :b => 2}
xfm = h.transform_value { |n| n * 2 }
xfm.values #=> [2, 4]
xfm[:a] #=> 2
xfm[:b] #=> 4
h[:c] = 3
xfm[:c] #=> 6

Yields:

  • (value)

    transforms the given value

Yield Parameters:

  • value

    the value to transform

Returns:

  • (Hasher)

    a new Hasher that transforms each value



340
341
342
# File 'lib/jinx/helpers/hasher.rb', line 340

def transform_value(&transformer)
  ValueTransformerHash.new(self, &transformer)
end

#union(other) ⇒ Hasher Also known as: +

Returns a Hasher which associates each key of both this Hasher and the other Hasher with the corresponding value in the first Hasher which has that key, e.g.:

x = {:a => 1, :b => 2}
y = {:b => 3, :c => 4}
z = x + y
z[:b] #=> 2

The accessor reflects changes to the underlying hashes, e.g. given the above example:

x.delete(:b)
z[:b] #=> 3

Update operations on the result are not supported.

Parameters:

  • other (Hasher)

    the Hasher to form a union with this Hasher

Returns:

  • (Hasher)

    the union result



142
143
144
# File 'lib/jinx/helpers/hasher.rb', line 142

def union(other)
  MultiHash.new(self, other)
end

#valuesArray

Returns this Enumerable’s values.

Returns:

  • (Array)

    this Enumerable’s values



284
285
286
# File 'lib/jinx/helpers/hasher.rb', line 284

def values
  enum_values.to_a
end