Class: GenevaDrive::SignalMatcher

Inherits:
Object
  • Object
show all
Defined in:
lib/geneva_drive/signal_matcher.rb

Overview

Decides whether a given Signal is the one a step is waiting for. A matcher is a plain object, so it can live in a constant and be shared between steps and workflows.

Name equality is the whole predicate unless a block is given; the block receives the (indifferent-access) payload and is +instance_exec+'d on the signal's workflow, so hero and the workflow's own methods are in scope.

Anything else responding to #matches?(signal) works just as well in wait_for: - a custom matcher owns its whole predicate and can, for instance, accept either of two signal names.

Matchers run both at the gate (the waiting step's own job) and at dispatch (inside signal!, in the sender's process). They must be cheap and free of side effects, the same expectation skip_if: carries.

Examples:

Name only (what wait_for: :payment_confirmed builds for you)

GenevaDrive::SignalMatcher.new(:payment_confirmed)

Narrowed by payload

GenevaDrive::SignalMatcher.new(:document_signed) do |payload|
  payload[:document_id] == hero.contract_id
end

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(name) {|payload| ... } ⇒ SignalMatcher

Returns a new instance of SignalMatcher.

Parameters:

  • name (String, Symbol) —

    signal name for equality matching

Yields:

  • (payload) —

    optional payload predicate, instance_exec'd on the workflow

Raises:

  • (ArgumentError) —

    if the name is blank



36
37
38
39
40
41
# File 'lib/geneva_drive/signal_matcher.rb', line 36

def initialize(name, &condition)
  raise ArgumentError, "GenevaDrive::SignalMatcher needs a signal name" if name.blank?

  @name = name.to_s
  @condition = condition
end

Instance Attribute Details

#condition ⇒ Proc? (readonly)

Returns the payload predicate, if any.

Returns:

  • (Proc, nil) —

    the payload predicate, if any



31
32
33
# File 'lib/geneva_drive/signal_matcher.rb', line 31

def condition
  @condition
end

#name ⇒ String (readonly)

Returns the signal name this matcher accepts.

Returns:

  • (String) —

    the signal name this matcher accepts



28
29
30
# File 'lib/geneva_drive/signal_matcher.rb', line 28

def name
  @name
end

Instance Method Details

#matches?(signal) ⇒ Boolean

Whether the signal is the one being waited for.

Parameters:

Returns:

  • (Boolean)


47
48
49
50
51
52
# File 'lib/geneva_drive/signal_matcher.rb', line 47

def matches?(signal)
  return false unless signal.name == @name
  return true unless @condition

  !!signal.workflow.instance_exec(signal.payload, &@condition)
end

#to_s ⇒ String

Human-readable description, used in log lines and test helper messages.

Returns:

  • (String)


57
58
59
# File 'lib/geneva_drive/signal_matcher.rb', line 57

def to_s
  @condition ? "#{@name} (narrowed by payload)" : @name
end