Class: Farce::Abstract::LeaseMap Abstract

Inherits:
Map
  • Object
show all
Includes:
Internal::MarshalSupport::Reject
Defined in:
lib/farce/abstract/lease_map.rb,
lib/farce/integrations/active_support/duplicable.rb

Overview

This class is abstract.

Shared per-key checkout, mutation, and automatic cleanup behavior for lease maps.

ActiveSupport Integration collapse

Methods inherited from Map

#as_json, #assert_valid_keys, #to_msgpack, #to_query

Instance Method Summary collapse

Methods inherited from Map

#as_extended_json, #assoc, #bson_type, #compare_by_identity?, #deconstruct_keys, #dig, #empty?, #fetch_values, #has_key?, #key, #length, #rassoc, #store, #to_bson, #to_bson_normalized_value, #to_cbor, #to_hash, #to_json, #to_s, #value?, #values_at, #weak_keys?, #weak_values?

Constructor Details

#initialize(normalize_keys: nil) { ... } ⇒ LeaseMap

Construct a lease map from a block returning key/value entries.

Parameters:

  • normalize_keys (Symbol, Proc, Hash, Farce::Abstract::Map, nil) (defaults to: nil) —

    Converts incoming keys to their canonical stored form:

    • If a Symbol is provided, it will be used as a method name to call on each key.
    • If a Proc is provided, it will be called with each key and should return the normalized key.
    • If a Hash or Map is provided, it will be used to look up the normalized key for each incoming key.

Yields:

  • builds the initial key and resource mapping

Yield Returns:

Raises:

  • (ArgumentError)


15
16
17
18
19
20
21
22
23
24
25
26
# File 'lib/farce/abstract/lease_map.rb', line 15

def initialize(normalize_keys: nil)
  raise ArgumentError, "a resource constructor block is required" unless block_given?

  normalizer = Internal::KeyNormalizer.build(
    normalize_keys,
    shareable: Internal::KeyNormalizer.shareable_target?(self),
  )
  Internal::KeyNormalizer.install(self, normalizer, Internal::KeyNormalizer::LeaseOperations)
  mapping = prepare_initial_resources(yield, normalizer)
  @lease_map = new_internal_lease_map(mapping)
  super()
end

Instance Method Details

#[](key) ⇒ BasicObject

Read an owned resource or acquire it through the active automatic scope.



86
# File 'lib/farce/abstract/lease_map.rb', line 86

def [](key) = internal_lease_map.read_entry(key).last

#[]=(key, resource) ⇒ BasicObject?

Insert or replace a resource. Assigning nil deletes the entry. Assignment waits for another owner. An assignment to an explicitly owned entry replaces its held resource without ending the checkout. Assignment is invalid during a checkout block or an iteration yield.

Returns:

  • (BasicObject, nil) —

    the supplied resource, or the deleted resource

Raises:

  • (ArgumentError) —

    if the resource is boolean



110
111
112
# File 'lib/farce/abstract/lease_map.rb', line 110

def []=(key, resource)
  internal_lease_map.store(key, resource)
end

#auto_lease { ... } ⇒ BasicObject

Keep resources acquired by reads checked out until the block exits. Checkouts already owned before the scope remain owned afterward. Nested scopes return only the resources they acquire, including on exceptions and early returns.

Examples:

Nesting automatic checkout scopes

map = Farce::LeaseMap.new { { a: [], b: [] } }
map.auto_lease do
  map[:a]       # Held by the outer scope

  map.auto_lease do
    map[:a]     # Reuses the outer checkout
    map[:b]     # Held by the inner scope
  end           # Checks in b only

  map[:b]       # Acquires b again for the outer scope
end             # Checks in a and b

Yields:

  • the automatic checkout scope

Returns:

  • (BasicObject) —

    the block result



83
# File 'lib/farce/abstract/lease_map.rb', line 83

def auto_lease(&) = internal_lease_map.auto_lease(&)

#available?(key) ⇒ Boolean

Returns whether the key's resource is available.

Returns:

  • (Boolean) —

    whether the key's resource is available



140
# File 'lib/farce/abstract/lease_map.rb', line 140

def available?(key) = internal_lease_map.available?(key)

#checked_out?(key) ⇒ Boolean

Returns whether the key's resource is checked out.

Returns:

  • (Boolean) —

    whether the key's resource is checked out



143
# File 'lib/farce/abstract/lease_map.rb', line 143

def checked_out?(key) = internal_lease_map.checked_out?(key)

#checkin(key, resource) ⇒ self

Return an explicitly checked-out resource, replace it, or delete it with nil.

Parameters:

  • key (BasicObject) —

    the checked-out key

  • resource (BasicObject, nil) —

    the replacement, or nil to delete the entry

Returns:

  • (self)

Raises:

  • (Farce::OwnershipError) —

    unless the current Fiber owns an explicit checkout

  • (ArgumentError) —

    if the replacement is boolean



55
# File 'lib/farce/abstract/lease_map.rb', line 55

