archspec 0.4.0 → 0.5.0

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.
data/lib/archspec/dsl.rb CHANGED
@@ -56,16 +56,6 @@ module ArchSpec
56
56
  self.todo_path = path.to_s
57
57
  end
58
58
 
59
- # Declares acronym inflections for Zeitwerk name checks, mirroring your
60
- # +config/initializers/inflections.rb+.
61
- #
62
- # inflect "api" => "API", "graphql" => "GraphQL"
63
- #
64
- # +app/models/api_client.rb+ then expects +APIClient+.
65
- def inflect(map)
66
- add_inflections(map)
67
- end
68
-
69
59
  # Yields each subdirectory matching a glob, so you can declare one
70
60
  # component per engine or pack without hardcoding their names. Paths
71
61
  # resolve against the +Archspec.rb+ directory, not the working directory,
@@ -97,9 +87,6 @@ module ArchSpec
97
87
  #
98
88
  # Returns an ArchSpec::DSL::ComponentProxy for attaching rules. The
99
89
  # component is also available by name later in the file.
100
- #
101
- # +layer+ and +role+ are aliases. Use whichever word fits the
102
- # architecture you are describing.
103
90
  def component(name, in: nil, namespace: nil, constants: nil)
104
91
  add_component(
105
92
  ComponentSpec.new(name, files: binding.local_variable_get(:in), namespace: namespace, constants: constants)
@@ -107,9 +94,6 @@ module ArchSpec
107
94
  ComponentProxy.new(self, name)
108
95
  end
109
96
 
110
- alias layer component
111
- alias role component
112
-
113
97
  # Applies a bundled architecture preset, defining its components and
114
98
  # rules together.
115
99
  #
@@ -117,34 +101,28 @@ module ArchSpec
117
101
  # architecture :hexagonal
118
102
  # architecture :modular_monolith, components: { ... }, allow: { ... }
119
103
  #
104
+ # +preset+ is an alias. Use whichever word fits: +architecture+ reads well
105
+ # for structural bundles like +:rails+, +preset+ for convention packs like
106
+ # +:ruby_conventions+.
107
+ #
120
108
  # See ArchSpec::Architectures for every preset and its options.
121
109
  def architecture(name, **options)
122
110
  Architectures.apply(name, self, **options)
123
111
  end
124
112
 
113
+ alias preset architecture
114
+
125
115
  # Forbids dependency cycles between components. Pass +among:+ to limit the
126
116
  # check to a subset; omit it to check every declared component.
127
117
  #
128
- # no_cycles!
129
- # no_cycles! among: %i[billing catalog shared]
118
+ # no_cycles
119
+ # no_cycles among: %i[billing catalog shared]
130
120
  #
131
121
  # Rule id: +dependencies.no_cycles+.
132
- def no_cycles!(among: nil)
122
+ def no_cycles(among: nil)
133
123
  add_rule(Rules::NoCyclesRule.new(among: among))
134
124
  end
135
125
 
136
- # Checks that files define the constant their path implies under Zeitwerk.
137
- # Pass globs to restrict the check to the autoloaded tree, since Rails
138
- # does not autoload +lib+ by default.
139
- #
140
- # verify_zeitwerk_names!
141
- # verify_zeitwerk_names! "app/**/*.rb"
142
- #
143
- # Rule id: +zeitwerk.naming+.
144
- def verify_zeitwerk_names!(*only)
145
- add_rule(Rules::ZeitwerkNamingRule.new(only: only))
146
- end
147
-
148
126
  # Adds a custom rule object. A rule responds to +id+ and
149
127
  # <tt>evaluate(graph)</tt>, returning ArchSpec::Diagnostic objects. Use
150
128
  # this to extend ArchSpec with project-specific checks.
@@ -176,23 +154,20 @@ module ArchSpec
176
154
  @name = name.to_sym
177
155
  end
178
156
 
179
- # Allowlists the components this one may depend on. A reference to any
180
- # other declared component fails.
157
+ # Allowlists the components this one may depend on: only the listed
158
+ # components are permitted, and a reference to any other declared
159
+ # component fails. The mirror image of #can_only_be_used_by.
181
160
  #
182
- # controllers.can_use :models, :services
161
+ # controllers.can_only_use :models, :services
183
162
  #
184
- # +only_depend_on+ and +must_only_depend_on+ are aliases.
185
163
  # Rule id: +dependencies.allow+.
186
- def can_use(*targets)
164
+ def can_only_use(*targets)
187
165
  add_rule(Rules::AllowDependenciesRule.new(name, targets))
188
166
  self
189
167
  end
190
168
 
191
- alias only_depend_on can_use
192
- alias must_only_depend_on can_use
193
-
194
- # Forbids depending on the named components. Narrower than #can_use: only
195
- # the listed components fail, other dependencies are left alone.
169
+ # Forbids depending on the named components. Narrower than #can_only_use:
170
+ # only the listed components fail, other dependencies are left alone.
196
171
  #
197
172
  # models.cannot_use :controllers, :helpers
198
173
  #
@@ -203,7 +178,7 @@ module ArchSpec
203
178
  end
204
179
 
205
180
  # Allowlists the components that may reference this one, the inverse of
206
- # #can_use. A reference from any other component fails. Use it to protect
181
+ # #can_only_use. A reference from any other component fails. Use it to protect
207
182
  # a shared kernel or a component with a deliberately narrow audience.
208
183
  #
209
184
  # shared_kernel.can_only_be_used_by :billing, :catalog
@@ -223,7 +198,8 @@ module ArchSpec
223
198
  # services.cannot_call :render, :params, receiver: :none
224
199
  #
225
200
  # A bare call to a method the component defines, inherits, or generates
226
- # with +attr_*+ or +delegate+ is treated as its own API and not flagged.
201
+ # with +attr_*+, Rails +attribute+, or +delegate+ is treated as its own API
202
+ # and not flagged.
227
203
  # Rule id: +methods.forbid+.
228
204
  def cannot_call(*methods, receiver: :any)
229
205
  add_rule(Rules::CannotCallRule.new(name, methods, receiver: receiver))
@@ -329,6 +305,21 @@ module ArchSpec
329
305
  self
330
306
  end
331
307
 
308
+ # Starts a naming-convention rule over the component's defined, public
309
+ # methods. Select the methods with +matching+, then assert something about
310
+ # them. Every check is name-based and exact.
311
+ #
312
+ # models.method_names.matching(/\A(get|set)_/).forbidden
313
+ # chat.method_names.matching(/\Awith_(?<base>.+)/).requires("without_%{base}")
314
+ # chat.method_names.matching(/\Awith_(?<b>.+)/).requires("%{b}", on: agent, scope: :class)
315
+ #
316
+ # Pass <tt>scope: :class</tt> to select class methods instead of instance
317
+ # methods. See ArchSpec::Rules::Naming::Selected for the constraints
318
+ # (+forbidden+, +requires+). Rule ids: +naming.forbidden+, +naming.requires+.
319
+ def method_names(scope: :instance)
320
+ Rules::Naming::Builder.new(self, scope: scope)
321
+ end
322
+
332
323
  private
333
324
 
334
325
  def add_rule(rule)
@@ -0,0 +1,93 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ArchSpec
4
+ module Formatters
5
+ # Renders <tt>archspec explain</tt>: why a file or constant belongs to its
6
+ # components, and the facts ArchSpec found for it. Raises ArchSpec::Error
7
+ # when the subject matches no file and no constant.
8
+ module Explanation
9
+ module_function
10
+
11
+ def print(output = $stdout, graph:, subject:)
12
+ path = File.expand_path(subject, graph.root)
13
+
14
+ if graph.files.key?(path)
15
+ explain_file(output, graph, path)
16
+ else
17
+ explain_constant(output, graph, subject)
18
+ end
19
+ end
20
+
21
+ def explain_file(output, graph, path)
22
+ file = graph.files.fetch(path)
23
+ output.puts file.relative_path
24
+ output.puts " defined constants: #{graph.constants_for_path(path).map(&:name).join(', ')}"
25
+ print_parse_errors(output, file)
26
+ print_component_reasons(output, graph.component_assignment_reasons_for_path(path))
27
+ print_suppressions(output, file)
28
+ output.puts ' outgoing facts:'
29
+
30
+ graph.edges.select { |edge| edge.from_path == path }.each do |edge|
31
+ output.puts " #{edge.type} #{edge.to} at #{edge.location.line}:#{edge.location.column}"
32
+ end
33
+ end
34
+
35
+ def explain_constant(output, graph, subject)
36
+ constants = graph.constants_named(subject)
37
+ raise Error, "No file or constant found for #{subject.inspect}" if constants.empty?
38
+
39
+ constants.each do |constant|
40
+ output.puts constant.name
41
+ output.puts " kind: #{constant.kind}"
42
+ output.puts " file: #{constant.location.relative_path(graph.root)}:#{constant.location.line}"
43
+ print_component_reasons(output, graph.component_assignment_reasons_for_constant(constant.name))
44
+ output.puts " superclass: #{constant.superclass || '(none)'}"
45
+ output.puts " instance methods: #{constant.instance_methods.to_a.sort.join(', ')}"
46
+ output.puts " class methods: #{constant.class_methods.to_a.sort.join(', ')}"
47
+ end
48
+ end
49
+
50
+ def print_component_reasons(output, assignments)
51
+ if assignments.empty?
52
+ output.puts ' components: (none)'
53
+ return
54
+ end
55
+
56
+ output.puts ' components:'
57
+ assignments.sort_by { |name, _reasons| name.to_s }.each do |name, reasons|
58
+ output.puts " #{name}: #{reasons.empty? ? '(no recorded reason)' : reasons.join('; ')}"
59
+ end
60
+ end
61
+
62
+ def print_suppressions(output, file)
63
+ return if file.suppressions.empty?
64
+
65
+ output.puts ' suppressions:'
66
+ file.suppressions.each do |suppression|
67
+ rule = suppression.rule || '*'
68
+ reason = suppression.reason ? " -- #{suppression.reason}" : ''
69
+ output.puts " #{rule} on line #{line_range(suppression)}#{reason}"
70
+ end
71
+ end
72
+
73
+ def print_parse_errors(output, file)
74
+ return if file.parse_errors.empty?
75
+
76
+ output.puts ' parse errors:'
77
+ file.parse_errors.each do |parse_error|
78
+ output.puts " #{parse_error.location.line}:#{parse_error.location.column} #{parse_error.message}"
79
+ end
80
+ end
81
+
82
+ def line_range(suppression)
83
+ if suppression.end_line == Float::INFINITY
84
+ "#{suppression.start_line}-EOF"
85
+ elsif suppression.start_line == suppression.end_line
86
+ suppression.start_line
87
+ else
88
+ "#{suppression.start_line}-#{suppression.end_line}"
89
+ end
90
+ end
91
+ end
92
+ end
93
+ end
@@ -7,7 +7,7 @@ require_relative 'value_object'
7
7
 
8
8
  module ArchSpec
9
9
  ParseError = ValueObject.define(:message, :location)
10
- MethodDefinition = ValueObject.define(:owner, :name, :scope, :location)
10
+ MethodDefinition = ValueObject.define(:owner, :name, :scope, :location, :visibility)
11
11
 
12
12
  Suppression = ValueObject.define(:rule, :start_line, :end_line, :reason) do
13
13
  def matches?(diagnostic)
@@ -18,12 +18,11 @@ module ArchSpec
18
18
  end
19
19
 
20
20
  class SourceFile
21
- attr_reader :path, :relative_path, :expected_constant, :parse_errors, :suppressions
21
+ attr_reader :path, :relative_path, :parse_errors, :suppressions
22
22
 
23
- def initialize(root:, path:, expected_constant:, parse_errors:, suppressions:)
23
+ def initialize(root:, path:, parse_errors:, suppressions:)
24
24
  @path = path
25
25
  @relative_path = Pathname(path).relative_path_from(Pathname(root)).to_s
26
- @expected_constant = expected_constant
27
26
  @parse_errors = parse_errors
28
27
  @suppressions = suppressions
29
28
  end
@@ -56,19 +55,28 @@ module ArchSpec
56
55
  kind == :module
57
56
  end
58
57
 
59
- def add_instance_method(name, location:)
58
+ def add_instance_method(name, location:, visibility: :public)
60
59
  instance_methods.add(name.to_sym)
61
- method_definitions << MethodDefinition.new(self.name, name.to_sym, :instance, location)
60
+ method_definitions << MethodDefinition.new(self.name, name.to_sym, :instance, location, visibility)
62
61
  end
63
62
 
64
- def add_class_method(name, location:)
63
+ def add_class_method(name, location:, visibility: :public)
65
64
  class_methods.add(name.to_sym)
66
- method_definitions << MethodDefinition.new(self.name, name.to_sym, :class, location)
65
+ method_definitions << MethodDefinition.new(self.name, name.to_sym, :class, location, visibility)
67
66
  end
68
67
 
69
68
  def add_mixin(kind, name)
70
69
  mixins.fetch(kind).add(name)
71
70
  end
71
+
72
+ # Rewrites the visibility of already-recorded definitions, for the
73
+ # <tt>private :foo, :bar</tt> form that names methods defined earlier.
74
+ def set_visibility(name, scope, visibility)
75
+ name = name.to_sym
76
+ method_definitions.map! do |definition|
77
+ definition.name == name && definition.scope == scope ? definition.with(visibility: visibility) : definition
78
+ end
79
+ end
72
80
  end
73
81
 
74
82
  Edge = ValueObject.define(:type, :from_path, :from_constant, :to, :location, :confidence, :receiver)
@@ -117,11 +125,10 @@ module ArchSpec
117
125
  @components = {}
118
126
  end
119
127
 
120
- def add_file(path:, expected_constant:, parse_errors:, suppressions: [])
128
+ def add_file(path:, parse_errors:, suppressions: [])
121
129
  files[path] = SourceFile.new(
122
130
  root: root,
123
131
  path: path,
124
- expected_constant: expected_constant,
125
132
  parse_errors: parse_errors,
126
133
  suppressions: suppressions
127
134
  )
@@ -157,6 +164,12 @@ module ArchSpec
157
164
  component.constants.flat_map { |constant_name| constants_named(constant_name) }.flat_map(&:method_definitions)
158
165
  end
159
166
 
167
+ # Every method definition in the graph, across all constants. Used by
168
+ # project-wide naming rules that are not scoped to one component.
169
+ def method_definitions
170
+ constants.flat_map(&:method_definitions)
171
+ end
172
+
160
173
  def assign_components(component_specs)
161
174
  @components = {}
162
175
 
@@ -2,7 +2,7 @@
2
2
 
3
3
  module ArchSpec
4
4
  module Rules
5
- # Backs ArchSpec::DSL::Context#no_cycles!. Flags dependency cycles between
5
+ # Backs ArchSpec::DSL::Context#no_cycles. Flags dependency cycles between
6
6
  # components, reporting each cycle once in a canonical order.
7
7
  class NoCyclesRule
8
8
  attr_reader :components
@@ -41,7 +41,7 @@ module ArchSpec
41
41
  end
42
42
  end
43
43
 
44
- # Backs ArchSpec::DSL::ComponentProxy#can_use. Flags references from the
44
+ # Backs ArchSpec::DSL::ComponentProxy#can_only_use. Flags references from the
45
45
  # source to any component outside its allowlist.
46
46
  class AllowDependenciesRule < DependencyRule
47
47
  def id
@@ -0,0 +1,209 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'set'
4
+
5
+ module ArchSpec
6
+ module Rules
7
+ # Backs the +methods.matching(...)+ DSL. One rule pairs a selector (which
8
+ # methods it judges) with a constraint (what must hold of them). It judges a
9
+ # component's defined, public methods in the requested scope, or every such
10
+ # method in the project when +source+ is nil. Every finding is name-based and
11
+ # exact, so confidence is always +:high+.
12
+ class NamingRule
13
+ attr_reader :source, :selector, :scope, :except
14
+
15
+ def initialize(source:, selector:, constraint:, scope: :instance, except: [])
16
+ @source = source&.to_sym
17
+ @selector = selector
18
+ @constraint = constraint
19
+ @scope = scope
20
+ @except = Array(except).flatten.map(&:to_sym).to_set
21
+ end
22
+
23
+ def id
24
+ @constraint.id
25
+ end
26
+
27
+ def evaluate(graph)
28
+ selected = candidate_methods(graph).filter_map do |definition|
29
+ next if except.include?(definition.name)
30
+
31
+ match = selector.match(definition)
32
+ [definition, match] if match
33
+ end
34
+
35
+ @constraint.diagnostics(selected, self, graph)
36
+ end
37
+
38
+ private
39
+
40
+ def candidate_methods(graph)
41
+ definitions = source ? graph.method_definitions_for_component(source) : graph.method_definitions
42
+ definitions.select { |definition| definition.scope == scope && definition.visibility == :public }
43
+ end
44
+ end
45
+
46
+ # The selectors and constraints the naming DSL composes, plus the builder the
47
+ # DSL returns.
48
+ module Naming
49
+ # Selects methods whose name matches a regex. A named capture in the regex
50
+ # (such as <tt>(?<base>.+)</tt>) is exposed to the +requires+ constraint.
51
+ class NameSelector
52
+ attr_reader :regex
53
+
54
+ def initialize(regex)
55
+ @regex = regex
56
+ end
57
+
58
+ def match(definition)
59
+ regex.match(definition.name.to_s)
60
+ end
61
+
62
+ def describe
63
+ "matches #{regex.inspect}"
64
+ end
65
+ end
66
+
67
+ # Forbids any selected method from existing. Rule id +naming.forbidden+.
68
+ class Forbidden
69
+ def initialize(because: nil)
70
+ @because = because
71
+ end
72
+
73
+ def id
74
+ 'naming.forbidden'
75
+ end
76
+
77
+ def diagnostics(selected, rule, _graph)
78
+ selected.map do |definition, _match|
79
+ Diagnostic.new(
80
+ rule: id,
81
+ message: message_for(definition),
82
+ location: definition.location,
83
+ evidence: "#{definition.owner} defines #{definition.scope} method #{definition.name} (#{rule.selector.describe})"
84
+ )
85
+ end
86
+ end
87
+
88
+ private
89
+
90
+ def message_for(definition)
91
+ base = "#{definition.owner} must not define ##{definition.name}"
92
+ @because ? "#{base}: #{@because}" : base
93
+ end
94
+ end
95
+
96
+ # Requires each selected method to have a sibling named by a template, in
97
+ # the same component or another (+on:+), at a given scope. The template
98
+ # interpolates the selector's named captures, as in
99
+ # <tt>requires("without_%{base}")</tt>. Rule id +naming.requires+.
100
+ class Requires
101
+ def initialize(template, on: nil, scope: :instance, because: nil)
102
+ @template = template
103
+ @on = on
104
+ @target_scope = scope
105
+ @because = because
106
+ end
107
+
108
+ def id
109
+ 'naming.requires'
110
+ end
111
+
112
+ def diagnostics(selected, rule, graph)
113
+ target = @on || rule.source
114
+ existing = existing_names(graph, target)
115
+
116
+ selected.filter_map do |definition, match|
117
+ sibling = expand(match)
118
+ next if sibling.nil? || existing.include?(sibling.to_sym)
119
+
120
+ Diagnostic.new(
121
+ rule: id,
122
+ message: message_for(definition, sibling, target, rule),
123
+ location: definition.location,
124
+ evidence: "#{definition.owner} defines ##{definition.name}, expected ##{sibling}"
125
+ )
126
+ end
127
+ end
128
+
129
+ private
130
+
131
+ def existing_names(graph, target)
132
+ definitions = target ? graph.method_definitions_for_component(target) : graph.method_definitions
133
+ definitions.select { |definition| definition.scope == @target_scope }.map(&:name).to_set
134
+ end
135
+
136
+ def expand(match)
137
+ @template % captures(match)
138
+ rescue KeyError, ArgumentError
139
+ nil
140
+ end
141
+
142
+ def captures(match)
143
+ match.is_a?(MatchData) ? match.named_captures.transform_keys(&:to_sym) : {}
144
+ end
145
+
146
+ def message_for(definition, sibling, target, rule)
147
+ clause =
148
+ if target && target != rule.source
149
+ "#{target} to define ##{sibling}"
150
+ else
151
+ "a matching ##{sibling}"
152
+ end
153
+ base = "#{definition.owner}##{definition.name} requires #{clause}"
154
+ @because ? "#{base}: #{@because}" : base
155
+ end
156
+ end
157
+
158
+ # Returned by ArchSpec::DSL::ComponentProxy#methods. Starts a selector.
159
+ class Builder
160
+ def initialize(component, scope: :instance)
161
+ @component = component
162
+ @scope = scope
163
+ end
164
+
165
+ def matching(regex)
166
+ Selected.new(@component, NameSelector.new(regex), @scope)
167
+ end
168
+ end
169
+
170
+ # A chosen selector, waiting for a constraint. Each constraint method builds
171
+ # a NamingRule, attaches it, and returns the component proxy so rules chain.
172
+ class Selected
173
+ def initialize(component, selector, scope)
174
+ @component = component
175
+ @selector = selector
176
+ @scope = scope
177
+ end
178
+
179
+ def forbidden(except: [], because: nil)
180
+ add(Forbidden.new(because: because), except)
181
+ end
182
+
183
+ def requires(template, on: nil, scope: :instance, except: [], because: nil)
184
+ add(Requires.new(template, on: component_name(on), scope: scope, because: because), except)
185
+ end
186
+
187
+ private
188
+
189
+ def add(constraint, except)
190
+ rule = NamingRule.new(
191
+ source: @component.name,
192
+ selector: @selector,
193
+ constraint: constraint,
194
+ scope: @scope,
195
+ except: except
196
+ )
197
+ @component.definition.add_rule(rule)
198
+ @component
199
+ end
200
+
201
+ def component_name(target)
202
+ return if target.nil?
203
+
204
+ target.respond_to?(:name) ? target.name : target.to_sym
205
+ end
206
+ end
207
+ end
208
+ end
209
+ end
@@ -50,7 +50,7 @@ module ArchSpec
50
50
  private
51
51
 
52
52
  # A receiverless call to a method the class itself defines (directly,
53
- # inherited, or via attr_*/delegate) is a call to its own API.
53
+ # inherited, or via attr_*/attribute/delegate) is a call to its own API.
54
54
  def own_method_call?(graph, edge)
55
55
  return false unless edge.receiver == :none && edge.from_constant
56
56
 
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ArchSpec
4
- VERSION = '0.4.0'
4
+ VERSION = '0.5.0'
5
5
  end
data/lib/archspec.rb CHANGED
@@ -12,16 +12,16 @@ require_relative 'archspec/dsl'
12
12
  require_relative 'archspec/analyzer'
13
13
  require_relative 'archspec/evaluator'
14
14
  require_relative 'archspec/architectures'
15
- require_relative 'archspec/presets'
16
15
  require_relative 'archspec/rules/component_rules'
17
16
  require_relative 'archspec/rules/concern_rules'
18
17
  require_relative 'archspec/rules/dependency_rules'
18
+ require_relative 'archspec/rules/naming_rules'
19
19
  require_relative 'archspec/rules/privacy_rule'
20
20
  require_relative 'archspec/rules/protocol_rules'
21
21
  require_relative 'archspec/rules/cycle_rule'
22
- require_relative 'archspec/rules/zeitwerk_rule'
23
22
  require_relative 'archspec/formatters/text'
24
23
  require_relative 'archspec/formatters/json'
24
+ require_relative 'archspec/formatters/explanation'
25
25
  require_relative 'archspec/cli'
26
26
 
27
27
  # ArchSpec turns your application's architecture into executable checks.
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: 0.4.0
4
+ version: 0.5.0
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-07-05 00:00:00.000000000 Z
11
+ date: 2026-08-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: prism
@@ -94,17 +94,17 @@ files:
94
94
  - lib/archspec/diagnostic.rb
95
95
  - lib/archspec/dsl.rb
96
96
  - lib/archspec/evaluator.rb
97
+ - lib/archspec/formatters/explanation.rb
97
98
  - lib/archspec/formatters/json.rb
98
99
  - lib/archspec/formatters/text.rb
99
100
  - lib/archspec/model.rb
100
- - lib/archspec/presets.rb
101
101
  - lib/archspec/rules/component_rules.rb
102
102
  - lib/archspec/rules/concern_rules.rb
103
103
  - lib/archspec/rules/cycle_rule.rb
104
104
  - lib/archspec/rules/dependency_rules.rb
105
+ - lib/archspec/rules/naming_rules.rb
105
106
  - lib/archspec/rules/privacy_rule.rb
106
107
  - lib/archspec/rules/protocol_rules.rb
107
- - lib/archspec/rules/zeitwerk_rule.rb
108
108
  - lib/archspec/source_location.rb
109
109
  - lib/archspec/todo.rb
110
110
  - lib/archspec/value_object.rb
@@ -1,14 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module ArchSpec
4
- # Backwards-compatible alias for ArchSpec::Architectures. New code should use
5
- # +architecture+ in the DSL and the ArchSpec::Architectures module.
6
- module Presets
7
- module_function
8
-
9
- # Delegates to ArchSpec::Architectures.apply.
10
- def apply(name, dsl, **options)
11
- Architectures.apply(name, dsl, **options)
12
- end
13
- end
14
- end