Module: LazyData

Defined in:
lib/lazy_data/dict.rb,
lib/lazy_data/value.rb,
lib/lazy_data/expiry.rb,
lib/lazy_data/retries.rb,
lib/lazy_data/version.rb,
lib/lazy_data/internal_state.rb,
lib/lazy_data.rb

Overview

LazyData provides data types featuring thread-safe lazy computation.

LazyData objects are constructed with a block that can be called to compute the final value, but it is not actually called until the value is requested. Once requested, the computation takes place only once, in the first thread that requested the value. Future requests will return a cached value. Furthermore, any other threads that request the value during the initial computation will block until the first thread has completed the computation.

  • Value holds a single value
  • Dict holds a dictionary of values, where each key points to a separate lazy value

This implementation also provides retry and expiration features. The code was extracted from the google-cloud-env gem that originally used it.

Defined Under Namespace

Classes: Dict, InternalState, Retries, Value

Constant Summary collapse

VERSION =

Current version of lazy_data

Returns:

  • (String)
"0.1.0"

Class Method Summary collapse

Class Method Details

.dict(retries: nil, lifetime: nil, &block) ⇒ Object

Create a LazyData::Dict.

You must pass a block that will be called to compute the value the first time it is accessed. The block takes the key as an argument and should evaluate to the value for that key, or raise an exception on error. To specify a value that expires, use expiring_value. To raise an exception that expires, use raise_expiring_error.

You can optionally pass a retry manager, which controls how subsequent accesses might try calling the block again if a compute attempt fails with an exception. A retry manager should either be an instance of Retries or an object that duck types it.

Parameters:

  • retries (Retries, Proc) (defaults to: nil)

    A retry manager. The default is a retry manager that tries only once. You can provide either a static retry manager or a Proc that returns a retry manager.

  • lifetime (Numeric, nil) (defaults to: nil)

    The default lifetime of a computed value. Optional. No expiration by default if not provided. This can be overridden in the block by returning expiring_value or calling raise_expiring_error explicitly.

  • block (Proc)

    A block that can be called to attempt to compute the value given the key.



94
95
96
# File 'lib/lazy_data.rb', line 94

def dict(retries: nil, lifetime: nil, &block)
  LazyData::Dict.new(retries: retries, lifetime: lifetime, &block)
end

.expiring_value(lifetime, value) ⇒ Object

Creates a special object that can be returned from a computation to indicate that a value expires after the given number of seconds. Any access after the expiration will cause a recomputation.

Parameters:

  • lifetime (Numeric, nil)

    timeout in seconds, or nil to explicitly disable expiration

  • value (Object)

    the computation result



32
33
34
35
# File 'lib/lazy_data/expiry.rb', line 32

def expiring_value(lifetime, value)
  return value unless lifetime
  ExpiringValue.new(lifetime, value)
end

.raise_expiring_error(lifetime, error, *args) ⇒ Object

Raise an error that, if it is the final result (i.e. retries have been exhausted), will expire after the given number of seconds. Any access after the expiration will cause a recomputation. If retries will not have been exhausted, expiration is ignored.

The error can be specified as an exception object, a string (in which case a RuntimeError will be raised), or a class that descends from Exception (in which case an error of that type will be created, and passed any additional args given).

Parameters:

  • lifetime (Numeric, nil)

    timeout in seconds, or nil to explicitly disable expiration

  • error (String, Exception, Class)

    the error to raise

  • args (Array)

    any arguments to pass to an error constructor

Raises:

  • (ExpiringError)


53
54
55
56
57
58
59
60
61
62
63
64
65
66
# File 'lib/lazy_data/expiry.rb', line 53

def raise_expiring_error(lifetime, error, *args)
  raise error unless lifetime
  raise ExpiringError, lifetime if error.equal?($!)
  if error.is_a?(::Class) && error.ancestors.include?(::Exception)
    error = error.new(*args)
  elsif !error.is_a?(::Exception)
    error = ::RuntimeError.new(error.to_s)
  end
  begin
    raise error
  rescue error.class
    raise ExpiringError, lifetime
  end
end

.value(retries: nil, lifetime: nil, &block) ⇒ Object

Create a LazyData::Value.

You must pass a block that will be called to compute the value the first time it is accessed. The block should evaluate to the desired value, or raise an exception on error. To specify a value that expires, use expiring_value. To raise an exception that expires, use raise_expiring_error.

You can optionally pass a retry manager, which controls how subsequent accesses might try calling the block again if a compute attempt fails with an exception. A retry manager should either be an instance of Retries or an object that duck types it.

Parameters:

  • retries (LazyData::Retries) (defaults to: nil)

    A retry manager. The default is a retry manager that tries only once.

  • lifetime (Numeric, nil) (defaults to: nil)

    The default lifetime of a computed value. Optional. No expiration by default if not provided. This can be overridden in the block by returning expiring_value or calling raise_expiring_error explicitly.

  • block (Proc)

    A block that can be called to attempt to compute the value.



66
67
68
# File 'lib/lazy_data.rb', line 66

def value(retries: nil, lifetime: nil, &block)
  LazyData::Value.new(retries: retries, lifetime: lifetime, &block)
end