def checkin(key, resource) = checkin_canonical(key, resource, missing_key: key)

#checkout(key, timeout: nil) {|resource| ... } ⇒ BasicObject

Acquire one key's resource, waiting until it is available.

Parameters:

  • key (BasicObject) —

    the key to acquire

  • timeout (Numeric, nil) (defaults to: nil) —

    maximum seconds to wait

Yield Parameters:

  • resource (BasicObject) —

    the acquired resource

Returns:

  • (BasicObject) —

    the resource without a block, or the block result

Raises:

  • (KeyError) —

    if the key is absent or its entry is deleted while waiting

  • (Farce::TimeoutError) —

    if the timeout expires



40
# File 'lib/farce/abstract/lease_map.rb', line 40

def checkout(key, timeout: nil, &) = checkout_canonical(key, missing_key: key, timeout:, &)

#clear ⇒ self

Delete each entry captured when clearing begins. Entries concurrently reinserted under the same key are preserved.

Returns:

  • (self)


134
135
136
137
# File 'lib/farce/abstract/lease_map.rb', line 134

def clear
  internal_lease_map.clear
  self
end

#compare_keys_by_identity? ⇒ Boolean

LeaseMap keys use equality and values use Lease identity.

Returns:

  • (Boolean)


161
# File 'lib/farce/abstract/lease_map.rb', line 161

def compare_keys_by_identity? = internal_lease_map.compare_keys_by_identity?

#compare_values_by_identity? ⇒ Boolean

Returns:

  • (Boolean)


162
# File 'lib/farce/abstract/lease_map.rb', line 162

def compare_values_by_identity? = internal_lease_map.compare_values_by_identity?

#delete(key) ⇒ BasicObject?

Delete a key after acquiring and retiring its Lease.

Returns:

  • (BasicObject, nil) —

    the removed resource, or nil if absent



129
# File 'lib/farce/abstract/lease_map.rb', line 129

def delete(key) = internal_lease_map.delete(key)

#duplicable? ⇒ Boolean

Note:

This methods is only available if ActiveSupport has been loaded.

Returns false.

Returns:

  • (Boolean) —

    false



49
# File 'lib/farce/integrations/active_support/duplicable.rb', line 49

def duplicable? = false

#each(&block) ⇒ BasicObject Also known as: each_pair

Iterate while leasing only the entry currently being yielded.



169
170
171
172
173
174
# File 'lib/farce/abstract/lease_map.rb', line 169

def each(&block)
  return enum_for(__callee__) { size } unless block

  internal_lease_map.each(&block)
  self
end

#each_key(&block) ⇒ BasicObject

Iterate over a snapshot of current keys without leasing their resources.



178
179
180
181
182
183
# File 'lib/farce/abstract/lease_map.rb', line 178

def each_key(&block)
  return enum_for(__callee__) { size } unless block

  internal_lease_map.each_key(&block)
  self
end

#each_value(&block) ⇒ BasicObject

Iterate while leasing only the value currently being yielded.



186
187
188
189
190
191
# File 'lib/farce/abstract/lease_map.rb', line 186

def each_value(&block)
  return enum_for(__callee__) { size } unless block

  internal_lease_map.each_value(&block)
  self
end

#fetch(key) ⇒ BasicObject #fetch(key, default) ⇒ BasicObject #fetch(key) {|key| ... } ⇒ BasicObject

This method is abstract.

Fetch the value associated with a key, using the same missing-key behavior as Hash#fetch. If both a default and a block are provided, the block takes precedence and a warning is emitted.

Overloads:

  • #fetch(key) ⇒ BasicObject

    Returns The associated value.

    Parameters:

    • key (BasicObject) —

      The key to look up.

    Returns:

    • (BasicObject) —

      The associated value.

    Raises:

    • (KeyError) —

      If the key is absent.

  • #fetch(key, default) ⇒ BasicObject

    Returns The associated value or default.

    Parameters:

    • key (BasicObject) —

      The key to look up.

    • default (BasicObject) —

      The value to return if the key is absent.

    Returns:

    • (BasicObject) —

      The associated value or default.

  • #fetch(key) {|key| ... } ⇒ BasicObject

    Returns The associated value or the block result.

    Parameters:

    • key (BasicObject) —

      The key to look up.

    Yields:

    • (key) —

      Called if the key is absent.

    Yield Parameters:

    • key (BasicObject) —

      The missing key.

    Yield Returns:

    • (BasicObject) —

      The value to return.

    Returns:

    • (BasicObject) —

      The associated value or the block result.

Raises:

  • (KeyError)


89
90
91
92
93
94
95
96
97
98
99
100
101
102
# File 'lib/farce/abstract/lease_map.rb', line 89

def fetch(*arguments)
  unless arguments.length.between?(1, 2)
    raise ArgumentError, "wrong number of arguments (given #{arguments.length}, expected 1..2)"
  end

  key, default = arguments
  warn "block supersedes default value argument", uplevel: 1 if block_given? && arguments.length == 2
  present, value = internal_lease_map.read_entry(key)
  return value if present
  return yield(key) if block_given?
  return default if arguments.length == 2

  raise KeyError.new("key not found: #{key.inspect}", receiver: self, key:)
