Class: Erlang::Map
- Inherits:
-
Object
- Object
- Erlang::Map
- Includes:
- Associable, Enumerable
- Defined in:
- lib/erlang/map.rb
Overview
A Erlang::Map maps a set of unique keys to corresponding values, much
like a dictionary maps from words to definitions. Given a key, it can store
and retrieve an associated value in constant time. If an existing key is
stored again, the new value will replace the old. It behaves much like
Ruby's built-in Hash, which we will call RubyHash for clarity. Like
RubyHash, two keys that are #eql? to each other and have the same
#hash are considered identical in a Erlang::Map.
A Erlang::Map can be created in a couple of ways:
Erlang::Map[first_name: 'John', last_name: 'Smith']
Erlang::Map[:first_name, 'John', :last_name, 'Smith']
Any Enumerable object with an even number of elements can be used to
initialize a Erlang::Map:
Erlang::Map[:first_name, 'John', :last_name, 'Smith']
Any Enumerable object which yields two-element [key, value] arrays
can be used to initialize a Erlang::Map:
Erlang::Map.new([[:first_name, 'John'], [:last_name, 'Smith']])
Key/value pairs can be added using #put. A new map is returned and the existing one is left unchanged:
map = Erlang::Map[a: 100, b: 200]
map.put(:c, 500) # => Erlang::Map[:a => 100, :b => 200, :c => 500]
map # => Erlang::Map[:a => 100, :b => 200]
#put can also take a block, which is used to calculate the value to be stored.
map.put(:a) { |current| current + 200 } # => Erlang::Map[:a => 300, :b => 200]
Since it is immutable, all methods which you might expect to "modify" a
Erlang::Map actually return a new map and leave the existing one
unchanged. This means that the map[key] = value syntax from RubyHash
cannot be used with Erlang::Map.
Nested data structures can easily be updated using #update_in:
map = Erlang::Map["a" => Erlang::Tuple[Erlang::Map["c" => 42]]]
map.update_in("a", 0, "c") { |value| value + 5 }
# => Erlang::Map["a" => Erlang::Tuple[Erlang::Map["c" => 47]]]
While a Erlang::Map can iterate over its keys or values, it does not
guarantee any specific iteration order (unlike RubyHash). Methods like
#flatten do not guarantee the order of returned key/value pairs.
Like RubyHash, a Erlang::Map can have a default block which is used
when looking up a key that does not exist. Unlike RubyHash, the default
block will only be passed the missing key, without the hash itself:
map = Erlang::Map.new { |missing_key| missing_key * 10 }
map[5] # => 50
Licensing
Portions taken and modified from https://github.com/hamstergem/hamster
Copyright (c) 2009-2014 Simon Harris
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
Class Method Summary collapse
-
.[](*pairs) ⇒ Map
Create a new
Mappopulated with the given key/value pairs. - .compare(a, b) ⇒ Object
-
.empty ⇒ Map
Return an empty
Map.
Instance Method Summary collapse
-
#assoc(obj) ⇒ Tuple
Searches through the
Map, comparingobjwith each key (using#==). -
#clear ⇒ Map
Return an empty
Mapinstance, of the same class as this one. -
#default_proc ⇒ Proc
Return the default block if there is one.
-
#delete(key) ⇒ Map
Return a new
Mapwithkeyremoved. -
#each {|key, value| ... } ⇒ self
(also: #each_pair)
Call the block once for each key/value pair in this
Map, passing the key/value pair as parameters. -
#each_key {|key| ... } ⇒ self
Call the block once for each key/value pair in this
Map, passing the key as a parameter. -
#each_value {|value| ... } ⇒ self
Call the block once for each key/value pair in this
Map, passing the value as a parameter. -
#empty? ⇒ Boolean
Return
trueif thisMapcontains no key/value pairs. -
#eql?(other) ⇒ Boolean
(also: #==)
Return true if
otherhas the same type and contents as thisMap. -
#erlang_inspect(raw = false) ⇒ String
Allows this
Mapto be printed usingErlang.inspect(). -
#except(*keys) ⇒ Map
Return a new
Mapwith the associations for all of the givenkeysremoved. -
#fetch(key, default = Undefined) ⇒ Object
Retrieve the value corresponding to the given key object, or use the provided default value or block, or otherwise raise a
KeyError. -
#fetch_values(*wanted) ⇒ Tuple
Return a List of the values which correspond to the
wantedkeys. -
#find {|key, value| ... } ⇒ Array
(also: #detect)
Yield
[key, value]pairs until one is found for which the block returns true. -
#flatten(level = 1) ⇒ List
Return a new List which is a one-dimensional flattening of this
Map. -
#get(key) ⇒ Object
(also: #[])
Retrieve the value corresponding to the provided key object.
-
#hash ⇒ Integer
See
Object#hash. -
#initialize(pairs = nil) {|key| ... } ⇒ Map
constructor
A new instance of Map.
-
#inspect ⇒ String
Return the contents of this
Mapas a programmer-readableString. -
#invert ⇒ Map
Return a new
Mapcreated by using keys as values and values as keys. -
#key(value) ⇒ Object
Searches through the
Map, comparingvaluewith each value (using#==). -
#key?(key) ⇒ Boolean
(also: #has_key?, #include?, #member?)
Return
trueif the given key object is present in thisMap. -
#keys ⇒ Set
Return a new List containing the keys from this
Map. -
#map {|key, value| ... } ⇒ Map
(also: #collect)
Call the block once for each key/value pair in this
Map, passing the key/value pair as parameters. -
#merge(other) {|key, my_value, other_value| ... } ⇒ Map
Return a new
Mapcontaining all the key/value pairs from thisMapandother. -
#put(key, value = yield(get(key))) {|value| ... } ⇒ Map
Return a new
Mapwith the existing key/value associations, plus an association between the provided key and value. -
#rassoc(obj) ⇒ Tuple
Searches through the
Map, comparingobjwith each value (using#==). -
#reverse_each {|key, value| ... } ⇒ self
Call the block once for each key/value pair in this
Map, passing the key/value pair as parameters. -
#sample ⇒ Tuple
Return a randomly chosen
[key, value]pair from thisMap. -
#select {|key, value| ... } ⇒ Map
(also: #find_all, #keep_if)
Return a new
Mapwith all the key/value pairs for which the block returns true. -
#slice(*wanted) ⇒ Map
Return a new
Mapwith only the associations for thewantedkeys retained. -
#sort(&comparator) ⇒ List
Return a sorted List which contains all the
[key, value]pairs in thisMapas two-elementTuples. -
#sort_by {|key, value| ... } ⇒ List
Return a List which contains all the
[key, value]pairs in thisHashas two-elementTuples. -
#store(key, value) ⇒ Map
An alias for #put to match RubyHash's API.
-
#to_hash ⇒ ::Hash
(also: #to_h)
Convert this
Erlang::Mapto an instance of Ruby's built-inHash. -
#to_proc ⇒ Proc
Return a Proc which accepts a key as an argument and returns the value.
-
#update_in(*key_path) {|value| ... } ⇒ Map
Return a new
Mapwith a deeply nested value modified to the result of the given code block. -
#value?(value) ⇒ Boolean
(also: #has_value?)
Return
trueif thisMaphas one or more keys which map to the provided value. -
#values ⇒ List
Return a new List populated with the values from this
Map. -
#values_at(*wanted) ⇒ List
Return a List of the values which correspond to the
wantedkeys.
Methods included from Associable
Methods included from Enumerable
#compact, #each_index, #grep, #grep_v, #group_by, #join, #partition, #product, #reject, #sum
Constructor Details
#initialize(pairs = nil) {|key| ... } ⇒ Map
Returns a new instance of Map.
149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 |
# File 'lib/erlang/map.rb', line 149 def initialize(pairs = nil, &block) if pairs obj = ::Array.new(pairs.size) i = 0 pairs.each do |key, val| obj[i] = [Erlang.from(key), Erlang.from(val)] i += 1 end pairs = obj end @trie = pairs ? Trie[pairs] : EmptyTrie @default = block if block_given? @default = ->(key) { return Erlang.from(block.call(key)) } end end |
Class Method Details
.[](*pairs) ⇒ Map
Create a new Map populated with the given key/value pairs.
105 106 107 108 109 110 111 112 113 114 |
# File 'lib/erlang/map.rb', line 105 def [](*pairs) return empty if pairs.nil? or pairs.empty? if pairs.size == 1 return pairs[0] if pairs[0].is_a?(Erlang::Map) return new(pairs[0]) if pairs[0].is_a?(::Hash) end raise ArgumentError, 'odd number of arguments for Erlang::Map' if pairs.size.odd? pairs = pairs.each_slice(2).to_a return new(pairs) end |
.compare(a, b) ⇒ Object
136 137 138 139 140 141 142 143 |
# File 'lib/erlang/map.rb', line 136 def compare(a, b) raise ArgumentError, "'a' must be of Erlang::Map type" if not a.kind_of?(Erlang::Map) raise ArgumentError, "'b' must be of Erlang::Map type" if not b.kind_of?(Erlang::Map) c = a.size <=> b.size return c if c != 0 return 0 if a.eql?(b) return Erlang.compare(a.sort, b.sort) end |
.empty ⇒ Map
Return an empty Map. If used on a subclass, returns an empty instance
of that class.
120 121 122 |
# File 'lib/erlang/map.rb', line 120 def empty return @empty ||= self.new end |
Instance Method Details
#assoc(obj) ⇒ Tuple
Searches through the Map, comparing obj with each key (using #==).
When a matching key is found, return the [key, value] pair as a Tuple.
Return nil if no match is found.
742 743 744 745 746 |
# File 'lib/erlang/map.rb', line 742 def assoc(obj) obj = Erlang.from(obj) each { |entry| return Erlang::Tuple[*entry] if obj == entry[0] } return nil end |
#clear ⇒ Map
Return an empty Map instance, of the same class as this one. Useful if you
have multiple subclasses of Map and want to treat them polymorphically.
Maintains the default block, if there is one.
795 796 797 798 799 800 801 |
# File 'lib/erlang/map.rb', line 795 def clear if @default return self.class.alloc(EmptyTrie, @default) else return self.class.empty end end |
#default_proc ⇒ Proc
Return the default block if there is one. Otherwise, return nil.
171 172 173 |
# File 'lib/erlang/map.rb', line 171 def default_proc return @default end |
#delete(key) ⇒ Map
Return a new Map with key removed. If key is not present, return
self.
378 379 380 |
# File 'lib/erlang/map.rb', line 378 def delete(key) return derive_new_map(@trie.delete(key)) end |
#each {|key, value| ... } ⇒ self Also known as: each_pair
Call the block once for each key/value pair in this Map, passing the key/value
pair as parameters. No specific iteration order is guaranteed, though the order will
be stable for any particular Map.
396 397 398 399 400 |
# File 'lib/erlang/map.rb', line 396 def each(&block) return to_enum if not block_given? @trie.each(&block) return self end |
#each_key {|key| ... } ⇒ self
Call the block once for each key/value pair in this Map, passing the key as a
parameter. Ordering guarantees are the same as #each.
435 436 437 438 439 |
# File 'lib/erlang/map.rb', line 435 def each_key return enum_for(:each_key) if not block_given? @trie.each { |k,v| yield k } return self end |
#each_value {|value| ... } ⇒ self
Call the block once for each key/value pair in this Map, passing the value as a
parameter. Ordering guarantees are the same as #each.
454 455 456 457 458 |
# File 'lib/erlang/map.rb', line 454 def each_value return enum_for(:each_value) if not block_given? @trie.each { |k,v| yield v } return self end |
#empty? ⇒ Boolean
Return true if this Map contains no key/value pairs.
190 191 192 |
# File 'lib/erlang/map.rb', line 190 def empty? return @trie.empty? end |
#eql?(other) ⇒ Boolean Also known as: ==
Return true if other has the same type and contents as this Map.
807 808 809 810 811 |
# File 'lib/erlang/map.rb', line 807 def eql?(other) return true if other.equal?(self) return @trie.eql?(other.instance_variable_get(:@trie)) if instance_of?(other.class) return !!(Erlang.compare(other, self) == 0) end |
#erlang_inspect(raw = false) ⇒ String
Allows this Map to be printed using Erlang.inspect().
843 844 845 846 847 848 849 850 851 852 |
# File 'lib/erlang/map.rb', line 843 def erlang_inspect(raw = false) result = '#{' each_with_index do |(key, val), i| result << ',' if i > 0 result << Erlang.inspect(key, raw: raw) result << ' => ' result << Erlang.inspect(val, raw: raw) end return result << '}' end |
#except(*keys) ⇒ Map
Return a new Map with the associations for all of the given keys removed.
609 610 611 |
# File 'lib/erlang/map.rb', line 609 def except(*keys) return keys.reduce(self) { |map, key| map.delete(key) } end |
#fetch(key) ⇒ Object #fetch(key) {|key| ... } ⇒ Object #fetch(key, default) ⇒ Object
Retrieve the value corresponding to the given key object, or use the provided
default value or block, or otherwise raise a KeyError.
286 287 288 289 290 291 292 293 294 295 296 297 298 |
# File 'lib/erlang/map.rb', line 286 def fetch(key, default = Undefined) key = Erlang.from(key) entry = @trie.get(key) if entry return entry[1] elsif block_given? return yield(key) elsif not Undefined.equal?(default) return Erlang.from(default) else raise KeyError, "key not found: #{key.inspect}" end end |
#fetch_values(*wanted) ⇒ Tuple
Return a List of the values which correspond to the wanted keys.
If any of the wanted keys are not present in this Map, raise KeyError
exception.
660 661 662 663 664 665 666 |
# File 'lib/erlang/map.rb', line 660 def fetch_values(*wanted) array = wanted.map { |key| key = Erlang.from(key) fetch(key) } return List.from_enum(array.freeze) end |
#find {|key, value| ... } ⇒ Array Also known as: detect
Yield [key, value] pairs until one is found for which the block returns true.
Return that [key, value] pair. If the block never returns true, return nil.
506 507 508 509 510 |
# File 'lib/erlang/map.rb', line 506 def find return enum_for(:find) unless block_given? each { |entry| return entry if yield entry } return nil end |
#flatten(level = 1) ⇒ List
Return a new List which is a one-dimensional flattening of this Map.
If level is 1, all the [key, value] pairs in the hash will be concatenated
into one List. If level is greater than 1, keys or values which are
themselves Arrays or Lists will be recursively flattened into the output
List. The depth to which that flattening will be recursively applied is
determined by level.
As a special case, if level is 0, each [key, value] pair will be a
separate element in the returned List.
725 726 727 728 729 730 731 |
# File 'lib/erlang/map.rb', line 725 def flatten(level = 1) return List.from_enum(self) if level == 0 array = [] each { |k,v| array << k; array << v } array.flatten!(level-1) if level > 1 return List.from_enum(array.freeze) end |
#get(key) ⇒ Object Also known as: []
Retrieve the value corresponding to the provided key object. If not found, and
this Map has a default block, the default block is called to provide the
value. Otherwise, return nil.
242 243 244 245 246 247 248 249 250 |
# File 'lib/erlang/map.rb', line 242 def get(key) key = Erlang.from(key) entry = @trie.get(key) if entry return entry[1] elsif @default return @default.call(key) end end |
#hash ⇒ Integer
See Object#hash.
816 817 818 819 820 |
# File 'lib/erlang/map.rb', line 816 def hash return keys.sort.reduce(Erlang::Map.hash) do |acc, key| (acc << 32) - acc + key.hash + get(key).hash end end |
#inspect ⇒ String
Return the contents of this Map as a programmer-readable String. If all the
keys and values are serializable as Ruby literal strings, the returned string can
be passed to eval to reconstitute an equivalent Map. The default
block (if there is one) will be lost when doing this, however.
828 829 830 831 832 833 834 835 836 837 838 |
# File 'lib/erlang/map.rb', line 828 def inspect # result = "#{self.class}[" result = "{" i = 0 each do |key, val| result << ', ' if i > 0 result << key.inspect << ' => ' << val.inspect i += 1 end return result << "}" end |
#invert ⇒ Map
Return a new Map created by using keys as values and values as keys.
If there are multiple values which are equivalent (as determined by #hash and
#eql?), only one out of each group of equivalent values will be
retained. Which one specifically is undefined.
700 701 702 703 704 |
# File 'lib/erlang/map.rb', line 700 def invert pairs = [] each { |k,v| pairs << [v, k] } return self.class.new(pairs, &@default) end |
#key(value) ⇒ Object
Searches through the Map, comparing value with each value (using #==).
When a matching value is found, return its associated key object.
Return nil if no match is found.
772 773 774 775 776 |
# File 'lib/erlang/map.rb', line 772 def key(value) value = Erlang.from(value) each { |entry| return entry[0] if value == entry[1] } return nil end |
#key?(key) ⇒ Boolean Also known as: has_key?, include?, member?
Return true if the given key object is present in this Map. More precisely,
return true if a key with the same #hash code, and which is also #eql?
to the given key object is present.
203 204 205 206 |
# File 'lib/erlang/map.rb', line 203 def key?(key) key = Erlang.from(key) return @trie.key?(key) end |
#keys ⇒ Set
Return a new List containing the keys from this Map.
675 676 677 |
# File 'lib/erlang/map.rb', line 675 def keys return Erlang::List.from_enum(each_key.to_a.freeze) end |
#map {|key, value| ... } ⇒ Map Also known as: collect
Call the block once for each key/value pair in this Map, passing the key/value
pair as parameters. The block should return a [key, value] array each time.
All the returned [key, value] arrays will be gathered into a new Map.
471 472 473 474 475 |
# File 'lib/erlang/map.rb', line 471 def map return enum_for(:map) unless block_given? return self if empty? return self.class.new(super, &@default) end |
#merge(other) {|key, my_value, other_value| ... } ⇒ Map
Return a new Map containing all the key/value pairs from this Map and
other. If no block is provided, the value for entries with colliding keys
will be that from other. Otherwise, the value for each duplicate key is
determined by calling the block.
other can be a Erlang::Map, a built-in Ruby Map, or any Enumerable
object which yields [key, value] pairs.
535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 |
# File 'lib/erlang/map.rb', line 535 def merge(other) other = Erlang.from(other) trie = if block_given? other.reduce(@trie) do |acc, (key, value)| if entry = acc.get(key) acc.put(key, yield(key, entry[1], value)) else acc.put(key, value) end end else @trie.bulk_put(other) end return derive_new_map(trie) end |
#put(key, value = yield(get(key))) {|value| ... } ⇒ Map
Return a new Map with the existing key/value associations, plus an association
between the provided key and value. If an equivalent key is already present, its
associated value will be replaced with the provided one.
If the value argument is missing, but an optional code block is provided,
it will be passed the existing value (or nil if there is none) and what it
returns will replace the existing value. This is useful for "transforming"
the value associated with a certain key.
Avoid mutating objects which are used as keys. Strings are an exception:
unfrozen Strings which are used as keys are internally duplicated and
frozen. This matches RubyHash's behaviour.
325 326 327 328 329 330 331 332 |
# File 'lib/erlang/map.rb', line 325 def put(key, value = yield(get(key))) new_trie = @trie.put(Erlang.from(key), Erlang.from(value)) if new_trie.equal?(@trie) return self else return self.class.alloc(new_trie, @default) end end |
#rassoc(obj) ⇒ Tuple
Searches through the Map, comparing obj with each value (using #==).
When a matching value is found, return the [key, value] pair as a Tuple.
Return nil if no match is found.
757 758 759 760 761 |
# File 'lib/erlang/map.rb', line 757 def rassoc(obj) obj = Erlang.from(obj) each { |entry| return Erlang::Tuple[*entry] if obj == entry[1] } return nil end |
#reverse_each {|key, value| ... } ⇒ self
Call the block once for each key/value pair in this Map, passing the key/value
pair as parameters. Iteration order will be the opposite of #each.
416 417 418 419 420 |
# File 'lib/erlang/map.rb', line 416 def reverse_each(&block) return enum_for(:reverse_each) if not block_given? @trie.reverse_each(&block) return self end |
#sample ⇒ Tuple
Return a randomly chosen [key, value] pair from this Map. If the hash is empty,
return nil.
786 787 788 |
# File 'lib/erlang/map.rb', line 786 def sample return Erlang::Tuple[*@trie.at(rand(size))] end |
#select {|key, value| ... } ⇒ Map Also known as: find_all, keep_if
Return a new Map with all the key/value pairs for which the block returns true.
488 489 490 491 |
# File 'lib/erlang/map.rb', line 488 def select(&block) return enum_for(:select) unless block_given? return derive_new_map(@trie.select(&block)) end |
#slice(*wanted) ⇒ Map
Return a new Map with only the associations for the wanted keys retained.
621 622 623 624 625 626 627 628 |
# File 'lib/erlang/map.rb', line 621 def slice(*wanted) trie = Trie.new(0) wanted.each { |key| key = Erlang.from(key) trie.put!(key, get(key)) if key?(key) } return self.class.alloc(trie, @default) end |
#sort ⇒ List #sort({ |(k1, v1), (k2, v2)| ... }) {|(k1, v1), (k2, v2)| ... } ⇒ List
Return a sorted List which contains all the [key, value] pairs in
this Map as two-element Tuples.
571 572 573 574 575 576 |
# File 'lib/erlang/map.rb', line 571 def sort(&comparator) comparator = Erlang.method(:compare) unless block_given? array = super(&comparator) array.map! { |k, v| next Erlang::Tuple[k, v] } return List.from_enum(array) end |
#sort_by {|key, value| ... } ⇒ List
Return a List which contains all the [key, value] pairs in this Hash
as two-element Tuples. The order which the pairs will appear in is determined by
passing each pair to the code block to obtain a sort key object, and comparing
the sort keys using #<=>.
593 594 595 596 597 598 599 |
# File 'lib/erlang/map.rb', line 593 def sort_by(&transformer) return sort unless block_given? block = ->(x) { Erlang.from(transformer.call(x)) } array = super(&block) array.map! { |k, v| next Erlang::Tuple[k, v] } return List.from_enum(array) end |
#store(key, value) ⇒ Map
365 366 367 |
# File 'lib/erlang/map.rb', line 365 def store(key, value) return put(key, value) end |
#to_hash ⇒ ::Hash Also known as: to_h
Convert this Erlang::Map to an instance of Ruby's built-in Hash.
880 881 882 883 884 885 886 |
# File 'lib/erlang/map.rb', line 880 def to_hash output = {} each do |key, value| output[key] = value end return output end |
#to_proc ⇒ Proc
Return a Proc which accepts a key as an argument and returns the value. The Proc behaves like #get (when the key is missing, it returns nil or result of the default proc).
901 902 903 |
# File 'lib/erlang/map.rb', line 901 def to_proc return lambda { |key| get(key) } end |
#update_in(*key_path) {|value| ... } ⇒ Map
Return a new Map with a deeply nested value modified to the result of
the given code block. When traversing the nested Mapes and Tuples,
non-existing keys are created with empty Map values.
The code block receives the existing value of the deeply nested key (or
nil if it doesn't exist). This is useful for "transforming" the value
associated with a certain key.
Note that the original Map and sub-Mapes and sub-Tuples are left
unmodified; new data structure copies are created along the path wherever
needed.
|
|
# File 'lib/erlang/map.rb', line 334
|
#value?(value) ⇒ Boolean Also known as: has_value?
Return true if this Map has one or more keys which map to the provided value.
218 219 220 221 222 |
# File 'lib/erlang/map.rb', line 218 def value?(value) value = Erlang.from(value) each { |k,v| return true if value == v } return false end |
#values ⇒ List
Return a new List populated with the values from this Map.
686 687 688 |
# File 'lib/erlang/map.rb', line 686 def values return Erlang::List.from_enum(each_value.to_a.freeze) end |