The slices family
Slices project many source files into architectural component names. A projection can forbid one directed relationship, compare the whole projected graph with PlantUML, or render the graph that the source actually contains.
Capture slices
defined_by accepts a portable glob with exactly one (**) capture. The captured path becomes the
slice label:
use archunit::project_slices;
let scope = project_slices().defined_by("src/(**)/");
assert_eq!(
scope.projection().label_for("src/api/handler.rs").as_deref(),
Some("api"),
);
defined_by_regex uses the first capture of a Rust regular expression. For reusable projections,
use slice_by_pattern, slice_by_regex, slice_by_file_suffix, or slice_identity, then pass the
result to with_projection.
Suffix projections remove .rs and choose the longest configured suffix:
use std::error::Error;
use archunit::{Checkable, project_slices, slice_by_file_suffix};
fn suffix_rule() -> Result<(), Box<dyn Error>> {
let projection = slice_by_file_suffix([
("_controller", "controllers"),
("_service", "services"),
])?;
let rule = project_slices()
.with_projection(projection)
.should_not()
.contain_dependency("controllers", "services");
let _: &dyn Checkable = &rule;
Ok(())
}
Forbid one directed pair
The negative mood checks one exact source-target pair:
use archunit::{assert_passes, project_slices};
let rule = project_slices()
.defined_by("src/(**)/")
.should_not()
.contain_dependency("api", "database");
assert_passes!(rule);
Dependencies inside one slice and projected self-edges are omitted. External Cargo dependencies
keep the crate name as the target slice, so a rule can explicitly forbid ("api", "tokio").
Check the whole graph against PlantUML
The supported component-diagram subset is line based: component [Name], [A] -> [B],
[A] --> [B], apostrophe or // comments, and @startuml / @enduml. Other styling lines are
ignored.
use archunit::{assert_passes, project_slices};
let diagram = r#"
@startuml
component [api]
component [application]
[api] --> [application]
@enduml
"#;
let rule = project_slices()
.defined_by("src/(**)/")
.should()
.ignoring_external_slices()
.ignoring_orphan_slices()
.adhere_to_diagram(diagram);
assert_passes!(rule);
Strict adherence reports every actual projected dependency missing from the diagram.
ignoring_external_slices omits Cargo targets. ignoring_orphan_slices omits dependencies whose
source or target component is undeclared. adhere_to_diagram_in_file(path) reads UTF-8 lazily when
the rule executes.
Draw the project as it is
The reverse path includes isolated selected slices and emits stable sorted PlantUML:
use archunit::{ArchUnitError, project_slices};
fn export_actual_architecture() -> Result<(), ArchUnitError> {
let slices = project_slices().defined_by("src/(**)/");
let text = slices.to_plantuml()?;
slices.export_as_plantuml("target/architecture/actual.puml")?;
assert!(text.starts_with("@startuml"));
Ok(())
}
Use to_plantuml_with and export_as_plantuml_with for explicit CheckOptions. The lower-level
PlantUmlParser, PlantUmlDiagram, PlantUmlDependency, and PlantUmlRenderer operate entirely
on in-memory values.
Next, quantify the source in the metrics family.