View Source Skitter.DSL.Strategy (Skitter v0.5.1)
Strategy and Hook definition DSL.
This module offers macros to define a strategy and hooks. To define a strategy, use
defstrategy/3
. Inside the strategy, defhook/2
can be used to define hooks. Inside the body
of the hook, context/0
, component/0
, strategy/0
, deployment/0
and invocation/0
can be
used to read information from the current context.
Note that it is possible to define a strategy as an elixir module which implements the
appropriate behaviour. Using defstrategy/3
instead offers three main advantages:
- The
Skitter.Strategy.context/0
of a hook is passed as an implicit argument, which can be accessed using the aforementioned macros. - The helpers defined in
Skitter.DSL.Strategy.Helpers
can be used. - A trait-like mechanism is introduced, which can be used to create new strategies based on existing ones.
Link to this section Summary
Functions
Obtain the context's arguments.
Obtain the context's component.
Obtain the context struct.
Define a hook.
Define a strategy.
Obtain the context's component.
Obtain the context's component.
Obtain the context's component.
Link to this section Functions
Obtain the context's arguments.
Obtain the context's component.
Examples
iex> defstrategy ReadComponent do
...> defhook read, do: component()
...> end
iex> ReadComponent.read(%Context{component: SomeComponent})
SomeComponent
Obtain the context struct.
A strategy hook is called with a Skitter.Strategy.context/0
as its first argument. This
macro is used to obtain this struct.
Examples
iex> defstrategy FullContext do
...> defhook read, do: context()
...> end
iex> FullContext.read(%Context{component: SomeComponent})
%Context{component: SomeComponent}
Define a hook.
This macro defines a single hook of a strategy. While a hook may be defined as a plain elixir function, using this macro offers three advantages:
The hook context is handled by the macro and can be accessed with
context/0
,component/0
,strategy/0
,deployment/0
andinvocation/0
.The macros defined in
Skitter.DSL.Strategy.Helpers
can be used, reducing the code needed to spawn workers, or call component callbacks.Other strategies can inherit this hook, making it easier to create new strategies. This is shown in the documentation of
defstrategy/3
.
Calling hooks
Hooks defined inside other strategies may be called like a normal elixir function inside the
body of a hook. When this occurs, defhook/2
automatically passes the context argument to the
hook that is called.
iex> defstrategy S1 do
...> defhook example, do: "world!"
...> end
iex> defstrategy S2 do
...> defhook example, do: "Hello, " <> S1.example()
...> end
iex> S2.example(%Context{})
"Hello, world!"
The same cannot be done when a local hook (i.e. a hook defined in the current module) is called.
Therefore, a local hook should be called with a context argument. context/0
can be used for
this:
iex> defstrategy Local do
...> defhook left, do: "Hello, "
...> defhook right, do: "world!"
...> defhook example, do: left(context()) <> right(context())
...> end
iex> Local.example(%Context{})
"Hello, world!"
A hook of a child strategy can also be called dynamically in a similar way:
iex> defstrategy Abstract do
...> defhook example, do: "Child says: " <> strategy().say(context())
...> end
iex> defstrategy Child, extends: Abstract do
...> defhook say, do: "Hello!"
...> end
iex> Child.example(%Context{strategy: Child})
"Child says: Hello!"
Define a strategy.
This macro is used to define a strategy module. Through the use of this macro, a strategy module
can be defined from scratch or based on one or more existing strategies. This macro enables the
use of defhook/2
, which is used to define a strategy hook.
A hook is an elixir function which accepts a Skitter.Strategy.context/0
as its first
argument. This context argument is implicitly created by the defhook/2
macro; the various
fields of the context can be accessed through the use of context/0
, component/0
,
strategy/0
, deployment/0
and invocation/0
.
Besides the context argument, hooks offer one additional feature: they can be inherited by other strategies.
Extending Strategies
A strategy can be created based on an existing strategy. This is done by extending some strategy. When a strategy extends another strategy, it will inherit all the hooks defined by the strategy it extends:
iex> defstrategy Parent do
...> defhook example, do: :example_hook
...> end
iex> defstrategy Child, extends: Parent do
...> end
iex> Child.example(%Context{})
:example_hook
Inherited hooks can be overridden:
iex> defstrategy Parent do
...> defhook example, do: :parent
...> end
iex> defstrategy Child, extends: Parent do
...> defhook example, do: :child
...> end
iex> Child.example(%Context{})
:child
Finally, a strategy can extend multiple parent strategies. When this is done, the hooks of earlier parent strategies take precedence over later hooks:
iex> defstrategy Parent1 do
...> defhook example, do: :parent1
...> end
iex> defstrategy Parent2 do
...> defhook example, do: :parent2
...> defhook another, do: :parent2
...> end
iex> defstrategy Child, extends: [Parent1, Parent2] do
...> end
iex> Child.example(%Context{})
:parent1
iex> Child.another(%Context{})
:parent2
Note that some caveats apply when hooks call other hooks. These are described in the
documentation of defhook/2
.
Obtain the context's component.
Examples
iex> defstrategy ReadDeployment do
...> defhook read, do: deployment()
...> end
iex> ReadDeployment.read(%Context{deployment: :some_deployment_data})
:some_deployment_data
Obtain the context's component.
Examples
iex> defstrategy ReadInvocation do
...> defhook read, do: invocation()
...> end
iex> ReadInvocation.read(%Context{invocation: :external})
:external
Obtain the context's component.
Examples
iex> defstrategy ReadStrategy do
...> defhook read, do: strategy()
...> end
iex> ReadStrategy.read(%Context{strategy: ReadStrategy})
Skitter.DSL.StrategyTest.ReadStrategy