ExActor.Operations
Macros that can be used for simpler definition of GenServer
operations such as casts or calls.
Summary
defabcast(req_def, options \\ [], body \\ []) | Defines an abcast operation |
defabcastp(req_def, options \\ [], body \\ []) | Same as |
defcall(req_def, options \\ [], body \\ []) | Defines the call callback clause and the corresponding interface fun |
defcallp(req_def, options \\ [], body \\ []) | Same as |
defcast(req_def, options \\ [], body \\ []) | Defines the cast callback clause and the corresponding interface fun |
defcastp(req_def, options \\ [], body \\ []) | Same as |
defhandlecall(req_def, options \\ [], body \\ []) | Similar to |
defhandlecast(req_def, options \\ [], body \\ []) | Similar to |
defhandleinfo(msg, opts \\ [], body) | Defines the info callback clause. Responses work just like with casts |
definit(arg \\ {:_, [], ExActor.Operations}, opts) | Similar to |
defmulticall(req_def, options \\ [], body \\ []) | Defines a multicall operation |
defmulticallp(req_def, options \\ [], body \\ []) | Same as |
defstart(arg1, opts \\ [], body \\ []) | Defines the starter function and initializer body |
defstartp(arg1, options \\ [], body \\ []) | Same as |
Macros
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
Same as defabcast/3
but the interface function is private.
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, ...}
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: ...
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
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: ...
Similar to defcall/3
, but generates just the handle_call
clause, without creating the interface function.
Similar to defcast/3
, but generates just the handle_call
clause, without creating the interface function.
Defines the info callback clause. Responses work just like with casts.
Examples:
defhandleinfo :some_message, do: ...
defhandleinfo :another_message, state: ..., do:
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}
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
.
Same as defmulticall/3
but the interface function is private.
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 usingExActor
, 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 theinit/1
.
Request format (arg passed to init/1
):
- no arguments ->
nil
- one arguments ->
{x}
- more arguments ->
{x, y, ...}
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