Module: Plumbing::Actor::Definitions

Defined in:
lib/plumbing/actor/definitions.rb

Defined Under Namespace

Classes: MethodDefinition

Instance Method Summary collapse

Instance Method Details

#async(name, &config) ⇒ Object

Defines three methods on the instance:

`name` - called from outside the actor, returns a message object that must be `await`ed to access the result
`_name` - runs inside the actor's context and validates the parameters before calling the implementation
`_name_implementation` - the actual implementation of the method

Validated params are passed into the returns block as keyword parameters, so declare them in the block's parameter list:

class Greeting
  include Plumbing::Actor

  def initialize(name:) = @name = name

  async :say do
    param :greeting, String, default: "Hello"
    returns { |greeting:| "#{greeting} #{@name}" }
  end
end

# Greeting has three methods - `say`, `_say` and `_say_implementation`
#   the latter two called internally within the actor's context

greeting = Greeting.new name: "Alice"
result = greeting.say greeting: "Hi there"
puts result.await # => "Hi there Alice"
# ALTERNATIVE SYNTAX
puts await { greeting.say greeting: "Hi there" }

Raises:

  • (ArgumentError)


33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
# File 'lib/plumbing/actor/definitions.rb', line 33

def async name, &config
  method = MethodDefinition.new(name: name.to_sym)
  method.instance_eval(&config)
  raise ArgumentError, "async :#{name} requires a `returns { ... }` block" if method.implementation.nil?

  # external async method
  define_method name.to_sym do |sender: nil, **params, &block|
    worker.post name.to_sym, sender: sender, **params, &block
  end

  # internal validator
  define_method :"_#{name}" do |**params, &block|
    validated = method.params_class.new(**params).to_h
    send(:"_#{name}_implementation", **validated, &block)
  end

  # internal implementation
  define_method(:"_#{name}_implementation", &method.implementation)
end