archspec 1.0.0 → 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.md +20 -12
- data/lib/archspec/evaluator.rb +6 -1
- data/lib/archspec/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 07a83d8f3402826cb160272cea2739a3ad9542bc7d35fd6590544c39fcf7c597
|
|
4
|
+
data.tar.gz: 5d087f15b56575032c262a7f7e097270b4bad4bb09acd066003bfbbc338900eb
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: c1ee035facb38cb68d9bde3b469f6fdd0e98bf434437254c3f9123cb7eb4ca9cfb2206ce0e4ad01fd25179054cc91e0c821de729026a08e69bb2cfb99092c084
|
|
7
|
+
data.tar.gz: de5d78b6d8e71e26d2a9cc67e6ad0854f532b876bd7e885536e867ddf27d5fb1a324b3bdb79e63f4d880c0194de036e94c2ae77d10219bedd19f6d84008e0d6b
|
data/README.md
CHANGED
|
@@ -1,20 +1,24 @@
|
|
|
1
|
+
<div align="center">
|
|
2
|
+
|
|
1
3
|
# ArchSpec
|
|
2
4
|
|
|
3
|
-
|
|
5
|
+
<strong>Executable architecture specifications for Ruby and Rails</strong>
|
|
6
|
+
|
|
7
|
+
<p>Declare your components and boundaries in one <code>Archspec.rb</code>, and every change gets checked in CI, whether a person or a coding agent wrote it. No AI involved, just Prism.</p>
|
|
8
|
+
|
|
9
|
+
Battle tested in [<picture><source media="(prefers-color-scheme: dark)" srcset="https://rubyllm.com/assets/images/logotype_dark.svg"><img src="https://rubyllm.com/assets/images/logotype.svg" alt="RubyLLM" height="30" align="absmiddle"></picture>](https://rubyllm.com) and at [<picture><source media="(prefers-color-scheme: dark)" srcset="https://chatwithwork.com/logotype-dark.svg"><img src="https://chatwithwork.com/logotype.svg" alt="Chat with Work" height="30" align="absmiddle"></picture>](https://chatwithwork.com)
|
|
4
10
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
analysis: it reads Ruby source with Prism, never boots the app, and no AI is
|
|
9
|
-
involved in checking your code.
|
|
11
|
+
[](https://rubygems.org/gems/archspec)
|
|
12
|
+
[](https://rubygems.org/gems/archspec)
|
|
13
|
+
[](https://github.com/crmne/archspec/actions/workflows/ci.yml)
|
|
10
14
|
|
|
11
|
-
|
|
12
|
-
you write down: components, layers, constant references, inheritance, mixins,
|
|
13
|
-
named method calls, method protocols, cycles, and Rails boundaries.
|
|
15
|
+
<img src="https://archspecrb.dev/assets/images/archspec-check.png" alt="archspec check reporting an architecture violation with a code frame, the offending span underlined, and the evidence as a note" width="760">
|
|
14
16
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
17
|
+
</div>
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
ArchSpec turns your architecture into executable checks: components, layers, constant references, inheritance, mixins, named method calls, method protocols, naming conventions, cycles, and Rails boundaries. It is plain static analysis: it reads Ruby source with Prism, never boots the app, and no AI is involved in checking your code. The full Discourse app, 1,899 files, checks in 2.5 seconds.
|
|
18
22
|
|
|
19
23
|
## Why ArchSpec?
|
|
20
24
|
|
|
@@ -32,6 +36,10 @@ to remember, and checks them on every change:
|
|
|
32
36
|
- query objects do not call obvious write methods
|
|
33
37
|
- generated code follows the same boundaries as hand-written code
|
|
34
38
|
|
|
39
|
+
ArchSpec does not try to infer the "true" design pattern of arbitrary Ruby code.
|
|
40
|
+
You describe the architecture your team wants. ArchSpec checks whether the code
|
|
41
|
+
still matches it.
|
|
42
|
+
|
|
35
43
|
## Show me the code
|
|
36
44
|
|
|
37
45
|
Start with conventional Rails boundaries:
|
data/lib/archspec/evaluator.rb
CHANGED
|
@@ -7,10 +7,15 @@ module ArchSpec
|
|
|
7
7
|
def evaluate(definition, graph, todo: Todo.empty)
|
|
8
8
|
diagnostics = parser_diagnostics(graph) + definition.rules.flat_map { |rule| rule.evaluate(graph) }
|
|
9
9
|
|
|
10
|
+
# Deduplicate before rejecting. One statement can raise several diagnostics
|
|
11
|
+
# that differ only in evidence, because `include Foo` is both an includes
|
|
12
|
+
# edge and a constant reference. Todo entries are matched on evidence, so
|
|
13
|
+
# rejecting first would drop the recorded diagnostic and report its
|
|
14
|
+
# surviving sibling as new.
|
|
10
15
|
diagnostics
|
|
11
|
-
.reject { |diagnostic| graph.suppressed?(diagnostic) || todo.include?(diagnostic) }
|
|
12
16
|
.sort_by { |d| [d.location.path, d.location.line, d.rule, d.message, d.evidence] }
|
|
13
17
|
.uniq { |d| [d.rule, d.message, d.location.path, d.location.line] }
|
|
18
|
+
.reject { |diagnostic| graph.suppressed?(diagnostic) || todo.include?(diagnostic) }
|
|
14
19
|
end
|
|
15
20
|
|
|
16
21
|
private
|
data/lib/archspec/version.rb
CHANGED
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: archspec
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.0.
|
|
4
|
+
version: 1.0.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Carmine Paolino
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: exe
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-08-
|
|
11
|
+
date: 2026-08-20 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: prism
|