Module: Hamster::Associable

Included in:
Hash, Vector
Defined in:
lib/hamster/associable.rb

Overview

Including Associable in your container class gives it an update_in method.

To mix in Associable, your class must implement two methods:

  • fetch(index, default = (missing_default = true))
  • put(index, item = yield(get(index)))

See Vector#fetch, Vector#put, Hash#fetch, and Hash#put for examples.

Instance Method Summary collapse

Instance Method Details

#update_in(*key_path) {|value| ... } ⇒ Associable

Return a new container with a deeply nested value modified to the result of the given code block. When traversing the nested containers non-existing keys are created with empty Hash values.

The code block receives the existing value of the deeply nested key/index (or nil if it doesn't exist). This is useful for "transforming" the value associated with a certain key/index.

Naturally, the original container and sub-containers are left unmodified; new data structure copies are created along the path as needed.

Examples:

v = Hamster::Vector[123, 456, 789, Hamster::Hash["a" => Hamster::Vector[5, 6, 7]]]
v.update_in(3, "a", 1) { |value| value + 9 }
# => Hamster::Vector[123, 456, 789, Hamster::Hash["a" => Hamster::Vector[5, 15, 7]]]
hash = Hamster::Hash["a" => Hamster::Hash["b" => Hamster::Hash["c" => 42]]]
hash.update_in("a", "b", "c") { |value| value + 5 }
# => Hamster::Hash["a" => Hamster::Hash["b" => Hamster::Hash["c" => 47]]]

Parameters:

  • key_path (Object(s))

    List of keys/indexes which form the path to the key to be modified

Yields:

  • (value)

    The previously stored value

Yield Returns:

  • (Object)

    The new value to store

Returns:



35
36
37
38
39
40
41
42
43
44
45
46
47
# File 'lib/hamster/associable.rb', line 35

def update_in(*key_path, &block)
  if key_path.empty?
    raise ArgumentError, "must have at least one key in path"
  end
  key = key_path[0]
  if key_path.size == 1
    new_value = block.call(fetch(key, nil))
  else
    value = fetch(key, EmptyHash)
    new_value = value.update_in(*key_path[1..-1], &block)
  end
  put(key, new_value)
end