Skip to content

Fluent API: immutable .because(...) rule rationale #47

Description

@TristanKruse

Context

Architecture rules explain what must hold, but a future maintainer also needs to know why the
constraint exists. ArchUnitPython already supports a terminal .because(...) rationale; Ruby
should provide the same product concept without copying Python's mutable implementation.

Goal

Allow every executable rule to carry an optional human-readable rationale that appears in failed
test output across the framework-neutral helper, RSpec, and Minitest.

Starting approach

  • Add one common rationale seam to Checkable rather than implementing presentation independently
    in each rule family.
  • Preserve Ruby's immutable-builder convention: .because(reason) returns a new frozen rule and
    leaves the original unchanged.
  • Keep rationale out of violation values; pass it into the central ResultFactory presentation
    path so message construction remains centralized.
  • Expose the normalized rationale for future generated architecture documentation.

Example:

rule = ArchUnit.project_files
               .in_folder('app/controllers/**')
               .should_not
               .depend_on_files
               .in_folder('app/persistence/**')
               .because('controllers should stay thin and delegate persistence')

Acceptance criteria

  • .because(...) is available on every final value that implements Checkable.
  • It trims surrounding whitespace and rejects non-strings or an empty result with ArgumentError.
  • Calling it returns a distinct frozen rule; the original rule remains unchanged and reusable.
  • The reason appears exactly once in a failed framework-neutral, RSpec, and Minitest assertion.
  • Positive and negated RSpec expectations retain their current behavior.
  • The reason does not alter violations, extraction, graph-cache keys, or direct rule.check output.
  • Existing rule families have shared contract tests plus at least one end-to-end fluent example.
  • README and generated API documentation explain the feature.

ArchUnitTS currently lists this as a TODO, so Ruby should follow the shared product vocabulary while
remaining idiomatic and immutable.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions