diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a2a78a4..15ffdd8 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -19,7 +19,7 @@ jobs: arch: - x64 steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@v4 - uses: julia-actions/setup-julia@v1 with: version: ${{ matrix.version }} @@ -37,6 +37,6 @@ jobs: - uses: julia-actions/julia-buildpkg@v1 - uses: julia-actions/julia-runtest@v1 - uses: julia-actions/julia-processcoverage@v1 - - uses: codecov/codecov-action@v1 + - uses: codecov/codecov-action@v3 with: file: lcov.info diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml new file mode 100644 index 0000000..fadeeaa --- /dev/null +++ b/.github/workflows/docs.yml @@ -0,0 +1,29 @@ +name: Documentation + +on: + push: + branches: + - 'master' + tags: '*' + pull_request: + +jobs: + build: + name: Documentation + permissions: + contents: write + statuses: write + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + - uses: julia-actions/setup-julia@v1 + with: + version: 1.6 + - uses: julia-actions/cache@v1 + - name: Install dependencies + run: julia --project=docs/ -e 'using Pkg; Pkg.develop(PackageSpec(path=pwd())); Pkg.instantiate()' + - name: Build and deploy + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + DOCUMENTER_KEY: ${{ secrets.DOCUMENTER_KEY }} # If authenticating with SSH deploy key + run: julia --project=docs/ docs/make.jl diff --git a/.gitignore b/.gitignore index 80516d7..95731a5 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,6 @@ -Manifest.toml -.DS_Store +*.jl.*.cov +*.jl.cov +*.jl.mem +/Manifest.toml +/docs/Manifest.toml +/docs/build/ diff --git a/README.md b/README.md index 6785f41..831fa3d 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,6 @@ # CompositeTypes.jl +[![Dev](https://img.shields.io/badge/docs-dev-blue.svg)](https://JuliaApproximation.github.io/CompositeTypes.jl/dev) [![Build Status](https://github.com/JuliaApproximation/CompositeTypes.jl/workflows/CI/badge.svg)](https://github.com/JuliaApproximation/CompositeTypes.jl/actions) [![Coverage Status](https://codecov.io/gh/JuliaApproximation/CompositeTypes.jl/branch/master/graph/badge.svg)](https://codecov.io/gh/JuliaApproximation/CompositeTypes.jl) diff --git a/docs/Project.toml b/docs/Project.toml new file mode 100644 index 0000000..962d28c --- /dev/null +++ b/docs/Project.toml @@ -0,0 +1,6 @@ +[deps] +Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4" +CompositeTypes = "b152e2b5-7a66-4b01-a709-34e65c35f657" + +[compat] +Documenter = "1.3" diff --git a/docs/make.jl b/docs/make.jl new file mode 100644 index 0000000..5bbc7af --- /dev/null +++ b/docs/make.jl @@ -0,0 +1,30 @@ +using Documenter +using CompositeTypes +using CompositeTypes.Indexing +using CompositeTypes.Display + +DocMeta.setdocmeta!(CompositeTypes, :DocTestSetup, :(using CompositeTypes); recursive=true) + +makedocs(; + modules=[CompositeTypes,CompositeTypes.Indexing,CompositeTypes.Display], + authors="Daan Huybrechs and contributors", + sitename="CompositeTypes.jl", + format=Documenter.HTML(; + edit_link="main", + assets=String[], + ), + pages=[ + "Home" => "index.md", + "API" => Any[ + "Public API Reference" => "api.md", + "Internal API Reference" => "internal.md" + ], + "Indexing submodule" => "indexing.md", + "Display submodule" => "display.md" + ], +) + +deploydocs( + repo = "github.com/JuliaApproximation/CompositeTypes.jl.git", + devbranch = "master" +) diff --git a/docs/src/api.md b/docs/src/api.md new file mode 100644 index 0000000..02e7661 --- /dev/null +++ b/docs/src/api.md @@ -0,0 +1,31 @@ +# Public API Reference + +This is an exhaustive list of all exported constants, types and functions +in `CompositeTypes.jl`. + +## Constants + +```@autodocs +Modules = [CompositeTypes] +Order = [:constant] +Public = true +Private = false +``` + +## Functions + +```@autodocs +Modules = [CompositeTypes] +Order = [:function] +Public = true +Private = false +``` + +## Types + +```@autodocs +Modules = [CompositeTypes] +Order = [:type] +Public = true +Private = false +``` diff --git a/docs/src/display.md b/docs/src/display.md new file mode 100644 index 0000000..61bcfc7 --- /dev/null +++ b/docs/src/display.md @@ -0,0 +1,70 @@ +# Display + +## Public API Reference + +This is an exhaustive list of all exported constants, types and functions +in `CompositeTypes.Display`. + +### Constants + +```@autodocs +Modules = [Display] +Order = [:constant] +Public = true +Private = false +``` + +### Functions + +```@autodocs +Modules = [Display] +Order = [:function] +Public = true +Private = false +``` + +### Types + +```@autodocs +Modules = [Display] +Order = [:type] +Public = true +Private = false +``` + + +## Internal API Reference + +This is an exhaustive list of all non-exported constants, types and functions +in `CompositeTypes.Display`. + +!!! warning + Unexported functions and types are subject to change across different + releases of the package, even if the release is said to be non-breaking. + +### Constants + +```@autodocs +Modules = [Display] +Order = [:constant] +Public = false +Private = true +``` + +### Functions + +```@autodocs +Modules = [Display] +Order = [:function] +Public = false +Private = true +``` + +### Types + +```@autodocs +Modules = [Display] +Order = [:type] +Public = false +Private = true +``` diff --git a/docs/src/index.md b/docs/src/index.md new file mode 100644 index 0000000..794ac45 --- /dev/null +++ b/docs/src/index.md @@ -0,0 +1,92 @@ +# CompositeTypes.jl + +CompositeTypes.jl defines an interface for types that consist of multiple components. + +## Interface + +The package defines the following functions: +```@docs; canonical=false +iscomposite(x) +components(x) +component(x, I...) +ncomponents(x) +setcomponent!(x, v, I...) +``` + +A type can declare to be composite simply by implementing `components(x)`, and +returning something with non-zero `length`. + +## Indexing + +The submodule `Indexing` defines a generic way to index components of a +composite object. For example, using the `DomainSets.jl` package: +```julia +julia> using DomainSets, CompositeTypes.Indexing + +julia> d = UnitCube(3); components(d) +3-element Vector{UnitInterval{Float64}}: + 0.0..1.0 (Unit) + 0.0..1.0 (Unit) + 0.0..1.0 (Unit) + +julia> d[Component(1)] + 0.0..1.0 (Unit) + +julia> d[Component(1):Component(2)] +2-element Vector{UnitInterval{Float64}}: + 0.0..1.0 (Unit) + 0.0..1.0 (Unit) +``` + +## Display + +### Examples + +Composite types can opt-in to a structured multi-line representation by +defining a display stencil and specializing `show`. An example, again using +the `DomainSets.jl` package: +```julia +julia> using DomainSets + +julia> boundary(UnitCube(3)) +D₄ ∪ D₁ ∪ D₃ + +D₁ = (0.0..1.0 (Unit)) × D₂ × (0.0..1.0 (Unit)) +D₂ = Point{Float64}(0.0) ∪ Point{Float64}(1.0) +D₃ = (0.0..1.0 (Unit)) × (0.0..1.0 (Unit)) × D₂ +D₄ = D₂ × (0.0..1.0 (Unit)) × (0.0..1.0 (Unit)) +``` +The display routines recursively evaluate display stencils of all objects +appearing in the stencil of an object, up to a maximum recursion depth. An +attempt is made to define symbols, such that the output remains somewhat +readable. + +Both the `ProductDomain` and `UnionDomain` types are composite types. They +combine their components using a `combinationsymbol`, in this case `∪` and `×`. +The output above is achieved with the definitions, for `ProductDomain`: +```julia +using CompositeTypes.Display +Display.combinationsymbol(d::ProductDomain) = Display.Symbol('×') +Display.displaystencil(d::ProductDomain) = composite_displaystencil(d) + +show(io::IO, mime::MIME"text/plain", d::ProductDomain) = composite_show(io, mime, d) +show(io::IO, d::ProductDomain) = composite_show_compact(io, d) +``` +The invocation of `show` with the `mime` argument indicates that a multi-line +representation can be shown. The shorter `show(io, x)` function typically expects +a one-line representation. Types can choose to implement either function. Typically +the longer version is the most useful, while for the compact version it may be +safer to rely on Julia's default. + +A type can define a custom display stencil, which is a vector in which each string +or character ends up being displayed, and each object is replaced by its own +display stencil or by a compact string representation. For example: +```julia +Display.displaystencil(object::LinearMap) = [object.A, " * x + ", object.b] +``` + +### Relevant functions + +```@docs; canonical=false +Display.displaystencil +``` diff --git a/docs/src/indexing.md b/docs/src/indexing.md new file mode 100644 index 0000000..1172d41 --- /dev/null +++ b/docs/src/indexing.md @@ -0,0 +1,70 @@ +# Indexing + +## Public API Reference + +This is an exhaustive list of all exported constants, types and functions +in `CompositeTypes.Indexing`. + +### Constants + +```@autodocs +Modules = [Indexing] +Order = [:constant] +Public = true +Private = false +``` + +### Functions + +```@autodocs +Modules = [Indexing] +Order = [:function] +Public = true +Private = false +``` + +### Types + +```@autodocs +Modules = [Indexing] +Order = [:type] +Public = true +Private = false +``` + + +## Internal API Reference + +This is an exhaustive list of all non-exported constants, types and functions +in `CompositeTypes.Indexing`. + +!!! warning + Unexported functions and types are subject to change across different + releases of the package, even if the release is said to be non-breaking. + +### Constants + +```@autodocs +Modules = [Indexing] +Order = [:constant] +Public = false +Private = true +``` + +### Functions + +```@autodocs +Modules = [Indexing] +Order = [:function] +Public = false +Private = true +``` + +### Types + +```@autodocs +Modules = [Indexing] +Order = [:type] +Public = false +Private = true +``` diff --git a/docs/src/internal.md b/docs/src/internal.md new file mode 100644 index 0000000..78caee1 --- /dev/null +++ b/docs/src/internal.md @@ -0,0 +1,35 @@ +# Internal API Reference + +This is an exhaustive list of all non-exported constants, types and functions +in `CompositeTypes.jl`. + +!!! warning + Unexported functions and types are subject to change across different + releases of the package, even if the release is said to be non-breaking. + +## Constants + +```@autodocs +Modules = [CompositeTypes] +Order = [:constant] +Public = false +Private = true +``` + +## Functions + +```@autodocs +Modules = [CompositeTypes] +Order = [:function] +Public = false +Private = true +``` + +## Types + +```@autodocs +Modules = [CompositeTypes] +Order = [:type] +Public = false +Private = true +``` diff --git a/src/CompositeTypes.jl b/src/CompositeTypes.jl index a393838..f314a3f 100644 --- a/src/CompositeTypes.jl +++ b/src/CompositeTypes.jl @@ -17,16 +17,24 @@ If an object is composite, then its components can be queried using the """ iscomposite(x) = length(components(x)) > 0 -"Return the components of the composite object `x`." +""" + components(x) + +The components of the composite object `x`. +""" components(x) = () -"Return the number of components of composite object `x`." +""" + ncomponents(x) + +The number of components of composite object `x`. +""" ncomponents(x) = length(components(x)) """ component(x, I...) -Return the component of `x` that corresponds to the given index. +The component of `x` that corresponds to the given index. """ component(x, I...) = getindex(components(x), I...) diff --git a/src/Display.jl b/src/Display.jl index 3d2cf78..889bfd8 100644 --- a/src/Display.jl +++ b/src/Display.jl @@ -97,6 +97,8 @@ end hasstencil(object) = length(displaystencil(object)) > 0 """ + displaystencil(object) + Return the stencil of the object as an array. The stencil of an object determines how it is displayed. The array may @@ -117,6 +119,8 @@ displaystencil(object) = [] constructorname(object) = typename(object) """ + composite_displaystencil(object; kwargs...) + Default display stencil for composite objects. The default leads to the representation `typename(component1, components2, ...)`, @@ -170,11 +174,17 @@ end SymbolObject(object) = SymbolObject(object, displaysymbol(object)) displaysymbol(object::SymbolObject) = object.sym -"Return all objects appearing in the display stencil." +""" + stencil_objects(object) + +Return all objects appearing in the display stencil. +""" stencil_objects(object) = objects(displaystencil(object)) objects(A::Vector) = unique([el for el in A if !istext(el)]) """ + compact_repr(object) + The conventional compact representation of an object. This representation is based on `show(io, d)`. If an object has overriden @@ -212,7 +222,11 @@ function recursive_stencils(object, depth = 1, maxdepth = maximum_depth(object), stencils end -"If an object in the stencil is complicated, should we put parentheses around it?" +""" + stencil_parentheses(object) + +If an object in the stencil is complicated, should we put parentheses around it? +""" function stencil_parentheses(object) if hasstencil(object) iscomposite(object) && !is_comma_separated(object) @@ -221,7 +235,11 @@ function stencil_parentheses(object) end end -"If this object appears in a more complicated expression, does it require parentheses?" +""" + object_parentheses(object) + +If this object appears in a more complicated expression, does it require parentheses? +""" function object_parentheses(object) if iscomposite(object) !is_comma_separated(object) @@ -324,6 +342,8 @@ end """ + composite_show(io::IO, ::MIME"text/plain", object) + Display multi-line structured information about a composite object, using the stencil of the object and, recursively, the stencils of any objects therein. @@ -368,6 +388,8 @@ function composite_show(io::IO, object) end """ + composite_show_compact(io::IO, object) + Display structured information about a composite object using its stencil, but not recursively. """ diff --git a/src/Indexing.jl b/src/Indexing.jl index aedd7f3..1aaab51 100644 --- a/src/Indexing.jl +++ b/src/Indexing.jl @@ -5,7 +5,11 @@ export Component, ComponentIndex using ..CompositeTypes -"Supertype of indices that select components of an object rather than its entries." +""" + ComponentIndex{I} + +Supertype of indices that select components of an object rather than its entries. +""" abstract type ComponentIndex{I} end import Base.(:) @@ -29,6 +33,8 @@ function _iterate(idx::ComponentIndex, it) end """ + Component{I} + Component index of a composite type. Internally, this index simply stores an index or a range of indices to @@ -38,10 +44,18 @@ struct Component{I} <: ComponentIndex{I} i :: I end -"Create a new component index of the same type but with a different value." +""" + similarindex(idx::Component, I) + +Create a new component index of the same type but with a different value. +""" similarindex(idx::Component, I) = Component(I) -"Convert the component index to an index of `components`." +""" + to_index(idx::Component) + +Convert the component index to an index of `components`. +""" to_index(idx::Component) = idx.i