ExActor.Operations

Macros that can be used for simpler definition of GenServer operations such as casts or calls.

Source

Summary

defabcast(req_def, options \\ [], body \\ [])

Defines an abcast operation

defabcastp(req_def, options \\ [], body \\ [])

Same as defabcast/3 but the interface function is private

defcall(req_def, options \\ [], body \\ [])

Defines the call callback clause and the corresponding interface fun

defcallp(req_def, options \\ [], body \\ [])

Same as defcall/3 but the interface function is private

defcast(req_def, options \\ [], body \\ [])

Defines the cast callback clause and the corresponding interface fun

defcastp(req_def, options \\ [], body \\ [])

Same as defcast/3 but the interface function is private

defhandlecall(req_def, options \\ [], body \\ [])

Similar to defcall/3, but generates just the handle_call clause, without creating the interface function

defhandlecast(req_def, options \\ [], body \\ [])

Similar to defcast/3, but generates just the handle_call clause, without creating the interface function

defhandleinfo(msg, opts \\ [], body)

Defines the info callback clause. Responses work just like with casts

definit(arg \\ {:_, [], ExActor.Operations}, opts)

Similar to defstart/3 but generates just the init clause

defmulticall(req_def, options \\ [], body \\ [])

Defines a multicall operation

defmulticallp(req_def, options \\ [], body \\ [])

Same as defmulticall/3 but the interface function is private

defstart(arg1, opts \\ [], body \\ [])

Defines the starter function and initializer body

defstartp(arg1, options \\ [], body \\ [])

Same as defstart/2 but the interface function is private

Macros

defabcast(req_def, options \\ [], body \\ [])

Defines an abcast operation.

Examples:

defabcast my_request(x, y), do: ...

...

# If the process is locally registered via `:export` option
MyServer.my_request(2, 3)
MyServer.my_request(nodes, 2, 3)

# The process is not locally registered via `:export` option
MyServer.my_request(:local_alias, 2, 3)
MyServer.my_request(nodes, :local_alias, 2, 3)

Request format is the same as in defcall/3

Source
defabcastp(req_def, options \\ [], body \\ [])

Same as defabcast/3 but the interface function is private.

Source
defcall(req_def, options \\ [], body \\ [])

Defines the call callback clause and the corresponding interface fun.

Examples:

defcall operation, do: reply(response)
defcall get, state: state, do: reply(state)
defcall inc, state: state, do: set_and_reply(state + 1, response)

# timeout option
defcall long_call, state: state, timeout: :timer.seconds(10), do: ...

# parameterizable timeout
# This will include the timeout argument at the end of the interface function
# arguments, so the caller may specify the timeout at runtime. Default value
# via `\\` can also be provided.
defcall long_call, timeout: some_variable, do: ...

# omitting interface fun
defcall operation, export: false, do: ...

# pattern matching
defcall a(1), do: ...
defcall a(2), do: ...
defcall a(x), state: 1, do: ...
defcall a(x), when: x > 1, do: ...
defcall a(_), do: ...

# default args
defcall a(x \ nil), do: ...

# Body-less clause - generates interface function which calls
# GenServer.call but doesn't generate the handler. You can use
# defhandlecall to generate the handler. This is useful if you
# need to pattern match on the state
defcall a(x)
defhandlecall a(x), state: state, when: state > 0, do: ...

Request format (passed to handle_call/3):

  • no arguments -> :my_request
  • one arguments -> {:my_request, x}
  • more arguments -> {:my_request, x, y, ...}
Source
defcallp(req_def, options \\ [], body \\ [])

Same as defcall/3 but the interface function is private.

Can be useful when you need to do pre/post processing in the caller process.

Examples:

def exported_interface(...) do
  # do some client side preprocessing here
  my_request(...)
  # do some client side post processing here
end

# Not available outside of this module
defcallp my_request(...), do: ...
Source
defcast(req_def, options \\ [], body \\ [])

Defines the cast callback clause and the corresponding interface fun.

Examples:

defcast operation, do: noreply
defcast inc(x), state: state, do: new_state(state + x)

# omitting interface fun
defcast operation, export: false, do: ...

# pattern matching
defcast a(1), do: ...
defcast a(2), do: ...
defcast a(x), state: 1, do: ...
defcast a(x), when: x > 1, do: ...
defcast a(_), do: ...

