2021-01-09 18:06:59 +00:00
|
|
|
require "./example_group_hook"
|
|
|
|
require "./example_hook"
|
2020-11-08 22:06:49 +00:00
|
|
|
|
|
|
|
module Spectator
|
|
|
|
# Mix-in for managing events and hooks.
|
|
|
|
# This module is intended to be included by `ExampleGroup`.
|
|
|
|
module Events
|
|
|
|
# Defines an event for an example group.
|
|
|
|
# This event typically runs before or after an example group finishes.
|
|
|
|
# No contextual information (or example) is provided to the hooks.
|
2021-01-09 17:27:54 +00:00
|
|
|
#
|
2020-11-08 22:06:49 +00:00
|
|
|
# The *name* defines the name of the event.
|
2021-01-09 17:27:54 +00:00
|
|
|
# This must be unique across all events, not just group events.
|
2021-01-09 18:06:59 +00:00
|
|
|
# Four public methods are defined - two to add a hook and the others to trigger the event which calls every hook.
|
2020-11-15 00:02:24 +00:00
|
|
|
# One trigger method, prefixed with *call_* will always call the event hooks.
|
|
|
|
# The other trigger method, prefixed with *call_once_* will only call the event hooks on the first invocation.
|
2021-01-09 17:27:54 +00:00
|
|
|
#
|
|
|
|
# A block must be provided to this macro.
|
|
|
|
# The block defines the logic for invoking all of the hooks.
|
|
|
|
# A single argument is yielded to the block - the set of hooks for the event.
|
|
|
|
#
|
|
|
|
# ```
|
|
|
|
# group_event some_hook do |hooks|
|
|
|
|
# hooks.each(&.call)
|
|
|
|
# end
|
|
|
|
# ```
|
2020-11-15 18:22:52 +00:00
|
|
|
private macro group_event(name, &block)
|
2021-01-09 18:06:59 +00:00
|
|
|
@%hooks = [] of ExampleGroupHook
|
2021-01-09 17:27:54 +00:00
|
|
|
@%called = Atomic::Flag.new
|
2020-11-08 22:06:49 +00:00
|
|
|
|
2021-01-09 18:06:59 +00:00
|
|
|
# Adds a hook to be invoked when the *{{name.id}}* event occurs.
|
|
|
|
def add_{{name.id}}_hook(hook : ExampleGroupHook) : Nil
|
|
|
|
@%hooks << hook
|
|
|
|
end
|
|
|
|
|
2020-11-08 22:06:49 +00:00
|
|
|
# Defines a hook for the *{{name.id}}* event.
|
|
|
|
# The block of code given to this method is invoked when the event occurs.
|
2021-01-09 18:06:59 +00:00
|
|
|
def {{name.id}}(&block : -> _) : Nil
|
|
|
|
hook = ExampleGroupHook.new(label: {{name.stringify}}, &block)
|
|
|
|
add_{{name.id}}_hook(hook)
|
2020-11-08 22:06:49 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
# Signals that the *{{name.id}}* event has occurred.
|
|
|
|
# All hooks associated with the event will be called.
|
|
|
|
def call_{{name.id}} : Nil
|
2021-01-09 17:27:54 +00:00
|
|
|
%block(@%hooks)
|
2020-11-08 22:06:49 +00:00
|
|
|
end
|
2020-11-15 00:02:24 +00:00
|
|
|
|
|
|
|
# Signals that the *{{name.id}}* event has occurred.
|
|
|
|
# Only calls the hooks if the event hasn't been triggered before by this method.
|
|
|
|
# Returns true if the hooks were called and false if they weren't (called previously).
|
|
|
|
def call_once_{{name.id}} : Bool
|
2021-01-09 17:27:54 +00:00
|
|
|
first = @%called.test_and_set
|
2020-11-15 00:02:24 +00:00
|
|
|
call_{{name.id}} if first
|
|
|
|
first
|
|
|
|
end
|
2021-01-09 17:27:54 +00:00
|
|
|
|
|
|
|
# Logic specific to invoking the *{{name.id}}* hook.
|
|
|
|
private def %block({{block.args.splat}})
|
|
|
|
{{block.body}}
|
|
|
|
end
|
2020-11-08 22:06:49 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
# Defines an event for an example.
|
|
|
|
# This event typically runs before or after an example finishes.
|
|
|
|
# The current example is provided to the hooks.
|
2021-01-09 17:27:54 +00:00
|
|
|
#
|
2020-11-08 22:06:49 +00:00
|
|
|
# The *name* defines the name of the event.
|
|
|
|
# This must be unique across all events.
|
2021-01-09 18:06:59 +00:00
|
|
|
# Three public methods are defined - two to add a hook and the other to trigger the event which calls every hook.
|
2021-01-09 17:27:54 +00:00
|
|
|
#
|
|
|
|
# A block must be provided to this macro.
|
|
|
|
# The block defines the logic for invoking all of the hooks.
|
|
|
|
# Two arguments are yielded to the block - the set of hooks for the event, and the current example.
|
|
|
|
#
|
|
|
|
# ```
|
|
|
|
# example_event some_hook do |hooks, example|
|
|
|
|
# hooks.each(&.call(example))
|
|
|
|
# end
|
|
|
|
# ```
|
2020-11-15 18:22:52 +00:00
|
|
|
private macro example_event(name, &block)
|
2021-01-09 18:06:59 +00:00
|
|
|
@%hooks = [] of ExampleHook
|
|
|
|
|
|
|
|
# Adds a hook to be invoked when the *{{name.id}}* event occurs.
|
|
|
|
def add_{{name.id}}_hook(hook : ExampleHook) : Nil
|
|
|
|
@%hooks << hook
|
|
|
|
end
|
2020-11-08 22:06:49 +00:00
|
|
|
|
|
|
|
# Defines a hook for the *{{name.id}}* event.
|
|
|
|
# The block of code given to this method is invoked when the event occurs.
|
|
|
|
# The current example is provided as a block argument.
|
2020-11-08 23:53:54 +00:00
|
|
|
def {{name.id}}(&block : Example ->) : Nil
|
2021-01-09 18:06:59 +00:00
|
|
|
hook = ExampleHook.new(label: {{name.stringify}}, &block)
|
|
|
|
add_{{name.id}}_hook(hook)
|
2020-11-08 22:06:49 +00:00
|
|
|
end
|
|
|
|
|
|
|
|
# Signals that the *{{name.id}}* event has occurred.
|
|
|
|
# All hooks associated with the event will be called.
|
|
|
|
# The *example* should be the current example.
|
2021-01-09 17:27:54 +00:00
|
|
|
def call_{{name.id}}(example : Example) : Nil
|
|
|
|
%block(@%hooks, example)
|
|
|
|
end
|
|
|
|
|
|
|
|
# Logic specific to invoking the *{{name.id}}* hook.
|
|
|
|
private def %block({{block.args.splat}})
|
|
|
|
{{block.body}}
|
2020-11-08 22:06:49 +00:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|