Promote hooks to fully-fledge types

Hook types include a source, label, and context delegate.
This commit is contained in:
Michael Miller 2021-01-09 11:06:59 -07:00
parent cf422eca02
commit e5cbc8d631
No known key found for this signature in database
GPG key ID: FB9F12F7C646A4AD
3 changed files with 87 additions and 8 deletions

View file

@ -1,4 +1,5 @@
require "./example_context_delegate" require "./example_group_hook"
require "./example_hook"
module Spectator module Spectator
# Mix-in for managing events and hooks. # Mix-in for managing events and hooks.
@ -10,7 +11,7 @@ module Spectator
# #
# The *name* defines the name of the event. # The *name* defines the name of the event.
# This must be unique across all events, not just group events. # This must be unique across all events, not just group events.
# Three public methods are defined - one to add a hook and the others to trigger the event which calls every hook. # Four public methods are defined - two to add a hook and the others to trigger the event which calls every hook.
# One trigger method, prefixed with *call_* will always call the event hooks. # 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. # The other trigger method, prefixed with *call_once_* will only call the event hooks on the first invocation.
# #
@ -24,13 +25,19 @@ module Spectator
# end # end
# ``` # ```
private macro group_event(name, &block) private macro group_event(name, &block)
@%hooks = Deque(->).new @%hooks = [] of ExampleGroupHook
@%called = Atomic::Flag.new @%called = Atomic::Flag.new
# Adds a hook to be invoked when the *{{name.id}}* event occurs.
def add_{{name.id}}_hook(hook : ExampleGroupHook) : Nil
@%hooks << hook
end
# Defines a hook for the *{{name.id}}* event. # Defines a hook for the *{{name.id}}* event.
# The block of code given to this method is invoked when the event occurs. # The block of code given to this method is invoked when the event occurs.
def {{name.id}}(&block) : Nil def {{name.id}}(&block : -> _) : Nil
@%hooks << block hook = ExampleGroupHook.new(label: {{name.stringify}}, &block)
add_{{name.id}}_hook(hook)
end end
# Signals that the *{{name.id}}* event has occurred. # Signals that the *{{name.id}}* event has occurred.
@ -60,7 +67,7 @@ module Spectator
# #
# The *name* defines the name of the event. # The *name* defines the name of the event.
# This must be unique across all events. # This must be unique across all events.
# Two public methods are defined - one to add a hook and the other to trigger the event which calls every hook. # Three public methods are defined - two to add a hook and the other to trigger the event which calls every hook.
# #
# A block must be provided to this macro. # A block must be provided to this macro.
# The block defines the logic for invoking all of the hooks. # The block defines the logic for invoking all of the hooks.
@ -72,13 +79,19 @@ module Spectator
# end # end
# ``` # ```
private macro example_event(name, &block) private macro example_event(name, &block)
@%hooks = Deque(Example ->).new @%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
# Defines a hook for the *{{name.id}}* event. # Defines a hook for the *{{name.id}}* event.
# The block of code given to this method is invoked when the event occurs. # The block of code given to this method is invoked when the event occurs.
# The current example is provided as a block argument. # The current example is provided as a block argument.
def {{name.id}}(&block : Example ->) : Nil def {{name.id}}(&block : Example ->) : Nil
@%hooks << block hook = ExampleHook.new(label: {{name.stringify}}, &block)
add_{{name.id}}_hook(hook)
end end
# Signals that the *{{name.id}}* event has occurred. # Signals that the *{{name.id}}* event has occurred.

View file

@ -0,0 +1,32 @@
require "./context_delegate"
require "./label"
require "./source"
module Spectator
# Information about a hook tied to an example group and a delegate to invoke it.
class ExampleGroupHook
# Location of the hook in source code.
getter! source : Source
# User-defined description of the hook.
getter! label : Label
# Creates the hook with a context delegate.
# The *delegate* will be called when the hook is invoked.
# A *source* and *label* can be provided for debugging.
def initialize(@delegate : ContextDelegate, *, @source : Source? = nil, @label : Label = nil)
end
# Creates the hook with a block.
# The block will be executed when the hook is invoked.
# A *source* and *label* can be provided for debugging.
def initialize(*, @source : Source? = nil, @label : Label = nil, &block : -> _)
@delegate = ContextDelegate.null(&block)
end
# Invokes the hook.
def call : Nil
@delegate.call
end
end
end

View file

@ -0,0 +1,34 @@
require "./example_context_delegate"
require "./label"
require "./source"
module Spectator
# Information about a hook tied to an example and a delegate to invoke it.
class ExampleHook
# Location of the hook in source code.
getter! source : Source
# User-defined description of the hook.
getter! label : Label
# Creates the hook with an example context delegate.
# The *delegate* will be called when the hook is invoked.
# A *source* and *label* can be provided for debugging.
def initialize(@delegate : ExampleContextDelegate, *, @source : Source? = nil, @label : Label = nil)
end
# Creates the hook with a block.
# The block must take a single argument - the current example.
# The block will be executed when the hook is invoked.
# A *source* and *label* can be provided for debugging.
def initialize(*, @source : Source? = nil, @label : Label = nil, &block : Example -> _)
@delegate = ExampleContextDelegate.null(&block)
end
# Invokes the hook.
# The *example* refers to the current example.
def call(example : Example) : Nil
@delegate.call(example)
end
end
end