Module: Farce::Abstract::DuplicableMap
- Included in:
- BoundedMap, ConcurrentMap, TreeMap
- Defined in:
- lib/farce/abstract/duplicable_map.rb,
lib/farce/integrations/active_support/map.rb,
lib/farce/integrations/active_support/duplicable.rb
Overview
Map operations that return independent maps of the same kind. Include this in subclasses of Map that support copying. Operations work on an independent copy, not an atomic snapshot of the source. Local copies transform the current scope and retain constructor defaults for other scopes.
ActiveSupport Integration collapse
-
#compact_blank ⇒ Map
Return a same-kind map without blank values, including false.
-
#deep_dup ⇒ Map
Deeply copy entries into a map of the same kind with the same settings.
-
#duplicable? ⇒ Boolean
True.
-
#reverse_merge(other) ⇒ Map
(also: #with_defaults)
Return a same-kind map with defaults applied before the receiver's entries.
-
#stringify_keys ⇒ Map
Return a same-kind map with string keys, subject to its key normalizer.
-
#symbolize_keys ⇒ Map
(also: #to_options)
Return a same-kind map with symbol keys where conversion succeeds.
-
#with_indifferent_access ⇒ Map
Return a new map of the same class with interchangeable Symbol and String keys.
Instance Method Summary collapse
-
#compact ⇒ Map
Return an independent map without entries whose value is nil.
-
#except(*keys) ⇒ Map
Return an independent map without the requested keys.
-
#flatten(level = 1) ⇒ Array
Return keys and values in a flattened Array.
-
#invert ⇒ Map
Return an independent map with keys and values exchanged.
-
#merge(*others) {|key, old_value, new_value| ... } ⇒ Map
Return an independent map with entries from each input applied in order.
-
#reject {|key, value| ... } ⇒ Map, Enumerator
Return an independent map excluding entries accepted by the block.
-
#select {|key, value| ... } ⇒ Map, Enumerator
(also: #filter)
Return an independent map containing entries accepted by the block.
-
#slice(*keys) ⇒ Map
Return an independent map containing only the requested keys that exist.
-
#to_proc ⇒ Proc
Return a lambda that looks up a key using this map's current contents and lookup rules.
-
#transform_keys(mapping = UNDEFINED) {|key| ... } ⇒ Map, Enumerator
Return an independent map with transformed keys and unchanged stored values.
-
#transform_values {|value| ... } ⇒ Map, Enumerator
Return an independent map with transformed values and unchanged keys.
Instance Method Details
#compact ⇒ Map
Return an independent map without entries whose value is nil. False values are retained.
38 39 40 41 42 43 |
# File 'lib/farce/abstract/duplicable_map.rb', line 38 def compact with_map_copy do |copy, map| nil_value = copy.wrap_value(nil) map.each { |key, value| map.delete(key) if nil_value.equal?(value) } end end |
#compact_blank ⇒ Map
This methods is only available if ActiveSupport has been loaded.
Return a same-kind map without blank values, including false.
88 |
# File 'lib/farce/integrations/active_support/map.rb', line 88 def compact_blank = reject { |_, value| value.blank? } |
#deep_dup ⇒ Map
This methods is only available if ActiveSupport has been loaded.
Deeply copy entries into a map of the same kind with the same settings. String and Symbol keys retain their identity, as with ActiveSupport's Hash#deep_dup. Copied keys and values must satisfy the map's normal storage rules.
56 57 58 59 60 61 62 63 64 65 66 |
# File 'lib/farce/integrations/active_support/map.rb', line 56 def deep_dup copier = ModeManager.new(mode: :copy) if respond_to?(:mode) && mode == :move with_map_copy(empty: true) do |copy, map| internal_map.each do |key, value| key = key.deep_dup unless String === key || Symbol === key value = unwrap_value(value).deep_dup value = copier.unwrap(copier.wrap(value)) if copier map[key] = copy.wrap_value(value) end end end |
#duplicable? ⇒ Boolean
This methods is only available if ActiveSupport has been loaded.
Returns true.
55 |
# File 'lib/farce/integrations/active_support/duplicable.rb', line 55 def duplicable? = true |
#except(*keys) ⇒ Map
Return an independent map without the requested keys.
30 31 32 33 34 |
# File 'lib/farce/abstract/duplicable_map.rb', line 30 def except(*keys) with_map_copy do |_, map| keys.each { map.delete(normalize_copied_key(it)) } end end |
#flatten(level = 1) ⇒ Array
Return keys and values in a flattened Array. The default depth flattens entry pairs. Zero preserves pairs, and negative depths flatten all levels.
170 171 172 173 |
# File 'lib/farce/abstract/duplicable_map.rb', line 170 def flatten(level = 1) level = Integer.try_convert(level) || raise(TypeError, "level must be an Integer or respond to #to_int") to_a.flatten(level) end |
#invert ⇒ Map
Return an independent map with keys and values exchanged. New keys follow the map's normal key normalization and shareability rules. On collisions, the last visited entry wins. Bounded copies rebuild eviction history.
121 122 123 124 125 126 127 128 129 |
# File 'lib/farce/abstract/duplicable_map.rb', line 121 def invert copier = ModeManager.new(mode: :copy) if respond_to?(:mode) && mode == :move empty_copy.tap do |copy| each_pair do |key, value| key = copier.unwrap(copier.wrap(key)) if copier copy[value] = key end end end |
#merge(*others) {|key, old_value, new_value| ... } ⇒ Map
Return an independent map with entries from each input applied in order. Incoming keys pass through the normalizer. A block resolves collisions using the canonical key. Move-mode values are copied before transfer to preserve the source and inputs. Bounded copies retain eviction history and apply their usual capacity limits to new writes.
141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 |
# File 'lib/farce/abstract/duplicable_map.rb', line 141 def merge(*others) copier = ModeManager.new(mode: :copy) if respond_to?(:mode) && mode == :move with_map_copy do |copy, map| others.each do |other| unless Map === other other = Hash.try_convert(other) || raise(TypeError, "input must be a Map, Hash, or respond to #to_hash") end other.each_pair do |key, value| key = normalize_copied_key(key) value = yield(key, copy.unwrap_value(map[key]), value) if block_given? && map.key?(key) value = copier.unwrap(copier.wrap(value)) if copier map[key] = copy.wrap_value(value) end end end end |
#reject {|key, value| ... } ⇒ Map, Enumerator
Return an independent map excluding entries accepted by the block. The block receives public values from the copy. Stored values and map settings are preserved.
63 64 65 66 67 68 |
# File 'lib/farce/abstract/duplicable_map.rb', line 63 def reject return enum_for(__method__) { size } unless block_given? with_map_copy do |copy, map| map.each { |key, value| map.delete(key) if yield(key, copy.unwrap_value(value)) } end end |
#reverse_merge(other) ⇒ Map Also known as: with_defaults
This methods is only available if ActiveSupport has been loaded.
Return a same-kind map with defaults applied before the receiver's entries. Existing entries win. Bounded copies rebuild eviction history and enforce their capacity. Move-mode defaults are copied so the input remains usable.
96 97 98 99 100 101 102 103 104 105 106 107 108 109 |
# File 'lib/farce/integrations/active_support/map.rb', line 96 def reverse_merge(other) unless Map === other other = Hash.try_convert(other) || raise(TypeError, "input must be a Map, Hash, or respond to #to_hash") end copier = ModeManager.new(mode: :copy) if respond_to?(:mode) && mode == :move with_map_copy(empty: true) do |copy, map| other.each_pair do |key, value| key = normalize_copied_key(key) value = copier.unwrap(copier.wrap(value)) if copier map[key] = copy.wrap_value(value) end internal_map.each { |key, value| map[key] = value } end end |
#select {|key, value| ... } ⇒ Map, Enumerator Also known as: filter
Return an independent map containing entries accepted by the block. The block receives public values from the copy. Stored values and map settings are preserved.
50 51 52 53 54 55 |
# File 'lib/farce/abstract/duplicable_map.rb', line 50 def select return enum_for(__method__) { size } unless block_given? with_map_copy do |copy, map| map.each { |key, value| map.delete(key) unless yield(key, copy.unwrap_value(value)) } end end |
#slice(*keys) ⇒ Map
Return an independent map containing only the requested keys that exist.
15 16 17 18 19 20 21 22 23 24 25 |
# File 'lib/farce/abstract/duplicable_map.rb', line 15 def slice(*keys) with_map_copy do |_, map| retained = {}.compare_by_identity keys.each do |key| key = normalize_copied_key(key) retained[map.getkey(key)] = true if map.key?(key) end # Tree backends expose each, but not each_key. map.each { |key, _| map.delete(key) unless retained.key?(key) } # rubocop:disable Style/HashEachMethods end end |
#stringify_keys ⇒ Map
This methods is only available if ActiveSupport has been loaded.
Return a same-kind map with string keys, subject to its key normalizer.
71 |
# File 'lib/farce/integrations/active_support/map.rb', line 71 def stringify_keys = transform_keys { |key| Symbol === key ? key.name : key.to_s } |
#symbolize_keys ⇒ Map Also known as: to_options
This methods is only available if ActiveSupport has been loaded.
Return a same-kind map with symbol keys where conversion succeeds.
76 77 78 79 80 81 82 |
# File 'lib/farce/integrations/active_support/map.rb', line 76 def symbolize_keys transform_keys do |key| key.to_sym rescue StandardError key end end |
#to_proc ⇒ Proc
Return a lambda that looks up a key using this map's current contents and lookup rules. The lambda is Ractor-shareable when this map is Ractor-shareable.
161 162 163 164 |
# File 'lib/farce/abstract/duplicable_map.rb', line 161 def to_proc lookup = ->(key) { self[key] } Ractor.shareable?(self) ? Ractor.shareable_lambda(self: self, &lookup) : lookup end |
#transform_keys(mapping = UNDEFINED) {|key| ... } ⇒ Map, Enumerator
Return an independent map with transformed keys and unchanged stored values. Mapping entries take precedence over the block. Unmapped keys are retained when no block is given. Transformed keys pass through this map's normalizer. On collisions, the last visited entry wins. Bounded copies rebuild eviction history as transformed entries are inserted.
78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 |
# File 'lib/farce/abstract/duplicable_map.rb', line 78 def transform_keys(mapping = UNDEFINED) if UNDEFINED.equal?(mapping) return enum_for(__method__, mapping) { size } unless block_given? mapping = nil else mapping = Hash.try_convert(mapping) || raise(TypeError, "mapping must be a Hash or respond to #to_hash") end with_map_copy(empty: true) do |_, map| internal_map.each do |key, value| if mapping&.key?(key) key = normalize_copied_key(mapping.fetch(key)) elsif block_given? key = normalize_copied_key(yield(key)) end map[key] = value end end end |
#transform_values {|value| ... } ⇒ Map, Enumerator
Return an independent map with transformed values and unchanged keys. Results follow the map's transfer mode. Move-mode results are copied before transfer to preserve the source. Bounded copies count replacements as writes. The source's eviction history is unchanged.
104 105 106 107 108 109 110 111 112 113 114 |
# File 'lib/farce/abstract/duplicable_map.rb', line 104 def transform_values return enum_for(__method__) { size } unless block_given? copier = ModeManager.new(mode: :copy) if respond_to?(:mode) && mode == :move with_map_copy do |copy, map| map.each do |key, value| value = yield copy.unwrap_value(value) value = copier.unwrap(copier.wrap(value)) if copier map[key] = copy.wrap_value(value) end end end |
#with_indifferent_access ⇒ Map
This methods is only available if ActiveSupport has been loaded.
Return a new map of the same class with interchangeable Symbol and String keys. Other key types and nested hashes are not normalized. Existing normalization is replaced. The copy preserves its value mode, value comparison, capacity, and Local scope where supported. Keys use equality. Entries from the current scope seed a Local copy. Values in move mode are copied to preserve the source.
46 47 48 49 |
# File 'lib/farce/integrations/active_support/map.rb', line 46 def with_indifferent_access normalizer = Ractor.shareable_proc { |key| Symbol === key ? key.name : key } build_indifferent_access(**, normalize_keys: normalizer) end |