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.

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}
Link to this macro

defhook(signature, list)

View Source (macro)

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:

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!"
Link to this macro

defstrategy(name, opts \\ [], list)

View Source (macro)

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