Module: Jinx::Hashable

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

Overview

Hashable is a Hash mixin that adds utility methods to a Hash. Hashable 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

#collection?, #compact_map, #detect_value, #detect_with_value, #difference, #empty?, #enumerate, #first, #hashify, #intersect, #last, #partial_sort, #partial_sort_by, #pp_s, #size, #to_compact_hash, #to_compact_hash_with_index, #to_enum, #to_series, #transform, #transitive_closure

Instance Method Details

#==(other) ⇒ Object



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

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

#[](key) ⇒ Object

See Also:

  • Hash#[]


17
18
19
# File 'lib/jinx/helpers/hashable.rb', line 17

def [](key)
  detect_value { |k, v| v if k == 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]}


193
194
195
196
197
198
199
# File 'lib/jinx/helpers/hashable.rb', line 193

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



152
153
154
# File 'lib/jinx/helpers/hashable.rb', line 152

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

#compose(other) ⇒ Hashable

Returns a Hashable which composes each value in this Hashable with the key of the other Hashable, 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.



73
74
75
# File 'lib/jinx/helpers/hashable.rb', line 73

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.



292
293
294
295
296
297
298
299
# File 'lib/jinx/helpers/hashable.rb', line 292

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_key {|key| ... } ⇒ Object

Returns the key for which the detector block returns a non-nil, non-false value, 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



32
33
34
35
# File 'lib/jinx/helpers/hashable.rb', line 32

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



47
48
49
50
# File 'lib/jinx/helpers/hashable.rb', line 47

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

#diff(other) {|key, v1, v2| ... } ⇒ {Object => (Object,Object)}

Returns the difference between this Hashable and the other Hashable 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

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 Hashable

  • v2

    the value for key from the other Hashable



171
172
173
174
175
176
177
# File 'lib/jinx/helpers/hashable.rb', line 171

def diff(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


22
23
24
# File 'lib/jinx/helpers/hashable.rb', line 22

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

#each_pair(&block) ⇒ Object

See Also:

  • Hash#each_pair


12
13
14
# File 'lib/jinx/helpers/hashable.rb', line 12

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

#each_valueObject

See Also:

  • Hash#each_value


53
54
55
# File 'lib/jinx/helpers/hashable.rb', line 53

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

#enum_keysEnumerable



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

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.

Yields:

  • (value)

    the filter block



207
208
209
210
# File 'lib/jinx/helpers/hashable.rb', line 207

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



231
232
233
# File 'lib/jinx/helpers/hashable.rb', line 231

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

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

Returns a new Hashable that iterates over the base Hashable <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



127
128
129
# File 'lib/jinx/helpers/hashable.rb', line 127

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

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

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



139
140
141
# File 'lib/jinx/helpers/hashable.rb', line 139

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

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

Yields:

  • (value)

    the filter block

Yield Parameters:

  • value

    the hash value to filter



147
148
149
# File 'lib/jinx/helpers/hashable.rb', line 147

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]


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

def flatten
  Flattener.new(self).to_a
end

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



224
225
226
# File 'lib/jinx/helpers/hashable.rb', line 224

def has_key?(key)
  !!detect_key { |k| k == key }
end

#has_value?(value) ⇒ Boolean



266
267
268
# File 'lib/jinx/helpers/hashable.rb', line 266

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

#inspectObject



336
337
338
# File 'lib/jinx/helpers/hashable.rb', line 336

def inspect
  to_hash.inspect
end

#join(other) ⇒ Hashable

Returns a Hashable which joins each value in this Hashable with the key of the other Hashable, 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.



93
94
95
# File 'lib/jinx/helpers/hashable.rb', line 93

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

#keysArray



218
219
220
# File 'lib/jinx/helpers/hashable.rb', line 218

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 Hashable with a filter that calls qp on each key and value.



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



243
244
245
# File 'lib/jinx/helpers/hashable.rb', line 243

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



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

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



237
238
239
# File 'lib/jinx/helpers/hashable.rb', line 237

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



249
250
251
# File 'lib/jinx/helpers/hashable.rb', line 249

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

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

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

Yields:

  • (key1, key2)

    the key sort block



181
182
183
# File 'lib/jinx/helpers/hashable.rb', line 181

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



282
283
284
# File 'lib/jinx/helpers/hashable.rb', line 282

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

#to_hashHash



322
323
324
325
326
# File 'lib/jinx/helpers/hashable.rb', line 322

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

#to_sObject



332
333
334
# File 'lib/jinx/helpers/hashable.rb', line 332

def to_s
  to_hash.to_s
end

#to_setObject



328
329
330
# File 'lib/jinx/helpers/hashable.rb', line 328

def to_set
  to_a.to_set
end

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

Returns a new Hash that transforms each key.

Examples:

{1 => :a, 2 => :b}.transform_key { |n| n * 2 }.keys #=> [2, 4]

Yields:

  • (key)

    transforms the given key

Yield Parameters:

  • the (value)

    key to transform



317
318
319
# File 'lib/jinx/helpers/hashable.rb', line 317

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

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

Returns a new Hash that transforms each value.

Examples:

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

Yields:

  • (value)

    transforms the given value

Yield Parameters:

  • the (value)

    value to transform



307
308
309
# File 'lib/jinx/helpers/hashable.rb', line 307

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

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

Returns a Hashable which associates each key of both this Hashable and the other Hashable with the corresponding value in the first Hashable 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.



112
113
114
# File 'lib/jinx/helpers/hashable.rb', line 112

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

#valuesArray



260
261
262
# File 'lib/jinx/helpers/hashable.rb', line 260

def values
  enum_values.to_a
end