Class: Weak::Map

Inherits:
Object
  • Object
show all
Includes:
Enumerable, [ Weak[ Weak::Map[ Weak::Map::WeakKeysWithDelete, Weak::Map::WeakKeys, Weak::Map::StrongKeys, Weak::Map::StrongSecondaryKeys ].find(&:usable?)
Defined in:
lib/weak/map.rb,
lib/weak/map/deletable.rb,
lib/weak/map/weak_keys.rb,
lib/weak/map/strong_keys.rb,
lib/weak/map/abstract_strong_keys.rb,
lib/weak/map/strong_secondary_keys.rb,
lib/weak/map/weak_keys_with_delete.rb
more...

Overview

Weak::Map behaves similar to a Hash or an ObjectSpace::WeakMap in Ruby (aka. MRI, aka. YARV). Both keys and values are weakly referenceed, allowing either of them to be independently garbage collected. If either the key or the value of a pair is garbage collected, the entire pair will be removed from the Weak::Map.

Map uses ObjectSpace::WeakMap as storage, so you must note the following points:

  • Equality of both keys and values is determined strictly by their object identity instead of Object#eql? or Object#hash as the Hash class does by default.
  • Keys and values can be freely changed without affecting the map.
  • Keys and values can be freely garbage collected by Ruby. A key-value pair will be removed from the map automatically if theoer the key or the value is garbage collected.
  • The order of key-value pairs in the map is non-deterministic. Insertion order is not preserved.

Note that Map is not inherently thread-safe. When accessing a Map from multiple threads or fibers, you MUST use a mutex or another locking mechanism.

Implementation Details

The various Ruby implementations and versions show quite diverse behavior in their respective ObjectSpace::WeakMap implementations. To provide a unified behavior on all implementations, we use different storage strategies:

  • Ruby (aka. MRI, aka. YARV) >= 3.3 has an ObjectSpace::WeakMap with weak keys and weak values and the ability to delete elements from it. This allows a straight-forward implementation in WeakKeysWithDelete.
  • Ruby (aka. MRI, aka. YARV) < 3.3 has an ObjectSpace::WeakMap with weak keys and weak values but does not allow to directly delete entries. We emulate this with special garbage-collectible values in WeakKeys.
  • JRuby >= 9.4.6.0 and TruffleRuby >= 22 have an ObjectSpace::WeakMap with strong keys and weak values. To allow both keys and values to be garbage collected, we can't use the actual object as a key in a single ObjectSpace::WeakMap. Instead, we use a sepate WeakMap for keys and values which in turn use the key's object_id as a key. As these ObjectSpace::WeakMap objects also do not allow to delete entries, we emulate deletion with special garbage-collectible values as above. This is implemented in StrongKeys.
  • JRuby < 9.4.6.0 has a similar ObjectSpace::WeakMap as newer JRuby versions with strong keys and weak values. However generally in JRuby, Integer values (including object_ids) can have multiple different object representations in memory and are not necessarily equal to each other when used as keys in an ObjectSpace::WeakMap. As a workaround we use an indirect implementation with a secondary lookup table for the map keys in for both stored keys and values StrongSecondaryKeys.

The required strategy is selected automatically based in the running Ruby. The external behavior is the same for all implementations.

Examples:

require "weak/map"

map = Weak::Map.new
map[:key] = "a value"
map[:key]
# => "a value"

Defined Under Namespace

Modules: AbstractStrongKeys, StrongKeys, StrongSecondaryKeys, WeakKeys, WeakKeysWithDelete

Constant Summary collapse

STRATEGY =

We try to find the best implementation strategy based on the current Ruby engine and version. The chosen STRATEGY is included into the Weak::Map class.

[
  Weak::Map::WeakKeysWithDelete,
  Weak::Map::WeakKeys,
  Weak::Map::StrongKeys,
  Weak::Map::StrongSecondaryKeys
].find(&:usable?)

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(default_value = UNDEFINED, &default_proc) ⇒ Map

Returns a new empty Weak::Map object.

The initial default value and initial default proc for the new hash depend on which form above was used.

If neither an default_value nor a block is given, initializes both the default value and the default proc to nil:

map = Weak::Map.new
map.default               # => nil
map.default_proc          # => nil

If a default_value is given but no block is given, initializes the default value to the given default_value and the default proc to nil:

map = Hash.new(false)
map.default               # => false
map.default_proc          # => nil

If a block is given but no default_value, stores the block as the default proc and sets the default value to nil:

map = Hash.new { |map, key| "Default value for #{key}" }
map.default              # => nil
map.default_proc.class   # => Proc
map[:nosuch]             # => "Default value for nosuch"

If both a block and a default_value are given, raises an ArgumentError

[View source] [View on GitHub]

315
316
317
318
319
320
321
322
323
324
325
326
327
# File 'lib/weak/map.rb', line 315

def initialize(default_value = UNDEFINED, &default_proc)
  clear

  if UNDEFINED.equal?(default_value)
    @default_value = nil
    @default_proc = default_proc
  elsif block_given?
    raise ArgumentError, "wrong number of arguments (given 1, expected 0)"
  else
    @default_value = default_value
    @default_proc = nil
  end
end

Class Method Details

.[](*maps) ⇒ Weak::Map

Returns a new Weak::Map object populated with the given objects, if any. With no argument, returns a new empty Weak::Map.

Examples:

hash = {foo: 0, bar: 1, baz: 2}
Weak::Map[hash]
# => #<Weak::Map {:foo=>0, :bar=>1, :baz=>2}>

Parameters:

  • maps (Array<#each_pair>)

    a list of maps which should be merged into the new Weak::Map

Returns:

[View source] [View on GitHub]

281
282
283
# File 'lib/weak/map.rb', line 281

def self.[](*maps)
  Weak::Map.new.merge!(*maps)
end

Instance Method Details

#[](key) ⇒ Object Also known as: store

Note:

Weak::Map does not test member equality with == or eql?. Instead, it always checks strict object equality, so that, e.g., different String keys are not considered equal, even if they may contain the same content.

Returns the value associated with the given key, if found. If key is not found, returns the default value, i.e. the value returned by the default proc (if defined) or the default value (which is initially nil.).

Parameters:

  • key (Object)

    the key for the requested value

Returns:

  • (Object)

    the value associated with the given key, if found. If key is not found, returns the default value, i.e. the value returned by the default proc (if defined) or the default value (which is initially nil.)

[View source] [View on GitHub]

# File 'lib/weak/map.rb', line 227

#[]=(key, value) ⇒ Object

Note:

Weak::Map does not test member equality with == or eql?. Instead, it always checks strict object equality, so that, e.g., different String keys are not considered equal, even if they may contain the same content.

Associates the given value with the given key; returns value. If the given key exists, replaces its value with the given value.

Parameters:

  • key (Object)

    the key for the set key-value pair

  • value (Object)

    the value of the set key-value pair

Returns:

  • (Object)

    the given value

[View source] [View on GitHub]

# File 'lib/weak/map.rb', line 230

#clearself

Removes all elements and returns self

Returns:

  • (self)
[View source] [View on GitHub]

# File 'lib/weak/map.rb', line 233

#clone(freeze: false) ⇒ Weak::Set

Weak::Map objects can't be frozen since this is not enforced by the underlying ObjectSpace::WeakMap implementation. Thus, we try to signal this by not actually setting the frozen? flag and ignoring attempts to freeze us with just a warning.

Parameters:

  • freeze (Bool, nil) (defaults to: false)

    ignored; we always behave as if this is false. If this is set to a truethy value, we emit a warning.

Returns:

  • (Weak::Set)

    a new Weak::Map object containing the same elements as self

[View source] [View on GitHub]

345
346
347
348
349
# File 'lib/weak/map.rb', line 345

def clone(freeze: false)
  warn("Can't freeze #{self.class}") if freeze

  super(freeze: false)
end

#compare_by_identityself

This method does nothing as we always compare elements by their object identity.

Returns:

  • (self)
[View source] [View on GitHub]

355
356
357
# File 'lib/weak/map.rb', line 355

def compare_by_identity
  self
end

#compare_by_identity?true

Returns always true since we always compare elements by their object identity.

Returns:

  • (true)

    always true since we always compare elements by their object identity

[View source] [View on GitHub]

361
362
363
# File 'lib/weak/map.rb', line 361

def compare_by_identity?
  true
end

#default(key = UNDEFINED) ⇒ Object

Returns the default value for the given key. The returned value will be determined either by the default proc or by the default value. With no argument, returns the current default value (initially nil). If key is given, returns the default value for key, regardless of whether that key exists.

Parameters:

  • key (Object) (defaults to: UNDEFINED)

    if given, we return the default value for this key

Returns:

  • (Object)

    the default value for key if given, or weak map's default value

[View source] [View on GitHub]

374
375
376
377
378
379
380
# File 'lib/weak/map.rb', line 374

def default(key = UNDEFINED)
  if UNDEFINED.equal? key
    @default_value
  else
    _default(key)
  end
end

#default=(default_value) ⇒ Object

Sets the default value to default_value and clears the #default_proc; returns default_value.

Parameters:

  • default_value (Object)

    the new default value which will be returned when accessing a non-existing key

Returns:

  • (Object)

    the given default_value

[View source] [View on GitHub]

388
389
390
391
# File 'lib/weak/map.rb', line 388

def default=(default_value)
  @default_proc = nil
  @default_value = default_value
end

#default_procProc?

Returns the default proc for self.

Returns:

  • (Proc, nil)

    the default proc for self

[View source] [View on GitHub]

394
395
396
# File 'lib/weak/map.rb', line 394

def default_proc
  @default_proc
end

#default_proc=(proc) ⇒ Proc?

Sets the default proc for self to proc and clears the #default value.

Parameters:

  • proc (Proc, #to_proc nil)

    a Proc which can be called with two arguments: the map and the rquested non-exiting key. The proc is expected to return the default value for the key. Whe giving nil, the default proc is cleared.

Returns:

  • (Proc, nil)

    the new default proc

Raises:

  • (TypeError)

    if the given proc can not be converted to a Proc.

[View source] [View on GitHub]

406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
# File 'lib/weak/map.rb', line 406

def default_proc=(proc)
  @default_value = nil
  return @default_proc = nil if proc.nil?

  if Proc === proc
    default_proc = proc
  elsif proc.respond_to?(:to_proc)
    default_proc = proc.to_proc
    unless Proc === default_proc
      raise TypeError, "can't convert #{proc.class} to Proc " \
        "(#{proc.class}#to_proc gives #{default_proc.class})"
    end
  else
    raise TypeError, "no implicit conversion of #{proc.class} into Proc"
  end

  if default_proc.lambda?
    arity = default_proc.arity
    if arity != 2 && (arity >= 0 || arity < -3)
      arity = -arity - 1 if arity < 0
      raise TypeError, "default_proc takes two arguments (2 for #{arity})"
    end
  end
  @default_proc = default_proc

  proc
end

#delete(key = UNDEFINED) {|key| ... } ⇒ Object?

Note:

Weak::Map does not test member equality with == or eql?. Instead, it always checks strict object equality, so that, e.g., different String keys are not considered equal, even if they may contain the same content.

Deletes the key-value pair and returns the value from self whose key is equal to key. If the key is not found, it returns nil. If the optional block is given and the key is not found, pass in the key and return the result of the block.

Parameters:

  • key (Object) (defaults to: UNDEFINED)

    the key to delete

Yields:

  • (key)

Yield Parameters:

  • key (Object)

    the given key if it was not part of the map

Returns:

  • (Object, nil)

    the value associated with the given key, or the result of the optional block if given the key was not found, or nil if the key was not found and no block was given.

[View source] [View on GitHub]

# File 'lib/weak/map.rb', line 236

#delete_if {|key, value| ... } ⇒ Enumerator, self

Deletes every key-value pair from self for which the given block evaluates to a truthy value.

If no block is given, an Enumerator is returned instead.

Yields:

  • (key, value)

    calls the given block once for each key in the map

Yield Parameters:

  • key (Object)

    a key

  • value (Object)

    the corresponding value

Returns:

  • (Enumerator, self)

    self if a block was given or an Enumerator if no block was given.

See Also:

[View source] [View on GitHub]

445
446
447
448
449
450
451
452
# File 'lib/weak/map.rb', line 445

def delete_if(&block)
  return enum_for(__method__) { size } unless block_given?

  each do |key, value|
    delete(key) if yield(key, value)
  end
  self
end

#each_key {|key| ... } ⇒ self, Enumerator

Calls the given block once for each live key in self, passing the key as a parameter. Returns the weak map itself.

If no block is given, an Enumerator is returned instead.

Yields:

  • (key)

    calls the given block once for each key in self

Yield Parameters:

  • key (Object)

    the key of the current key-value pair

Returns:

  • (self, Enumerator)

    self if a block was given or an Enumerator if no block was given.

[View source] [View on GitHub]

# File 'lib/weak/map.rb', line 242

#each_pair {|key, value| ... } ⇒ self, Enumerator Also known as: each

Calls the given block once for each live key in self, passing the key and value as parameters. Returns the weak map itself.

If no block is given, an Enumerator is returned instead.

Yields:

  • (key, value)

    calls the given block once for each key in self

Yield Parameters:

  • key (Object)

    the key of the current key-value pair

  • value (Object)

    the value of the current key-value pair

Returns:

  • (self, Enumerator)

    self if a block was given or an Enumerator if no block was given.

[View source] [View on GitHub]

# File 'lib/weak/map.rb', line 239

#each_value {|value| ... } ⇒ self, Enumerator

Calls the given block once for each live key self, passing the live value associated with the key as a parameter. Returns the weak map itself.

If no block is given, an Enumerator is returned instead.

Yields:

  • (value)

    calls the given block once for each key in self

Yield Parameters:

  • value (Object)

    the value of the current key-value pair

Returns:

  • (self, Enumerator)

    self if a block was given or an Enumerator if no block was given.

[View source] [View on GitHub]

# File 'lib/weak/map.rb', line 245

#empty?Boolean

Returns true if self contains no elements.

Returns:

  • (Boolean)

    true if self contains no elements

[View source] [View on GitHub]

455
456
457
# File 'lib/weak/map.rb', line 455

def empty?
  size == 0
end

#fetch(key, default = UNDEFINED) {|key| ... } ⇒ Object

Note:

Weak::Map does not test member equality with == or eql?. Instead, it always checks strict object equality, so that, e.g., different String keys are not considered equal, even if they may contain the same content.

Returns a value from the hash 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 value will be returned; if the optional code block is specified, then it will be called and its result returned.

Parameters:

  • key (Object)

    the key for the requested value

  • default (Object) (defaults to: UNDEFINED)

    a value to return if there is no value at key in the hash

Yields:

  • (key)

    if no value was set at key, no default value was given, and a block was given, we call the block and return its value

Yield Parameters:

  • key (String)

    the given key

Returns:

  • (Object)

    the value for the given key if present in the map. If the key was not found, we return the default value or the value of the given block.

Raises:

  • (KeyError)

    if the key can not be found and no block or default value was provided

[View source] [View on GitHub]

# File 'lib/weak/map.rb', line 248

#freezeself

Set objects can't be frozen since this is not enforced by the underlying ObjectSpace::WeakMap implementation. Thus, we try to signal this by not actually setting the frozen? flag and ignoring attempts to freeze us with just a warning.

Returns:

  • (self)
[View source] [View on GitHub]

465
466
467
468
# File 'lib/weak/map.rb', line 465

def freeze
  warn("Can't freeze #{self.class}")
  self
end

#has_value?(value) ⇒ Bool Also known as: value?

Note:

Weak::Map does not test member equality with == or eql?. Instead, it always checks strict object equality, so that, e.g., different String keys are not considered equal, even if they may contain the same content.

Returns true if value is a value in self, false otherwise.

Parameters:

  • value (Object)

    a value to check

Returns:

  • (Bool)

    true if value is a value in self, false otherwise

[View source] [View on GitHub]

474
475
476
477
# File 'lib/weak/map.rb', line 474

def has_value?(value)
  id = value.__id__
  each_value.any? { |v| v.__id__ == id }
end

#include?(key) ⇒ Bool Also known as: has_key?, key?, member?

Note:

Weak::Map does not test member equality with == or eql?. Instead, it always checks strict object equality, so that, e.g., different String keys are not considered equal, even if they may contain the same content.

Returns true if the given key is included in self and has an associated live value, false otherwise.

Parameters:

  • key (Object)

    a possible key

Returns:

  • (Bool)

    true if the given key is included in self and has an associated live value, false otherwise

[View source] [View on GitHub]

# File 'lib/weak/map.rb', line 251

#inspectString Also known as: to_s

Returns a string containing a human-readable representation of the weak set, e.g., "#<Weak::Map {key1 => value1, key2 => value2, ...}>".

Returns:

  • (String)

    a string containing a human-readable representation of the weak set, e.g., "#<Weak::Map {key1 => value1, key2 => value2, ...}>"

[View source] [View on GitHub]

483
484
485
486
487
488
489
490
491
492
493
494
# File 'lib/weak/map.rb', line 483

def inspect
  object_ids = (Thread.current[INSPECT_KEY] ||= [])
  return "#<#{self.class} {...}>" if object_ids.include?(object_id)

  object_ids << object_id
  begin
    elements = to_a.sort_by! { |k, _v| k.__id__ }.to_h.inspect[1..-2]
    "#<#{self.class} {#{elements}}>"
  ensure
    object_ids.pop
  end
end

#keep_if {|key, value| ... } ⇒ Enumerator, self

Deletes every key-value pair from self for which the given block evaluates to a falsey value.

If no block is given, an Enumerator is returned instead.

Yields:

  • (key, value)

    calls the given block once for each key in the map

Yield Parameters:

  • key (String)

    a hash key

  • value (Object)

    the corresponding hash value

Returns:

  • (Enumerator, self)

    self if a block was given, an Enumerator if no block was given.

See Also:

[View source] [View on GitHub]

508
509
510
511
512
513
514
515
# File 'lib/weak/map.rb', line 508

def keep_if(&block)
  return enum_for(__method__) { size } unless block_given?

  each do |key, value|
    delete(key) unless yield(key, value)
  end
  self
end

#keysArray

Note:

In contrast to a Hash, Weak::Maps do not necessarily retain insertion order.

Returns an Array containing all keys of the map for which we have a valid value. Keys with garbage-collected values are excluded.

Returns:

  • (Array)

    an Array containing all keys of the map for which we have a valid value. Keys with garbage-collected values are excluded.

See Also:

[View source] [View on GitHub]

# File 'lib/weak/map.rb', line 254

#merge(*other_maps) {|key, old_value, new_value| ... } ⇒ Weak::Map

Note:

Weak::Map does not test member equality with == or eql?. Instead, it always checks strict object equality, so that, e.g., different String keys are not considered equal, even if they may contain the same content.

Returns the new Weak::Map formed by merging each of other_maps into a copy of self.

Each argument in other_maos must be respond to each_pair, e.g. a Weak::Map or a Hash.

With arguments and no block:

  • Returns a new Weak::Map, after the given maps are merged into a copy of self.
  • The given hashes are merged left to right.
  • Each duplicate-key entry’s value overwrites the previous value.

Example:

map = Weak::Map.new
map[:foo] = 0
map[:bar] = 1

h1 = {baz: 3, bar: 4}
h2 = {bam: 5, baz: 6}
map.merge(h1, h2)
# => #<Weak::Map {:foo=>0, :bar=>4, :baz=>6, :bam=>5}

With arguments and a block:

  • Returns self, after the given maps are merged.
  • The given hashes are merged left to right.
  • For each duplicate key:
    • Calls the block with the key and the old and new values.
    • The block’s return value becomes the new value for the entry.
  • The block should only return values which are otherwise strongly referenced to ensure that the value is not immediately garbage-collected.

Example:

map = Weak::Map.new
map[:foo] = 0
map[:bar] = 1

h1 = {baz: 3, bar: 4}
h2 = {bam: 5, baz: 6}
map.merge(h1, h2) { |key, old_value, new_value| old_value + new_value }
# => #<Weak::Map {:foo=>0, :bar=>5, :baz=>9, :bam=>5}

With no arguments:

  • Returns a copy of self.
  • The block, if given, is ignored.

Parameters:

  • other_maps (Array<#each_pair>)

    a list of maps which should be merged into a copy of self

Yields:

  • (key, old_value, new_value)

    If self already contains a value for a key, we yield the key, the old value from self and the new value from the given map and use the value returned from the block as the new value to be merged.

Yield Parameters:

  • key (Object)

    the conflicting key

  • old_value (Object)

    the existing value from self

  • old_value (Object)

    the new value from one of the given other_maps

Returns:

  • (Weak::Map)

    a new weak map containing the merged pairs

[View source] [View on GitHub]

581
582
583
# File 'lib/weak/map.rb', line 581

def merge(*other_maps, &block)
  dup.merge!(*other_maps, &block)
end

#pruneself

Cleanup data structures from the map to remove data associated with deleted or garbage collected keys and/or values. This method may be called automatically for some Weak::Map operations.

Returns:

  • (self)
[View source] [View on GitHub]

# File 'lib/weak/map.rb', line 257

#reject! {|key, value| ... } ⇒ Enumerator, ...

Deletes every key-value pair from self for which the given block evaluates to a truethy value.

Equivalent to #delete_if, but returns nil if no changes were made.

If no block is given, an Enumerator is returned instead.

deleted, or an Enumerator if no block was given.

see #delete_if

Yields:

  • (key, value)

    calls the given block once for each key in the map

Yield Parameters:

  • key (Object)

    a key

Returns:

  • (Enumerator, self, nil)

    self if a block was given and some element(s) were deleted, nil if a block was given but no keys were

[View source] [View on GitHub]

606
607
608
609
610
611
612
613
614
615
616
617
618
# File 'lib/weak/map.rb', line 606

def reject!(&block)
  return enum_for(__method__) { size } unless block_given?

  deleted_anything = false
  each do |key, value|
    next unless yield(key, value)

    delete(key)
    deleted_anything = true
  end

  self if deleted_anything
end

#select! {|key, value| ... } ⇒ Enumerator, ... Also known as: filter!

Deletes every key-value pair from self for which the given block evaluates to a falsey value.

Equivalent to #keep_if, but returns nil if no changes were made.

If no block is given, an Enumerator is returned instead.

Yields:

  • (key, value)

    calls the given block once for each key in the map

Yield Parameters:

  • key (Object)

    a key

  • value (Object)

    the corresponding value

Returns:

  • (Enumerator, self, nil)

    self if a block was given and some element(s) were deleted, nil if a block was given but nothing was deleted, or an Enumerator if no block was given.

See Also:

[View source] [View on GitHub]

634
635
636
637
638
639
640
641
642
643
644
645
646
# File 'lib/weak/map.rb', line 634

def select!(&block)
  return enum_for(__method__) { size } unless block_given?

  deleted_anything = false
  each do |key, value|
    next if yield(key, value)

    delete(key)
    deleted_anything = true
  end

  self if deleted_anything
end

#sizeInteger Also known as: length

Returns the number of live key-value pairs in self.

Returns:

  • (Integer)

    the number of live key-value pairs in self

[View source] [View on GitHub]

# File 'lib/weak/map.rb', line 260

#to_aArray

Returns a new Array of 2-element Array objects; each nested Array contains a key-value pair from self.

Returns:

  • (Array)

    a new Array of 2-element Array objects; each nested Array contains a key-value pair from self

[View source] [View on GitHub]

736
737
738
# File 'lib/weak/map.rb', line 736

def to_a
  to_h.to_a
end

#to_h {|key, value| ... } ⇒ Hash

Returns a new Hash which considers object identity for keys which contains the key-value pairs in self.

Yields:

  • (key, value)

    When a block is given, returns a new Hash object whose content is based on the block; the block should return a 2-element Array object specifying the key-value pair to be included in the returned Hash.

Yield Parameters:

  • key (Object)

    the key of the current key-value pair

  • value (Object)

    the value of the current key-value pair

Returns:

  • (Hash)

    a new Hash which considers object identity for keys which contains the key-value pairs in self.

[View source] [View on GitHub]

748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
# File 'lib/weak/map.rb', line 748

def to_h(&block)
  hash = {}.compare_by_identity
  if block_given?
    each do |key, value|
      map = yield(key, value)
      ary = Array.try_convert(map)
      unless ary
        raise TypeError, "wrong element type #{map.class} (expected array)"
      end
      unless ary.size == 2
        raise ArgumentError, "element has wrong array length " \
          "(expected 2, was #{ary.size})"
      end

      hash[ary[0]] = ary[1]
    end
  else
    each do |key, value|
      hash[key] = value
    end
  end

  hash
end

#update(*other_maps) {|key, old_value, new_value| ... } ⇒ self Also known as: merge!

Note:

Weak::Map does not test member equality with == or eql?. Instead, it always checks strict object equality, so that, e.g., different String keys are not considered equal, even if they may contain the same content.

Merges each of other_maps into self; returns self.

Each argument in other_maos must be respond to each_pair, e.g. a Weak::Map or a Hash.

With arguments and no block:

  • Returns self, after the given maps are merged into it.
  • The given hashes are merged left to right.
  • Each duplicate-key entry’s value overwrites the previous value.

Example:

map = Weak::Map.new
map[:foo] = 0
map[:bar] = 1

h1 = {baz: 3, bar: 4}
h2 = {bam: 5, baz: 6}
map.update(h1, h2)
# => #<Weak::Map {:foo=>0, :bar=>4, :baz=>6, :bam=>5}

With arguments and a block:

  • Returns self, after the given maps are merged.
  • The given hashes are merged left to right.
  • For each duplicate key:
    • Calls the block with the key and the old and new values.
    • The block’s return value becomes the new value for the entry.
  • The block should only return values which are otherwise strongly referenced to ensure that the value is not immediately garbage-collected.

Example:

map = Weak::Map.new
map[:foo] = 0
map[:bar] = 1

h1 = {baz: 3, bar: 4}
h2 = {bam: 5, baz: 6}
map.update(h1, h2) { |key, old_value, new_value| old_value + new_value }
# => #<Weak::Map {:foo=>0, :bar=>5, :baz=>9, :bam=>5}

With no arguments:

  • Returns self.
  • The block, if given, is ignored.

Parameters:

  • other_maps (Array<#each_pair>)

    a list of maps which should be merged into self

Yields:

  • (key, old_value, new_value)

    If self already contains a value for a key, we yield the key, the old value from self and the new value from the given map and use the value returned from the block as the new value to be merged.

Yield Parameters:

  • key (Object)

    the conflicting key

  • old_value (Object)

    the existing value from self

  • old_value (Object)

    the new value from one of the given other_maps

Returns:

  • (self)
[View source] [View on GitHub]

711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
# File 'lib/weak/map.rb', line 711

def update(*other_maps)
  if block_given?
    missing = Object.new

    other_maps.each do |map|
      map.each_pair do |key, value|
        old_value = fetch(key, missing)
        value = yield(key, old_value, value) unless missing == old_value
        self[key] = value
      end
    end
  else
    other_maps.each do |map|
      map.each_pair do |key, value|
        self[key] = value
      end
    end
  end

  self
end

#valuesArray

Note:

In contrast to a Hash, Weak::Maps do not necessarily retain insertion order.

Returns an Array containing all values of the map for which we have a valid key. Values with garbage-collected keys are excluded.

Returns:

  • (Array)

    an Array containing all values of the map for which we have a valid key. Values with garbage-collected keys are excluded.

See Also:

[View source] [View on GitHub]

# File 'lib/weak/map.rb', line 263

#values_at(*keys) ⇒ Array

Returns a new Array containing values for the given keys:

map = Weak::Map[foo: 0, bar: 1, baz: 2]
map.values_at(:baz, :foo)
# => [2, 0]

The default values are returned for any keys that are not found:

map.values_at(:hello, :foo)
# => [nil, 0]

Parameters:

  • keys (Array<Object>)

    a list of keys

Returns:

  • (Array)

    an Array containing the values for the given keys if present or the default value if not. The order of the given keys is preserved.

[View source] [View on GitHub]

788
789
790
# File 'lib/weak/map.rb', line 788

def values_at(*keys)
  keys.map { |key| self[key] }
end