decorator!
Generating Macro
The decorator! macro is useful for creating higher-order functions, known as decorators, that can be used to modify or wrap classes, enums, methods, and parameters. This enables cross-cutting concerns like logging, validation, or persistence to be applied cleanly and declaratively.
Defining a Decorator
You define a decorator by providing different code blocks for the various kinds of things it can decorate. The macro generates a function that checks its arguments at runtime to figure out what it's decorating and executes the appropriate block.
local log = decorator! {
-- A block for decorating class methods
(_class, method) {
local method_name = name -- a locally available variable
print(f"Method '{method_name}' in class '{_class.__name}' is now being logged.")
-- Return a new function that wraps the original method
return function(...)
print(f"Calling '{method_name}'...")
local result = method(...)
print(f"'{method_name}' returned.")
return result
end
}
-- A block for decorating enums
(_enum) {
print(f"Enum '{_enum.__name}' is now being logged.")
-- You could wrap enum creation here, but for now we just log.
return _enum
}
}
Decorator Targets
The decorator! macro can target several different code constructs. You provide an implementation for each target you want to support.
_ { ... }- A common block executed for any decoration before the specific target block.
(_class) { ... }- Applied to a class definition. The
_classvariable holds the class table. You should return the (possibly modified) class table.
- Applied to a class definition. The
(_class, method) { ... }- Applied to a class method.
_classis the class table andmethodis the function. You should return a new function.
- Applied to a class method.
(_self, value) { ... }- Applied to a parameter of a class constructor or method.
_selfis the class instance, andvalueis the parameter's value. You should return the (possibly modified) value.
- Applied to a parameter of a class constructor or method.
(_enum) { ... }- Applied to an enum definition.
_enumis the enum table. You should return the (possibly modified) enum table.
- Applied to an enum definition.
(_enum, variant) { ... }- Applied to an enum variant.
_enumis the enum table andvariantis the variant itself. This block can have its own sub-blocks:_ { ... }: Common code for all variants.static { ... }: Executed for simple, raw variants.dynamic { ... }: Executed for variants that take arguments (function-like variants).
- Applied to an enum variant.
Using Decorators
You apply a decorator using the @ symbol before the item you want to decorate.
-- Using the 'log' decorator from above
enum! @log MyEnum, {
A, B
}
-- Prints: Enum 'MyEnum' is now being logged.
class! MyClass, {
my_method() {
print("Executing my_method.")
}
}
-- You can also apply decorators to methods directly
MyClass.my_method = log(MyClass, MyClass.my_method)
-- Prints: Method 'my_method' in class 'MyClass' is now being logged.
local instance = MyClass()
instance:my_method()
-- Prints:
-- Calling 'my_method'...
-- Executing my_method.
-- '{method_name}' returned.
Example for all of the decorator targets
Here is a simple example for all of the targets:
local deprecated = decorator! {
(_class, method) {
return function(...)
print(f"Warning: Method '{name}' is deprecated.")
return method(...)
end
}
(_enum, variant) {
dynamic {
return function(...)
print(f"Warning: Enum '{_enum.__name}' variant '{name}' is deprecated.")
return variant(...)
end
}
static {
print(f"Warning: Enum '{_enum.__name}' variant '{name}' is deprecated.")
return variant
}
}
(_enum) {
print(f"Warning: Enum '{name}' is deprecated.")
return _enum
}
(_class) {
function _class:init()
print(f"Warning: Class '{name}' is deprecated.")
end
return _class
}
(_function) {
return function(...)
print(f"Warning: Function '{name}' is deprecated.")
return _function(...)
end
}
(_self, value) {
print(f"Warning: Parameter '{name}' is deprecated.")
return value
}
}