Module: ArchSpec

Defined in:
lib/archspec.rb,
lib/archspec/cli.rb,
lib/archspec/dsl.rb,
lib/archspec/todo.rb,
lib/archspec/model.rb,
lib/archspec/presets.rb,
lib/archspec/version.rb,
lib/archspec/analyzer.rb,
lib/archspec/evaluator.rb,
lib/archspec/definition.rb,
lib/archspec/diagnostic.rb,
lib/archspec/value_object.rb,
lib/archspec/architectures.rb,
lib/archspec/component_spec.rb,
lib/archspec/formatters/json.rb,
lib/archspec/formatters/text.rb,
lib/archspec/source_location.rb,
lib/archspec/rules/cycle_rule.rb,
lib/archspec/rules/privacy_rule.rb,
lib/archspec/rules/concern_rules.rb,
lib/archspec/rules/zeitwerk_rule.rb,
lib/archspec/rules/protocol_rules.rb,
lib/archspec/rules/component_rules.rb,
lib/archspec/rules/dependency_rules.rb

Overview

ArchSpec turns your application's architecture into executable checks.

You describe components, dependencies, and boundaries in an Archspec.rb file written in the ArchSpec::DSL, then run archspec check to verify every change. ArchSpec reads Ruby source with Prism and never boots the app.

The DSL is the public API. An Archspec.rb file is evaluated directly:

architecture :rails

component :services, in: "app/services/**/*.rb"
services.cannot_call :render, :redirect_to, receiver: :none

See ArchSpec::DSL::Context for the top-level DSL and ArchSpec::DSL::ComponentProxy for per-component rules. See ArchSpec::Architectures for the bundled architecture presets.

You can also build a definition in plain Ruby with ArchSpec.define.

Defined Under Namespace

Modules: Analyzer, Architectures, CLI, DSL, Evaluator, Formatters, Presets, Rules, ValueObject Classes: Component, ComponentSpec, ConstantNode, Definition, Diagnostic, Error, Graph, SourceFile, Todo

Constant Summary collapse

ParseError =
ValueObject.define(:message, :location)
MethodDefinition =
ValueObject.define(:owner, :name, :scope, :location)
Suppression =
ValueObject.define(:rule, :start_line, :end_line, :reason) do
  def matches?(diagnostic)
    (rule.nil? || rule == diagnostic.rule) &&
      diagnostic.location.line >= start_line &&
      diagnostic.location.line <= end_line
  end
end
Edge =
ValueObject.define(:type, :from_path, :from_constant, :to, :location, :confidence, :receiver)
VERSION =
'0.4.0'
SourceLocation =
ValueObject.define(:path, :line, :column) do
  def self.from_prism(path, location)
    new(path, location.start_line, location.start_column + 1)
  end

  def relative_path(root)
    Pathname(path).relative_path_from(Pathname(root)).to_s
  rescue ArgumentError
    path
  end
end

Class Attribute Summary collapse

Class Method Summary collapse

Class Attribute Details

.last_definitionObject

The definition produced by the most recent ArchSpec.define call, or by evaluating an Archspec.rb file. The CLI reads this after loading config.



53
54
55
# File 'lib/archspec.rb', line 53

def last_definition
  @last_definition
end

Class Method Details

.define(name = nil, &block) ⇒ Object

Builds an architecture definition from a block of DSL calls.

ArchSpec.define do
component :models, in: "app/models/**/*.rb"
component :controllers, in: "app/controllers/**/*.rb"
models.cannot_use :controllers
end

An Archspec.rb file does not need this wrapper. Its top level is already the DSL, so bare component and architecture calls work directly. Use define when constructing a definition from Ruby, such as in a test.

Returns the ArchSpec::Definition, which is also stored as last_definition.



68
69
70
71
72
73
# File 'lib/archspec.rb', line 68

def define(name = nil, &block)
  definition = Definition.new(name)
  definition.extend(DSL::Context)
  definition.instance_eval(&block) if block
  self.last_definition = definition
end