end

#getkey(key) ⇒ BasicObject?

This method is abstract.

Return the stored key that matches a lookup key.

Parameters:

  • key (BasicObject) —

    The key to match.

Returns:

  • (BasicObject, nil) —

    The matching stored key, or nil if no key matches.



152
# File 'lib/farce/abstract/lease_map.rb', line 152

def getkey(key) = internal_lease_map.getkey(key)

#key?(key) ⇒ Boolean

This method is abstract.

Test whether a key is present, including when its associated value is nil.

Parameters:

  • key (BasicObject) —

    The key to look up.

Returns:

  • (Boolean) —

    Whether the key is present.



149
# File 'lib/farce/abstract/lease_map.rb', line 149

def key?(key) = internal_lease_map.key?(key)

#keys ⇒ Array<BasicObject>

This method is abstract.

Return the keys currently stored in the map. The returned keys are not guaranteed to be in insertion order.

Returns:

  • (Array<BasicObject>) —

    A new array containing the stored keys.



158
# File 'lib/farce/abstract/lease_map.rb', line 158

def keys = internal_lease_map.keys

#lease_for(key) ⇒ Farce::Abstract::Lease

Return the Lease attached to a key's current entry. A retained handle becomes retired when its entry is deleted.

Parameters:

  • key (BasicObject) —

    the key to look up

Returns:

Raises:

  • (KeyError) —

    if the key is absent



62
# File 'lib/farce/abstract/lease_map.rb', line 62

def lease_for(key) = lease_for_canonical(key, missing_key: key)

#owned?(key) ⇒ Boolean

Returns whether the current Fiber owns the key's checkout.

Returns:

  • (Boolean) —

    whether the current Fiber owns the key's checkout



146
# File 'lib/farce/abstract/lease_map.rb', line 146

def owned?(key) = internal_lease_map.owned?(key)

#shareable_keys? ⇒ Boolean

Top-level keys must be shareable. Managed resources may be unshareable.

Returns:

  • (Boolean)


165
# File 'lib/farce/abstract/lease_map.rb', line 165

def shareable_keys? = true

#shareable_values? ⇒ Boolean

Returns:

  • (Boolean)


166
# File 'lib/farce/abstract/lease_map.rb', line 166

def shareable_values? = false

#size ⇒ Integer

This method is abstract.

Return the number of entries currently in the map.

Returns:

  • (Integer) —

    The number of entries.



155
# File 'lib/farce/abstract/lease_map.rb', line 155

def size = internal_lease_map.size

#store_if_absent(key) { ... } ⇒ BasicObject

Read an owned resource or construct an absent resource in an automatic scope. Constructors for the same key run one at a time, outside the map lock. Missing-key assignments wait for construction. Deletion and clear only affect published entries and do not cancel a pending constructor.

Parameters:

  • key (BasicObject) —

    the key to read or initialize

Yields:

  • builds the missing resource without arguments

Yield Returns:

  • (BasicObject) —

    a resource other than nil or a boolean

Returns:

  • (BasicObject) —

    the existing or newly constructed resource

Raises:

  • (LocalJumpError) —

    if no block is given

  • (Farce::OwnershipError) —

    if reading requires ownership or creation lacks an automatic scope

  • (ArgumentError) —

    if the constructor returns nil or a boolean



125
# File 'lib/farce/abstract/lease_map.rb', line 125

def store_if_absent(key, &) = internal_lease_map.store_if_absent(key, &)

#to_a ⇒ Array<Array(BasicObject, Farce::Abstract::Lease)>

Return key and Lease handle pairs. Unlike iteration, this method never checks resources out.

Returns:



196
# File 'lib/farce/abstract/lease_map.rb', line 196

def to_a = internal_lease_map.handles

#to_h ⇒ Hash{BasicObject => Farce::Abstract::Lease}

Return a key to Lease handle mapping. Unlike iteration, this method never checks resources out. A block receives each key and Lease handle and returns a pair for the new Hash.

Returns:



202
# File 'lib/farce/abstract/lease_map.rb', line 202

def to_h(&) = entries_to_hash(to_a, &)

#try_checkout(key) {|resource| ... } ⇒ BasicObject?

Acquire one key's resource immediately if it is available.

Parameters:

  • key (BasicObject) —

    the key to acquire

Yield Parameters:

  • resource (BasicObject) —

    the acquired resource

Returns:

  • (BasicObject, nil) —

    the resource or block result, or nil when unavailable

Raises:

  • (KeyError) —

    if the key is absent



47
# File 'lib/farce/abstract/lease_map.rb', line 47

def try_checkout(key, &) = try_checkout_canonical(key, missing_key: key, &)

#values ⇒ Array<Farce::Abstract::Lease>

Return the current Lease handles.

Returns:



206
# File 'lib/farce/abstract/lease_map.rb', line 206

def values = to_h.values