Class: Functional::Delay
- Inherits:
-
Synchronization::Object
- Object
- Synchronization::Object
- Functional::Delay
- Defined in:
- lib/functional/delay.rb
Overview
This is a write-once, read-many, thread safe object that can be used in concurrent systems. Thread safety guarantees cannot be made about objects contained within this object, however. Ruby variables are mutable references to mutable objects. This cannot be changed. The best practice it to only encapsulate immutable, frozen, or thread safe objects. Ultimately, thread safety is the responsibility of the programmer.
Lazy evaluation of a block yielding an immutable result. Useful for expensive operations that may never be needed.
When a Delay
is created its state is set to pending
. The value and
reason are both nil
. The first time the #value
method is called the
enclosed opration will be run and the calling thread will block. Other
threads attempting to call #value
will block as well. Once the operation
is complete the value will be set to the result of the operation or the
reason will be set to the raised exception, as appropriate. All threads
blocked on #value
will return. Subsequent calls to #value
will
immediately return the cached value. The operation will only be run once.
This means that any side effects created by the operation will only happen
once as well.
Instance Method Summary collapse
-
#fulfilled? ⇒ Boolean
(also: #value?)
Has the delay been fulfilled?.
-
#initialize { ... } ⇒ Delay
constructor
Create a new
Delay
in the:pending
state. -
#pending? ⇒ Boolean
Is delay completion still pending?.
-
#reason ⇒ StandardError
The exception raised when processing the block.
-
#rejected? ⇒ Boolean
(also: #reason?)
Has the delay been rejected?.
-
#state ⇒ Symbol
Current state of block processing.
-
#value ⇒ Object
Return the (possibly memoized) value of the delayed operation.
Constructor Details
#initialize { ... } ⇒ Delay
Create a new Delay
in the :pending
state.
37 38 39 40 41 42 43 44 |
# File 'lib/functional/delay.rb', line 37 def initialize(&block) raise ArgumentError.new('no block given') unless block_given? super synchronize do @state = :pending @task = block end end |
Instance Method Details
#fulfilled? ⇒ Boolean Also known as: value?
Has the delay been fulfilled?
81 82 83 |
# File 'lib/functional/delay.rb', line 81 def fulfilled? synchronize{ @state == :fulfilled } end |
#pending? ⇒ Boolean
Is delay completion still pending?
95 96 97 |
# File 'lib/functional/delay.rb', line 95 def pending? synchronize{ @state == :pending } end |
#reason ⇒ StandardError
The exception raised when processing the block. Returns nil
if the
operation is still :pending
or has been :fulfilled
.
58 59 60 |
# File 'lib/functional/delay.rb', line 58 def reason synchronize{ @reason } end |
#rejected? ⇒ Boolean Also known as: reason?
Has the delay been rejected?
88 89 90 |
# File 'lib/functional/delay.rb', line 88 def rejected? synchronize{ @state == :rejected } end |
#state ⇒ Symbol
Current state of block processing.
49 50 51 |
# File 'lib/functional/delay.rb', line 49 def state synchronize{ @state } end |
#value ⇒ Object
Return the (possibly memoized) value of the delayed operation.
If the state is :pending
then the calling thread will block while the
operation is performed. All other threads simultaneously calling #value
will block as well. Once the operation is complete (either :fulfilled
or
:rejected
) all waiting threads will unblock and the new value will be
returned.
If the state is not :pending
when #value
is called the (possibly
memoized) value will be returned without blocking and without performing
the operation again.
75 76 77 |
# File 'lib/functional/delay.rb', line 75 def value synchronize{ execute_task_once } end |