Spek is a boolean expression engine for Elixir.
It allows you to model, optimize, and evaluate rules using composable expressions.
This module contains all expression builder, evaluation, and optimization functions. Please refer to the readme for details.
Example
Given this check module:
defmodule DeviceChecks do
import Spek.Macros
defcheck device_online(device, reason: :device_offline) do
device.online?
end
defcheck battery_above_20(device, reason: :battery_too_low) do
device.battery_level > 20
end
defcheck charging(device) do
device.charging?
end
defcheck low_power_mode_enabled(device) do
device.low_power_mode?
end
endWe can compose, optimize, and evaluate rules like this:
iex> import Spek
iex> battery_safe =
...> all_of([
...> DeviceChecks.device_online_check(),
...> DeviceChecks.battery_above_20_check()
...> ])
iex> charging_safe =
...> all_of([
...> DeviceChecks.device_online_check(),
...> DeviceChecks.charging_check()
...> ])
iex> rule =
...> any_of([
...> battery_safe,
...> charging_safe,
...> DeviceChecks.low_power_mode_enabled_check()
...> ])
%Spek.AnyOf{
children: [
%Spek.AllOf{
children: [
%Spek.Check{
module: DeviceChecks,
fun: :device_online,
args: [:ctx]
},
%Spek.Check{
module: DeviceChecks,
fun: :battery_above_20,
args: [:ctx]
}
]
},
%Spek.AllOf{
children: [
%Spek.Check{
module: DeviceChecks,
fun: :device_online,
args: [:ctx]
},
%Spek.Check{
module: DeviceChecks,
fun: :charging,
args: [:ctx]
}
]
},
%Spek.Check{
module: DeviceChecks,
fun: :low_power_mode_enabled,
args: [:ctx]
}
]
}
iex> rule = optimize(rule)
%Spek.AnyOf{
children: [
%Spek.AllOf{
children: [
%Spek.Check{
module: DeviceChecks,
fun: :device_online,
args: [:ctx]
},
%Spek.AnyOf{
children: [
%Spek.Check{
module: DeviceChecks,
fun: :battery_above_20,
args: [:ctx]
},
%Spek.Check{
module: DeviceChecks,
fun: :charging,
args: [:ctx]
}
]
}
]
},
%Spek.Check{
module: DeviceChecks,
fun: :low_power_mode_enabled,
args: [:ctx]
}
]
}
iex> device = %{
...> online?: true,
...> battery_level: 12,
...> charging?: false,
...> low_power_mode?: false
...> }
iex> Spek.eval?(rule, device)
false
iex> device = %{
...> online?: false,
...> battery_level: 25,
...> charging?: false,
...> low_power_mode?: false
...> }
iex> Spek.eval_tree(rule, device)
{
:error,
%Spek.EvaluationError{
expression: %Spek.AnyOf{
children: [
%Spek.AllOf{
satisfied?: false,
children: [
%Spek.Check{
module: DeviceChecks,
fun: :device_online,
args: [:ctx],
result: {:error, :device_offline},
satisfied?: false
}
]
},
%Spek.Check{
module: DeviceChecks,
fun: :low_power_mode_enabled,
args: [:ctx],
result: {:error, :failed},
satisfied?: false
}
],
satisfied?: false
},
message: "rule evaluation failed"
}
}
Summary
Builder Functions
Builds an expression that requires all children to be true.
Builds an expression that requires both children to be true.
Builds an expression that requires at least one child to be true.
Builds an expression that requires at least one of two children to be true.
Builds a check.
Builds an expression that is always false.
Builds an expression that always evaluates to the same value.
Builds an expression that evaluates to true unless both children are true.
Negates the given expression.
Builds an expression that requires all of its children to be false.
Builds an expression that evaluates to true if both children are false.
Builds an expression that is always true.
Builds the exclusive or of the given expressions.
Evaluation Functions
Collects all tagged results from an expression into a list.
Collects the success or error results of an expression into a list.
Evaluates the given expression and returns :ok or an error tuple.
Evaluates the given expression and raises an exception if it is not satisfied.
Evaluates the given expression and returns the result as a boolean.
Evaluates the given expression with eval_tree/2 and collects the results
into a list with collect_results/2.
Evaluates the given expression with eval_tree/2 and collects the results
into a list with collect_results/2.
Evaluates the given expression with eval_tree_all/2 and collects the results
into a list with collect_results/2.
Evaluates the given expression with eval_tree_all/2 and collects the results
into a list with collect_results/2.
Evaluates the given expression and returns the expression annotated with evaluation results.
Evaluates the given expression and returns the expression annotated with evaluation results or raises an error.
Evaluates the full given expression and returns the expression annotated with the expression results.
Evaluates the full given expression and returns the expression annotated with evaluation results or raises an error.
Filters the given enumerable to only retain the items that satisfy the given expression.
Filters the given enumerable to only retain the items that do not satisfy the given expression.
Optimization Functions
Performs boolean algebra transformations on the given expression.
Types
The evaluation context as passed to the evaluation functions.
A boolean expression tree.
An expression result value that results in a failed evaluation.
The result of an expression evaluation.
An expression result value that results in a successful evaluation.
Builder Functions
@spec all_of([expression()]) :: Spek.AllOf.t()
Builds an expression that requires all children to be true.
Example
iex> all_of([
...> check(MyModule, :session_active, []),
...> check(MyModule, :permissions_valid, [])
...> ])
%Spek.AllOf{
children: [
%Spek.Check{module: MyModule, fun: :session_active, args: []},
%Spek.Check{module: MyModule, fun: :permissions_valid, args: []}
]
}
@spec all_of(expression(), expression()) :: Spek.AllOf.t()
Builds an expression that requires both children to be true.
Example
iex> all_of(
...> check(RenderingChecks, :color_profile_valid, []),
...> check(RenderingChecks, :frame_rate_supported, [])
...> )
%Spek.AllOf{
children: [
%Spek.Check{module: RenderingChecks, fun: :color_profile_valid, args: []},
%Spek.Check{module: RenderingChecks, fun: :frame_rate_supported, args: []}
]
}
@spec any_of([expression()]) :: Spek.AnyOf.t()
Builds an expression that requires at least one child to be true.
Example
iex> any_of([
...> check(AudioPipelineChecks, :waveform_detected, []),
...> check(AudioPipelineChecks, :silence_threshold_exceeded, [])
...> ])
%Spek.AnyOf{
children: [
%Spek.Check{module: AudioPipelineChecks, fun: :waveform_detected, args: []},
%Spek.Check{module: AudioPipelineChecks, fun: :silence_threshold_exceeded, args: []}
]
}
@spec any_of(expression(), expression()) :: Spek.AnyOf.t()
Builds an expression that requires at least one of two children to be true.
Example
iex> any_of(
...> check(SubtitleChecks, :burn_in_detected, []),
...> check(SubtitleChecks, :timecode_aligned, [])
...> )
%Spek.AnyOf{
children: [
%Spek.Check{module: SubtitleChecks, fun: :burn_in_detected, args: []},
%Spek.Check{module: SubtitleChecks, fun: :timecode_aligned, args: []}
]
}
@spec check(module(), fun(), Spek.Check.args()) :: Spek.Check.t()
Builds a check.
Example
iex> check(WeatherChecks, :temperature_below_freezing, [0])
%Spek.Check{module: WeatherChecks, fun: :temperature_below_freezing, args: [0]}
@spec fail(falsy()) :: Spek.Literal.t()
Builds an expression that is always false.
Example
iex> fail()
%Spek.Literal{result: false, satisfied?: false}
iex> fail(:error)
%Spek.Literal{result: :error, satisfied?: false}
iex> fail({:error, :insufficient_lighting})
%Spek.Literal{result: {:error, :insufficient_lighting}, satisfied?: false}
@spec literal(result()) :: Spek.Literal.t()
Builds an expression that always evaluates to the same value.
Examples
iex> literal(true)
%Spek.Literal{result: true, satisfied?: true}
iex> literal(:ok)
%Spek.Literal{result: :ok, satisfied?: true}
iex> literal({:ok, "render_queue_ready"})
%Spek.Literal{result: {:ok, "render_queue_ready"}, satisfied?: true}
iex> literal(false)
%Spek.Literal{result: false, satisfied?: false}
iex> literal(:error)
%Spek.Literal{result: :error, satisfied?: false}
iex> literal({:error, :codec_not_supported})
%Spek.Literal{result: {:error, :codec_not_supported}, satisfied?: false}
@spec nand(expression(), expression()) :: expression()
Builds an expression that evaluates to true unless both children are true.
Example
iex> nand(check(RenderChecks, :gpu_available, []), check(RenderChecks, :texture_cache_warm, []))
%Spek.Not{
expression: %Spek.AllOf{
children: [
%Spek.Check{module: RenderChecks, fun: :gpu_available, args: []},
%Spek.Check{module: RenderChecks, fun: :texture_cache_warm, args: []}
]
}
}
@spec negate(expression()) :: Spek.Not.t()
Negates the given expression.
Examples
iex> negate(literal(true))
%Spek.Not{expression: %Spek.Literal{result: true, satisfied?: true}}
iex> negate(check(EncodingChecks, :keyframe_aligned, []))
%Spek.Not{
expression: %Spek.Check{module: EncodingChecks, fun: :keyframe_aligned, args: []}
}
@spec none([expression()]) :: expression()
Builds an expression that requires all of its children to be false.
Example
iex> none([check(AudioChecks, :noise_floor_exceeded, []), check(AudioChecks, :clipping_detected, [])])
%Spek.Not{
expression: %Spek.AnyOf{
children: [
%Spek.Check{module: AudioChecks, fun: :noise_floor_exceeded, args: []},
%Spek.Check{module: AudioChecks, fun: :clipping_detected, args: []}
]
}
}
@spec nor(expression(), expression()) :: expression()
Builds an expression that evaluates to true if both children are false.
Example
iex> nor(check(VideoChecks, :frame_dropped, []), check(VideoChecks, :desync_detected, []))
%Spek.Not{
expression: %Spek.AnyOf{
children: [
%Spek.Check{module: VideoChecks, fun: :frame_dropped, args: []},
%Spek.Check{module: VideoChecks, fun: :desync_detected, args: []}
]
}
}
@spec pass(truthy()) :: Spek.Literal.t()
Builds an expression that is always true.
Example
iex> pass()
%Spek.Literal{result: true, satisfied?: true}
iex> pass(:ok)
%Spek.Literal{result: :ok, satisfied?: true}
iex> pass({:ok, "proxy_stream_ready"})
%Spek.Literal{result: {:ok, "proxy_stream_ready"}, satisfied?: true}
@spec xor(expression(), expression()) :: expression()
Builds the exclusive or of the given expressions.
Example
iex> xor(check(PipelineChecks, :transcode_complete, []), check(PipelineChecks, :thumbnail_generated, []))
%Spek.AnyOf{
children: [
%Spek.AllOf{
children: [
%Spek.Check{module: PipelineChecks, fun: :transcode_complete, args: []},
%Spek.Not{
expression: %Spek.Check{
module: PipelineChecks,
fun: :thumbnail_generated,
args: []
}
}
]
},
%Spek.AllOf{
children: [
%Spek.Not{
expression: %Spek.Check{
module: PipelineChecks,
fun: :transcode_complete,
args: []
}
},
%Spek.Check{module: PipelineChecks, fun: :thumbnail_generated, args: []}
]
}
]
}
Evaluation Functions
@spec collect_results(expression()) :: [term()]
Collects all tagged results from an expression into a list.
Results are returned without their :ok / :error tags.
Examples
Literals and checks contribute only tagged tuple payloads. The plain result
values :ok, :error, true and false are not returned.
iex> Spek.collect_results(
...> %Literal{result: {:ok, "good"}, satisfied?: true}
...> )
["good"]
iex> Spek.collect_results(
...> %Literal{result: true, satisfied?: true}
...> )
[]
iex> Spek.collect_results(
...> %Check{
...> module: Checks,
...> fun: :some_check,
...> args: [],
...> result: {:error, "bad"},
...> satisfied?: false
...> }
...> )
["bad"]The results of nested expressions are flattened.
iex> expression =
...> %AllOf{
...> children: [
...> %Literal{result: {:ok, "a"}, satisfied?: true},
...> %Literal{result: {:error, "b"}, satisfied?: false},
...> %Check{
...> module: Checks,
...> fun: :some_check,
...> args: [],
...> result: {:ok, "c"},
...> satisfied?: true
...> }
...> ]
...> }
iex> Spek.collect_results(expression)
["a", "b", "c"]
@spec collect_results(expression(), :ok | :error) :: [term()]
Collects the success or error results of an expression into a list.
Examples
The returned list only contains results using :ok or :error tuples.
iex> Spek.collect_results(
...> %Literal{result: {:ok, "good"}, satisfied?: true},
...> :ok
...> )
["good"]
iex> Spek.collect_results(
...> %Check{
...> module: Checks,
...> fun: :some_check,
...> args: [],
...> result: {:error, "bad"},
...> satisfied?: false
...> },
...> :error
...> )
["bad"]The plain result values :ok, :error, true and false are not returned.
iex> Spek.collect_results(
...> %Check{
...> module: Checks,
...> fun: :some_check,
...> args: [],
...> result: false,
...> satisfied?: false
...> },
...> :error
...> )
[]The results of nested expressions are flattened.
iex> expression =
...> %AllOf{
...> children: [
...> %Literal{result: {:ok, "a"}, satisfied?: true},
...> %Literal{result: {:error, "b"}, satisfied?: false},
...> %Check{
...> module: Checks,
...> fun: :some_check,
...> args: [],
...> result: {:ok, "c"},
...> satisfied?: true
...> }
...> ]
...> }
iex> Spek.collect_results(expression, :ok)
["a", "c"]
iex> Spek.collect_results(expression, :error)
["b"]Not reverses which tagged results are returned:
iex> expression =
...> %Not{
...> satisfied?: true,
...> expression: %Literal{
...> result: {:error, "bad"},
...> satisfied?: false
...> }
...> }
iex> Spek.collect_results(expression, :ok)
["bad"]
iex> Spek.collect_results(expression, :error)
[]
@spec eval(expression(), context()) :: :ok | {:error, Spek.EvaluationError.t()}
Evaluates the given expression and returns :ok or an error tuple.
Stops early as soon as the final outcome is determined.
Examples
iex> eval(
...> %Check{module: String, fun: :starts_with?, args: [:ctx, "scene_"]},
...> "scene_042_render_complete"
...> )
:ok
iex> eval(
...> %Check{module: String, fun: :starts_with?, args: [:ctx, "scene_"]},
...> "shot_042_render_complete"
...> )
{:error, %Spek.EvaluationError{message: "rule evaluation failed"}}
@spec eval!(expression(), context()) :: :ok | no_return()
Evaluates the given expression and raises an exception if it is not satisfied.
Stops early as soon as the final outcome is determined.
Examples
iex> eval!(
...> %Check{module: String, fun: :starts_with?, args: [:ctx, "scene_"]},
...> "scene_042_render_complete"
...> )
:ok
iex> eval!(
...> %Check{module: String, fun: :starts_with?, args: [:ctx, "scene_"]},
...> "shot_042_render_complete"
...> )
** (Spek.EvaluationError) rule evaluation failed
@spec eval?(expression(), context()) :: boolean()
Evaluates the given expression and returns the result as a boolean.
Stops early as soon as the final outcome is determined.
Examples
iex> eval?(
...> %Check{module: String, fun: :starts_with?, args: [:ctx, "scene_"]},
...> "scene_042_render_complete"
...> )
true
iex> eval?(
...> %Check{module: String, fun: :starts_with?, args: [:ctx, "scene_"]},
...> "shot_042_render_complete"
...> )
false
@spec eval_collect(expression(), context()) :: {:ok, [term()]} | {:error, Spek.EvaluationError.t()}
Evaluates the given expression with eval_tree/2 and collects the results
into a list with collect_results/2.
In the success case, an :ok tuple with the list of success results is
returned.
In the error case, an :error tuple with a Spek.EvaluationError struct that
contains both the evaluation tree and the list of error results.
Examples
iex> eval_collect(
...> %Check{module: Date, fun: :from_iso8601, args: [:ctx]},
...> "2000-01-12"
...> )
{:ok, [~D[2000-01-12]]}
iex> eval_collect(
...> %Check{module: Date, fun: :from_iso8601, args: [:ctx]},
...> "2000-01.12"
...> )
{
:error,
%Spek.EvaluationError{
expression: %Spek.Check{
module: Date,
fun: :from_iso8601,
args: [:ctx],
result: {:error, :invalid_format},
satisfied?: false
},
results: [:invalid_format],
message: "rule evaluation failed"
}
}
@spec eval_collect!(expression(), context()) :: [term()] | no_return()
Evaluates the given expression with eval_tree/2 and collects the results
into a list with collect_results/2.
In the success case, the list of success results is returned.
In the error case, a Spek.EvaluationError exception is raised that
contains both the evaluation tree and the list of error results.
Examples
iex> eval_collect!(
...> %Check{module: Date, fun: :from_iso8601, args: [:ctx]},
...> "2000-01-12"
...> )
[~D[2000-01-12]]
iex> eval_collect!(
...> %Check{module: Date, fun: :from_iso8601, args: [:ctx]},
...> "2000-01.12"
...> )
** (Spek.EvaluationError) rule evaluation failed
@spec eval_collect_all(expression(), context()) :: {:ok, [term()]} | {:error, Spek.EvaluationError.t()}
Evaluates the given expression with eval_tree_all/2 and collects the results
into a list with collect_results/2.
In the success case, an :ok tuple with the list of success results is
returned.
In the error case, an :error tuple with a Spek.EvaluationError struct that
contains both the evaluation tree and the list of error results.
Examples
iex> eval_collect_all(
...> %Check{module: Date, fun: :from_iso8601, args: [:ctx]},
...> "2000-01-12"
...> )
{:ok, [~D[2000-01-12]]}
iex> eval_collect_all(
...> %Check{module: Date, fun: :from_iso8601, args: [:ctx]},
...> "2000-01.12"
...> )
{
:error,
%Spek.EvaluationError{
expression: %Spek.Check{
module: Date,
fun: :from_iso8601,
args: [:ctx],
result: {:error, :invalid_format},
satisfied?: false
},
results: [:invalid_format],
message: "rule evaluation failed"
}
}
@spec eval_collect_all!(expression(), context()) :: [term()] | no_return()
Evaluates the given expression with eval_tree_all/2 and collects the results
into a list with collect_results/2.
In the success case, the list of success results is returned.
In the error case, a Spek.EvaluationError exception is raised that
contains both the evaluation tree and the list of error results.
Examples
iex> eval_collect_all!(
...> %Check{module: Date, fun: :from_iso8601, args: [:ctx]},
...> "2000-01-12"
...> )
[~D[2000-01-12]]
iex> eval_collect_all!(
...> %Check{module: Date, fun: :from_iso8601, args: [:ctx]},
...> "2000-01.12"
...> )
** (Spek.EvaluationError) rule evaluation failed
@spec eval_tree(expression(), context()) :: {:ok, expression()} | {:error, Spek.EvaluationError.t()}
Evaluates the given expression and returns the expression annotated with evaluation results.
Stops early as soon as the final outcome is determined. The returned expression only contains the evaluated parts.
Examples
iex> eval_tree(
...> %Check{module: String, fun: :starts_with?, args: [:ctx, "scene_"]},
...> "scene_042_render_complete"
...> )
{
:ok,
%Spek.Check{
module: String,
fun: :starts_with?,
args: [:ctx, "scene_"],
result: true,
satisfied?: true
}
}
iex> eval_tree(
...> %Check{module: String, fun: :starts_with?, args: [:ctx, "scene_"]},
...> "shot_042_render_complete"
...> )
{
:error,
%Spek.EvaluationError{
expression: %Spek.Check{
module: String,
fun: :starts_with?,
args: [:ctx, "scene_"],
result: false,
satisfied?: false
},
message: "rule evaluation failed"
}
}
@spec eval_tree!(expression(), context()) :: expression() | no_return()
Evaluates the given expression and returns the expression annotated with evaluation results or raises an error.
Stops early as soon as the final outcome is determined. The returned expression only contains the evaluated parts.
Raises an exception if the rule is not satisfied. Unlike eval!/2, the
exception contains the evaluated expression.
Examples
iex> eval_tree!(
...> %Check{module: String, fun: :starts_with?, args: [:ctx, "scene_"]},
...> "scene_042_render_complete"
...> )
%Spek.Check{
module: String,
fun: :starts_with?,
args: [:ctx, "scene_"],
result: true,
satisfied?: true
}
iex> eval_tree!(
...> %Check{module: String, fun: :starts_with?, args: [:ctx, "scene_"]},
...> "shot_042_render_complete"
...> )
** (Spek.EvaluationError) rule evaluation failed
@spec eval_tree_all(expression(), context()) :: {:ok, expression()} | {:error, Spek.EvaluationError.t()}
Evaluates the full given expression and returns the expression annotated with the expression results.
Always evaluates the entire expression, even if the final outcome could be determined earlier.
Examples
iex> eval_tree_all(
...> all_of([
...> %Check{module: String, fun: :starts_with?, args: [:ctx, "scene_"]},
...> %Check{module: String, fun: :ends_with?, args: [:ctx, "_render_complete"]}
...> ]),
...> "scene_042_render_complete"
...> )
{
:ok,
%Spek.AllOf{
children: [
%Spek.Check{
module: String,
fun: :starts_with?,
args: [:ctx, "scene_"],
result: true,
satisfied?: true
},
%Spek.Check{
module: String,
fun: :ends_with?,
args: [:ctx, "_render_complete"],
result: true,
satisfied?: true
}
],
satisfied?: true
}
}
iex> eval_tree_all(
...> all_of([
...> %Check{module: String, fun: :starts_with?, args: [:ctx, "scene_"]},
...> %Check{module: String, fun: :ends_with?, args: [:ctx, "_render_complete"]}
...> ]),
...> "shot_042_render_complete"
...> )
{
:error,
%Spek.EvaluationError{
expression: %Spek.AllOf{
children: [
%Spek.Check{
module: String,
fun: :starts_with?,
args: [:ctx, "scene_"],
result: false,
satisfied?: false
},
%Spek.Check{
module: String,
fun: :ends_with?,
args: [:ctx, "_render_complete"],
result: true,
satisfied?: true
}
],
satisfied?: false
},
message: "rule evaluation failed"
}
}
@spec eval_tree_all!(expression(), context()) :: expression() | no_return()
Evaluates the full given expression and returns the expression annotated with evaluation results or raises an error.
Raises if the expression is not satisfied. Unlike eval!/2, the raised
exception contains the evaluated expression.
Always evaluates the entire expression, even if the final outcome could be determined earlier.
Examples
iex> eval_tree_all!(
...> any_of([
...> %Check{module: String, fun: :starts_with?, args: [:ctx, "scene_"]},
...> %Check{module: String, fun: :ends_with?, args: [:ctx, "_render_complete"]}
...> ]),
...> "scene_042_render_complete"
...> )
%Spek.AnyOf{
satisfied?: true,
children: [
%Spek.Check{
module: String,
fun: :starts_with?,
args: [:ctx, "scene_"],
result: true,
satisfied?: true
},
%Spek.Check{
module: String,
fun: :ends_with?,
args: [:ctx, "_render_complete"],
result: true,
satisfied?: true
}
]
}
iex> eval_tree_all!(
...> %Check{module: String, fun: :starts_with?, args: [:ctx, "scene_"]},
...> "shot_042_render_complete"
...> )
** (Spek.EvaluationError) rule evaluation failed
@spec filter(Enumerable.t(), expression()) :: Enumerable.t()
Filters the given enumerable to only retain the items that satisfy the given expression.
Example
iex> filter(
...> ["scene_042_render_complete", "shot_017_proxy_ready"],
...> %Check{module: String, fun: :starts_with?, args: [:ctx, "scene_"]}
...> )
["scene_042_render_complete"]
@spec reject(Enumerable.t(), expression()) :: Enumerable.t()
Filters the given enumerable to only retain the items that do not satisfy the given expression.
Example
iex> reject(
...> ["scene_042_render_complete", "shot_017_proxy_ready"],
...> %Check{module: String, fun: :starts_with?, args: [:ctx, "scene_"]}
...> )
["shot_017_proxy_ready"]
Optimization Functions
@spec optimize(expression()) :: expression()
Performs boolean algebra transformations on the given expression.
Examples
iex> Spek.optimize(%AnyOf{
...> children: [
...> %AllOf{
...> children: [
...> %Check{module: RenderChecks, fun: :gpu_available, args: []},
...> %Check{module: RenderChecks, fun: :texture_cache_warm, args: []}
...> ]
...> },
...> %AllOf{
...> children: [
...> %Check{module: RenderChecks, fun: :color_space_valid, args: []},
...> %Check{module: RenderChecks, fun: :gpu_available, args: []}
...> ]
...> },
...> %Check{module: RenderChecks, fun: :fallback_renderer_enabled, args: []}
...> ]
...> })
%AnyOf{
children: [
%AllOf{
children: [
%Check{module: RenderChecks, fun: :gpu_available, args: []},
%AnyOf{
children: [
%Check{module: RenderChecks, fun: :texture_cache_warm, args: []},
%Check{module: RenderChecks, fun: :color_space_valid, args: []}
]
}
]
},
%Check{module: RenderChecks, fun: :fallback_renderer_enabled, args: []}
]
}Optimizations
| Optimization | Formula |
|---|---|
| Identity (AND) | A and true = A |
| Identity (OR) | A or false = A |
| Annihilation (AND) | A and false = false |
| Annihilation (OR) | A or true = true |
| Double negation elimination | not (not A) = A |
| Negation of literals | not true = false, not false = true |
| De Morgan’s law (AND) | not (A and B) = (not A) or (not B) |
| De Morgan’s law (OR) | not (A or B) = (not A) and (not B) |
| Empty conjunction | allof() = true |
| Empty disjunction | anyof() = false |
| Single-child conjunction elimination | allof(A) = A |
| Single-child disjunction elimination | anyof(A) = A |
| Deduplication (AND) | A and A = A |
| Deduplication (OR) | A or A = A |
| Factoring OR over AND | (A and B) or (A and C) = A and (B or C) |
| Factoring AND over OR | (A or B) and (A or C) = A or (B and C) |
| Absorption (OR) | A or (A and B) = A |
| Absorption (AND) | A and (A or B) = A |
Types
@type context() :: term()
The evaluation context as passed to the evaluation functions.
@type expression() :: Spek.AllOf.t() | Spek.AnyOf.t() | Spek.Check.t() | Spek.Literal.t() | Spek.Not.t()
A boolean expression tree.
@type falsy() :: false | :error | {:error, term()}
An expression result value that results in a failed evaluation.
The result of an expression evaluation.
@type truthy() :: true | :ok | {:ok, term()}
An expression result value that results in a successful evaluation.