For example, how could I add, in my own code/package, a method for the @test
macro defined in the standard package Test.jl
.
Doing the following does not seem to work:
import Test: @test
macro test(ex::SomeArbitraryType, args...)
...
end
More concretely, it does not register an extra method on the actual Test.@test
macro,
but just defines a new local macro called @test
.
You can add new methods, but the types you can dispatch on are limited: Expr
, Symbol
, literal numbers:
julia> using Test
julia> @test 1+1==2 # macro called with Expr type
Test Passed
julia> @which @test 1+1==2
var"@test"(__source__::LineNumberNode, __module__::Module, ex, kws...)
@ Test ~/.julia/dev/julia/usr/share/julia/stdlib/v1.12/Test/src/Test.jl:493
julia> function Test.var"@test"(__source__::LineNumberNode, __module__::Module, ex::Int, kws...)
println("new method for Int") # more specific signature
return __module__
end
julia> @test 3 # macro called with Int type
new method for Int
If x isa SomeArbitraryType
at runtume, this is not visible to the macro. For instance, if we define f(x) = @test x
, then the macro method for ::Symbol
is called immediately. The macro sees the code involved in defining f
, and returns other code which runs once f
is called.
julia> macro Test.test(ex::Symbol, args...)
println("method for symbol")
return string(__source__)
end
julia> f(x) = @test x # macro expansion happens immediately
method for symbol
f (generic function with 1 method)
julia> f("something") # now the expanded code is run
"#= REPL[10]:1 =#"
julia> methods(Test.var"@test")
# 3 methods for macro "@test" from Test:
[1] var"@test"(__source__::LineNumberNode, __module__::Module, ex::Symbol, args...)
@ Main REPL[6]:1
[2] var"@test"(__source__::LineNumberNode, __module__::Module, ex::Int64, kws...)
@ Main REPL[4]:1
[3] var"@test"(__source__::LineNumberNode, __module__::Module, ex, kws...)
@ ~/.julia/dev/julia/usr/share/julia/stdlib/v1.12/Test/src/Test.jl:493