# default args
defcast a(x \\ nil), do: ...

# Body-less clause - generates interface function which calls
# GenServer.cast but doesn't generate the handler. You can use
# defhandlecast to generate the handler. This is useful if you
# need to pattern match on the state
defcast a(x)
defhandlecast a(x), state: state, when: state > 0, do: ...

Request format is the same as in defcall/3

Source
defcastp(req_def, options \\ [], body \\ [])

Same as defcast/3 but the interface function is private.

Can be useful when you need to do pre/post processing in the caller process.

Examples:

def exported_interface(...) do
  # do some client side preprocessing here
  my_request(...)
  # do some client side post processing here
end

# Not available outside of this module
defcastp my_request(...), do: ...
Source
defhandlecall(req_def, options \\ [], body \\ [])

Similar to defcall/3, but generates just the handle_call clause, without creating the interface function.

Source
defhandlecast(req_def, options \\ [], body \\ [])

Similar to defcast/3, but generates just the handle_call clause, without creating the interface function.

Source
defhandleinfo(msg, opts \\ [], body)

Defines the info callback clause. Responses work just like with casts.

Examples:

defhandleinfo :some_message, do: ...
defhandleinfo :another_message, state: ..., do:
Source
definit(arg \\ {:_, [], ExActor.Operations}, opts)

Similar to defstart/3 but generates just the init clause.

Note: keep in mind that defstart wraps arguments in a tuple. If you want to handle defstart start(x), you need to define definit {x}

Source
defmulticall(req_def, options \\ [], body \\ [])

Defines a multicall operation.

Examples:

defmulticall my_request(x, y), do: ...

...

# If the process is locally registered via `:export` option
MyServer.my_request(2, 3)
MyServer.my_request(nodes, 2, 3)

# The process is not locally registered via `:export` option
MyServer.my_request(:local_alias, 2, 3)
MyServer.my_request(nodes, :local_alias, 2, 3)

Request format is the same as in defcall/3. Timeout option works just like with defcall/3.

Source
defmulticallp(req_def, options \\ [], body \\ [])

Same as defmulticall/3 but the interface function is private.

Source
defstart(arg1, opts \\ [], body \\ [])

Defines the starter function and initializer body.

Examples:

# defines and export start/2
defstart start(x, y) do
  # runs in init/1 callback
  initial_state(x + y)
end

# defines and export start_link/2
defstart start_link(x, y) do
  # runs in init/1 callback
  initial_state(x + y)
end

You can also provide additional GenServer options via :gen_server_opts option.

defstart start(x, y), gen_server_opts: [spawn_opts: [min_heap_size: 10000]], do: ...

If you need to set GenServer options at runtime, use gen_server_opts: :runtime and then the starter function will receive one more argument where you can pass options:

defstart start(x, y), gen_server_opts: :runtime do
  ...
end

...

MyServer.start(x, y, name: :foo, spawn_opts: [min_heap_size: 10000])

Body can be omitted. In this case, just the interface function is generated. This can be useful if you want to define both start and start_link:

defstart start(x, y)
defstart start_link(x, y) do
  # runs for both cases
end

Keep in mind that generated info/1 matches on the number of arguments, so this won't work:

defstart start_link(x)
defstart start_link(x, y) do
  # doesn't handle start_link(x)
end

If you want to handle various versions, you can just define start heads without the body, and then use defhandleinfo/2 or just implement handle_info/1.

Other notes:

  • If the export option is set while using ExActor, it will be honored in starters.
  • You can use patterns in arguments. Pattern matching is done on init/1. There will be just one interface function for the given arity.
  • You can provide additional guard via :when option. The guard applies to the init/1.

Request format (arg passed to init/1):

  • no arguments -> nil
  • one arguments -> {x}
  • more arguments -> {x, y, ...}
Source
defstartp(arg1, options \\ [], body \\ [])

Same as defstart/2 but the interface function is private.

Can be useful when you need to do pre/post processing in the caller process.

defmodule MyServer do
  def start_link(x, y) do
    ...

    do_start_link(x, y)

    ...
  end

  defstartp do_start_link(x, y), link: true do
    ...
  end
end
Source