Class: DeferrableGratification::Combinators::Bind
- Inherits:
-
DefaultDeferrable
- Object
- DefaultDeferrable
- DeferrableGratification::Combinators::Bind
- Defined in:
- lib/deferrable_gratification/combinators/bind.rb
Overview
Combinator that passes the result of one deferred operation to a block that uses that result to begin another deferred operation. The compound operation itself succeeds if the second operation does.
You probably want to call #bind! rather than using this class directly.
If we define Deferrable err (IO a) to be the type of a Deferrable that may perform a side effect and then either succeed with a value of type a or fail with an error of type err, then we expect the block to have type
a -> Deferrable err (IO b)
and if so this combinator (actually Bind.setup!) is a specialisation of the monadic bind operator >>=:
# example: database query that depends on the result of another
Bind.setup!(DB.query('select foo from bar')) do |result|
DB.query("select baz from quuz where name = '#{result}'")
end
# type signatures, in pseudo-Haskell
(>>=) :: Deferrable err a ->
(a -> Deferrable err b) -> Deferrable err b
Bind :: Deferrable err a ->
(a -> Deferrable err (IO b)) -> Deferrable err (IO b)
However, because Ruby doesn’t actually type-check blocks, we can’t enforce that the block really does return a second Deferrable. This therefore also supports (reasonably) arbitrary blocks. However, it’s probably clearer (though equivalent) to use #transform for this case.
Class Method Summary collapse
-
.setup!(first, options = {}, &block) ⇒ Bind
Create a Bind and register the callbacks.
Instance Method Summary collapse
-
#initialize(first, options = {}, &block) ⇒ Bind
constructor
Prepare to bind
block
tofirst
, and create the Deferrable that will represent the bind. -
#setup! ⇒ Object
Register a callback on the first Deferrable to run the bound block on success, and an errback to fail this Bind on failure.
Constructor Details
#initialize(first, options = {}, &block) ⇒ Bind
Prepare to bind block
to first
, and create the Deferrable that will represent the bind.
Does not actually set up any callbacks or errbacks: call #setup! for that.
46 47 48 49 50 51 52 53 54 55 |
# File 'lib/deferrable_gratification/combinators/bind.rb', line 46 def initialize(first, = {}, &block) @first = first @with_chaining = !.delete(:without_chaining) bad_keys = .keys.join(', ') raise "Unknown options: #{bad_keys}" unless bad_keys.empty? raise ArgumentError, 'must pass a block' unless block @proc = block end |
Class Method Details
.setup!(first, options = {}, &block) ⇒ Bind
Create a DeferrableGratification::Combinators::Bind and register the callbacks.
71 72 73 |
# File 'lib/deferrable_gratification/combinators/bind.rb', line 71 def self.setup!(first, = {}, &block) new(first, , &block).tap(&:setup!) end |
Instance Method Details
#setup! ⇒ Object
Register a callback on the first Deferrable to run the bound block on success, and an errback to fail this DeferrableGratification::Combinators::Bind on failure.
59 60 61 62 |
# File 'lib/deferrable_gratification/combinators/bind.rb', line 59 def setup! @first.callback {|*args| run_bound_proc(*args) } @first.errback {|*args| self.fail(*args) } end |