diff --git a/src/Interfaces.jl b/src/Interfaces.jl index 26d97ed..fdbaa2d 100644 --- a/src/Interfaces.jl +++ b/src/Interfaces.jl @@ -10,6 +10,7 @@ export @implements, @interface include("arguments.jl") include("interface.jl") +include("documentation.jl") include("implements.jl") include("test.jl") diff --git a/src/documentation.jl b/src/documentation.jl new file mode 100644 index 0000000..cdfd823 --- /dev/null +++ b/src/documentation.jl @@ -0,0 +1,42 @@ +function _help_header(@nospecialize(interface::Type{<:Interface})) + m_keys = mandatory_keys(interface) + o_keys = optional_keys(interface) + return "An Interfaces.jl `Interface` with mandatory components `$m_keys` and optional components `$o_keys`." +end + +function _extended_help(@nospecialize(interface::Type{<:Interface})) + comp = components(interface) + + io_buf = IOBuffer() + # ^(More efficient and readable than string concatenation) + + println(io_buf, "# Extended help") + !isempty(comp.mandatory) && println(io_buf, "\n## Mandatory keys:\n") + _list_keys(io_buf, comp.mandatory) + + !isempty(comp.optional) && println(io_buf, "\n## Optional keys:\n") + _list_keys(io_buf, comp.optional) + + return String(take!(io_buf)) +end + +function _list_keys(io::IO, @nospecialize(component)) + for key in keys(component) + print(io, "* `$key`") + values = component[key] + if values isa Tuple && all(Base.Fix2(isa, Pair), values) + # Such as `iterate = ("description1" => f, "description2" => g)` + println(io, ":") + for value in values + println(io, " * $(first(value))") + end + elseif values isa Pair + # Such as `iterate = "description" => f` + println(io, ": $(first(values))") + else + # all other cases, like `iterate = f` + println(io) + end + end + return nothing +end diff --git a/src/interface.jl b/src/interface.jl index 6c0cd82..449e5ba 100644 --- a/src/interface.jl +++ b/src/interface.jl @@ -81,14 +81,16 @@ macro interface(interface::Symbol, type, components, description) # Generate a docstring for the interface let description=$description, interfacesym=$(QuoteNode(interface)), - m_keys=$Interfaces.mandatory_keys($interface), - o_keys=$Interfaces.optional_keys($interface) + header=$Interfaces._help_header($interface), + extended_help=$Interfaces._extended_help($interface) @doc """ $(" ") $interfacesym - An Interfaces.jl `Interface` with mandatory components `$m_keys` and optional components `$o_keys`. + $header $description + + $extended_help """ $interface end end |> esc diff --git a/test/advanced.jl b/test/advanced.jl index 9d1e06f..d0e2190 100644 --- a/test/advanced.jl +++ b/test/advanced.jl @@ -102,3 +102,6 @@ using Test #src @test Interfaces.test(Group.GroupInterface, Float64) #src @test !Interfaces.test(Group.GroupInterface, Int, int_pairs) #src @test_throws ArgumentError Interfaces.test(Group.GroupInterface, Float64, int_pairs) #src + +include("test_generated_docs.jl") #src + diff --git a/test/test_generated_docs.jl b/test/test_generated_docs.jl new file mode 100644 index 0000000..7199c98 --- /dev/null +++ b/test/test_generated_docs.jl @@ -0,0 +1,42 @@ +expected_extended_help = """# Extended help + +## Mandatory keys: + +* `neutral_check`: + * neutral stable +* `multiplication_check`: + * multiplication stable +* `inversion_check`: + * inversion stable + * inversion works""" + +@test strip(Interfaces._extended_help(Group.GroupInterface)) == strip(expected_extended_help) + + +expected_docs = """``` + GroupInterface +``` + +An Interfaces.jl `Interface` with mandatory components `(:neutral_check, :multiplication_check, :inversion_check)` and optional components `()`. + +A group is a set of elements with a neutral element where you can perform multiplications and inversions. + +The conditions checking the interface accept an `Arguments` object with two fields named `x` and `y`. The type of the first field `x` must be the type you wish to declare as implementing `GroupInterface`. + +# Extended help + +## Mandatory keys: + + * `neutral_check`: + + * neutral stable + * `multiplication_check`: + + * multiplication stable + * `inversion_check`: + + * inversion stable + * inversion works""" + +@test strip(string(@doc Group.GroupInterface)) == strip(expected_docs) +