archspec 1.0.1 → 1.1.0.rc2

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 07a83d8f3402826cb160272cea2739a3ad9542bc7d35fd6590544c39fcf7c597
4
- data.tar.gz: 5d087f15b56575032c262a7f7e097270b4bad4bb09acd066003bfbbc338900eb
3
+ metadata.gz: 9ae3db03b27c8b620de672283e7ff539eacf0e02db06a8f02c169aad8f4bf314
4
+ data.tar.gz: '01364687e888415205e3397ffc649e38d96e6bd5ae63cc2dbaae6c453d6bdd22'
5
5
  SHA512:
6
- metadata.gz: c1ee035facb38cb68d9bde3b469f6fdd0e98bf434437254c3f9123cb7eb4ca9cfb2206ce0e4ad01fd25179054cc91e0c821de729026a08e69bb2cfb99092c084
7
- data.tar.gz: de5d78b6d8e71e26d2a9cc67e6ad0854f532b876bd7e885536e867ddf27d5fb1a324b3bdb79e63f4d880c0194de036e94c2ae77d10219bedd19f6d84008e0d6b
6
+ metadata.gz: a3744ea8826f19ff6a0c125c54bfac608c36faca53d4a56e15f5c0a5bbc334610985c34cba9cc5b2624939a18062e82d8a4d7c47a21fcaa0ab7250f561516b15
7
+ data.tar.gz: 74b660133723ac4baa18c980c2caa53a9e63e373f37abeb5a2c2a57b43d022a4c41faf6ab4ea3b45bd88f71d5ead637308c106801dfe880179bded85e4b5008b
data/README.md CHANGED
@@ -4,7 +4,7 @@
4
4
 
5
5
  <strong>Executable architecture specifications for Ruby and Rails</strong>
6
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>
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 static analysis.</p>
8
8
 
9
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)
10
10
 
@@ -18,7 +18,7 @@ Battle tested in [<picture><source media="(prefers-color-scheme: dark)" srcset="
18
18
 
19
19
  ---
20
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.
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: Rubydex builds the semantic index, Prism supplies a small syntax overlay, the app never boots, and no AI is involved in checking your code.
22
22
 
23
23
  ## Why ArchSpec?
24
24
 
@@ -100,10 +100,13 @@ Write local rules in plain Ruby:
100
100
  component :controllers, in: "app/controllers/**/*.rb"
101
101
  component :models, in: "app/models/**/*.rb"
102
102
  component :services, in: "app/services/**/*.rb"
103
+ component :records, descendants_of: "ApplicationRecord"
103
104
 
104
105
  controllers.can_only_use :models, :services
105
106
  models.cannot_use :controllers
106
- services.cannot_call :render, :redirect_to, :params, :session
107
+ services.cannot_call :render, :redirect_to, :params, :session,
108
+ because: "services do not own the HTTP response"
109
+ models.cannot_call :find_by_sql, receiver: "ActiveRecord::Base"
107
110
  services.cannot_instantiate_and_invoke
108
111
  ```
109
112
 
@@ -124,7 +127,7 @@ architecture :cqrs,
124
127
  - **Layers:** dependency direction and cycles
125
128
  - **Rails:** controller APIs kept out of models and services
126
129
  - **Architectures:** Rails, vanilla Rails, layered, hexagonal, clean, modular monolith, CQRS, event-driven, and Ruby conventions bundles
127
- - **Protocols:** required methods such as `resolve`, `perform`, or project-specific interfaces
130
+ - **Protocols:** instance/class APIs and callable signatures such as `call(amount, actor:)`
128
131
  - **Naming:** conventions on a component's public API, such as banning `get_`/`set_` or pairing `with_x` with `without_x`
129
132
  - **Objects:** rules against one-shot `Something.new(...).whatever` command objects
130
133
  - **Empty components:** directories that must stay empty, like `app/services` in vanilla Rails
@@ -136,6 +139,8 @@ ArchSpec does not check Zeitwerk constant names. Zeitwerk does that itself. Add
136
139
 
137
140
  ## Installation
138
141
 
142
+ ArchSpec requires Ruby 3.2 or newer.
143
+
139
144
  Add ArchSpec to your Gemfile:
140
145
 
141
146
  ```ruby
@@ -172,8 +177,9 @@ bundle exec archspec check --update-todo
172
177
  bundle exec archspec explain app/models/user.rb
173
178
  ```
174
179
 
175
- `explain` shows why a file or constant belongs to a component and which outgoing
176
- facts ArchSpec found:
180
+ `explain` shows why a file or constant belongs to a component, its resolved
181
+ ancestry, outgoing facts, incoming dependencies, and anything the analysis
182
+ could not prove:
177
183
 
178
184
  ```text
179
185
  app/models/user.rb