rampart-core 0.1.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 +7 -0
- data/LICENSE +191 -0
- data/README.md +296 -0
- data/lib/rampart/application/command.rb +15 -0
- data/lib/rampart/application/query.rb +15 -0
- data/lib/rampart/application/service.rb +26 -0
- data/lib/rampart/application/transaction.rb +15 -0
- data/lib/rampart/domain/aggregate_root.rb +13 -0
- data/lib/rampart/domain/domain_event.rb +24 -0
- data/lib/rampart/domain/domain_exception.rb +15 -0
- data/lib/rampart/domain/domain_service.rb +10 -0
- data/lib/rampart/domain/entity.rb +20 -0
- data/lib/rampart/domain/value_object.rb +12 -0
- data/lib/rampart/engine_loader.rb +101 -0
- data/lib/rampart/ports/event_bus_port.rb +10 -0
- data/lib/rampart/ports/secondary_port.rb +13 -0
- data/lib/rampart/support/container.rb +28 -0
- data/lib/rampart/support/result.rb +9 -0
- data/lib/rampart/support/types.rb +9 -0
- data/lib/rampart/testing/architecture_matchers.rb +279 -0
- data/lib/rampart/testing/engine_architecture_shared_spec.rb +345 -0
- data/lib/rampart/testing.rb +15 -0
- data/lib/rampart/version.rb +5 -0
- data/lib/rampart.rb +28 -0
- metadata +152 -0
|
@@ -0,0 +1,345 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "json"
|
|
4
|
+
require "rampart/testing/architecture_matchers"
|
|
5
|
+
|
|
6
|
+
# Shared RSpec examples for enforcing Rampart engine architectural patterns.
|
|
7
|
+
#
|
|
8
|
+
# Usage:
|
|
9
|
+
# RSpec.describe "Architecture", type: :architecture do
|
|
10
|
+
# it_behaves_like "Rampart Engine Architecture",
|
|
11
|
+
# engine_root: File.expand_path("../../..", __FILE__),
|
|
12
|
+
# container_class: MyEngine::Infrastructure::Wiring::Container
|
|
13
|
+
# end
|
|
14
|
+
#
|
|
15
|
+
# Options:
|
|
16
|
+
# - engine_root: (required) Path to the engine root directory
|
|
17
|
+
# - container_class: (required) The DI container class for the engine
|
|
18
|
+
# - architecture_json_path: (optional) Path to the architecture JSON file
|
|
19
|
+
# - warn_unimplemented: (optional, default: false) When true, items defined in JSON
|
|
20
|
+
# but missing from code will emit warnings instead of failures. This is useful
|
|
21
|
+
# during development when the JSON blueprint represents planned architecture
|
|
22
|
+
# that hasn't been implemented yet. Code that exists but isn't documented in
|
|
23
|
+
# JSON will still fail (to catch architecture drift).
|
|
24
|
+
#
|
|
25
|
+
# This shared group verifies:
|
|
26
|
+
# 1. DI and Wiring Policies (Services depend on Ports, Controllers depend on Services)
|
|
27
|
+
# 2. Base Class Contracts (Inheritance from Rampart primitives)
|
|
28
|
+
# 3. Immutability (Aggregates and Value Objects are immutable)
|
|
29
|
+
# 4. Public API (No leakage of internal types like ActiveRecord)
|
|
30
|
+
# 5. Architecture JSON Sync (Bidirectional check of code vs blueprint)
|
|
31
|
+
RSpec.shared_examples "Rampart Engine Architecture" do |options = {}|
|
|
32
|
+
include Rampart::Testing::ArchitectureMatchers
|
|
33
|
+
|
|
34
|
+
let(:engine_root) do
|
|
35
|
+
options[:engine_root] || raise("Must provide :engine_root to shared examples")
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
let(:container_class) do
|
|
39
|
+
options[:container_class] || raise("Must provide :container_class (e.g. MyEngine::Infrastructure::Wiring::Container)")
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
let(:architecture_json_path) do
|
|
43
|
+
options[:architecture_json_path] || begin
|
|
44
|
+
bc_id = File.basename(engine_root)
|
|
45
|
+
File.join(engine_root, "../../architecture/#{bc_id}/architecture.json")
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
let(:warn_unimplemented) do
|
|
50
|
+
options[:warn_unimplemented] || false
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
# Helper to check architecture sync with support for warning-only mode on unimplemented items
|
|
54
|
+
def check_architecture_sync(component_type:, json_items:, code_items:, json_path:, add_to_code_hint:, add_to_json_hint:)
|
|
55
|
+
missing_from_code = json_items - code_items
|
|
56
|
+
missing_from_json = code_items - json_items
|
|
57
|
+
|
|
58
|
+
# Always fail if code exists that isn't documented in JSON (architecture drift)
|
|
59
|
+
if missing_from_json.any?
|
|
60
|
+
error_parts = []
|
|
61
|
+
error_parts << "#{component_type} mismatch - undocumented code found:"
|
|
62
|
+
error_parts << ""
|
|
63
|
+
error_parts << " JSON defines: #{json_items.inspect}"
|
|
64
|
+
error_parts << " Code defines: #{code_items.inspect}"
|
|
65
|
+
error_parts << ""
|
|
66
|
+
error_parts << " ❌ Defined in code but missing from JSON: #{missing_from_json.inspect}"
|
|
67
|
+
error_parts << " → #{add_to_json_hint}"
|
|
68
|
+
fail error_parts.join("\n")
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
# For items in JSON but missing from code: warn or fail based on option
|
|
72
|
+
if missing_from_code.any?
|
|
73
|
+
message_parts = []
|
|
74
|
+
message_parts << "#{component_type} not yet implemented:"
|
|
75
|
+
message_parts << ""
|
|
76
|
+
message_parts << " JSON defines: #{json_items.inspect}"
|
|
77
|
+
message_parts << " Code defines: #{code_items.inspect}"
|
|
78
|
+
message_parts << ""
|
|
79
|
+
message_parts << " ⚠️ Defined in JSON but missing from code: #{missing_from_code.inspect}"
|
|
80
|
+
message_parts << " → #{add_to_code_hint}"
|
|
81
|
+
message = message_parts.join("\n")
|
|
82
|
+
|
|
83
|
+
if warn_unimplemented
|
|
84
|
+
# Emit as RSpec warning (will appear in output but not fail)
|
|
85
|
+
warn "\n#{message}\n"
|
|
86
|
+
else
|
|
87
|
+
fail message
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def classes_in_engine(base_class)
|
|
93
|
+
ObjectSpace.each_object(Class).select do |klass|
|
|
94
|
+
next unless klass < base_class
|
|
95
|
+
|
|
96
|
+
location = Object.const_source_location(klass.name)&.first
|
|
97
|
+
location && location.start_with?(engine_root)
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
let(:architecture_json) do
|
|
102
|
+
JSON.parse(File.read(architecture_json_path))
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
# Helpers for class discovery
|
|
106
|
+
let(:aggregates) { classes_in_engine(Rampart::Domain::AggregateRoot) }
|
|
107
|
+
let(:entities) { classes_in_engine(Rampart::Domain::Entity) }
|
|
108
|
+
let(:value_objects) { classes_in_engine(Rampart::Domain::ValueObject) }
|
|
109
|
+
let(:events) { classes_in_engine(Rampart::Domain::DomainEvent) }
|
|
110
|
+
let(:services) { classes_in_engine(Rampart::Application::Service) }
|
|
111
|
+
let(:ports) do
|
|
112
|
+
classes_in_engine(Rampart::Ports::SecondaryPort).select do |klass|
|
|
113
|
+
location = Object.const_source_location(klass.name)&.first
|
|
114
|
+
location&.include?("/domain/")
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
# Adapters are implementations of ports that live in infrastructure
|
|
118
|
+
let(:adapters) do
|
|
119
|
+
classes_in_engine(Rampart::Ports::SecondaryPort).select do |klass|
|
|
120
|
+
location = Object.const_source_location(klass.name)&.first
|
|
121
|
+
location&.include?("/infrastructure/")
|
|
122
|
+
end
|
|
123
|
+
end
|
|
124
|
+
# Controllers (excluding base ApplicationController classes)
|
|
125
|
+
let(:controllers) do
|
|
126
|
+
ObjectSpace.each_object(Class).select do |klass|
|
|
127
|
+
next unless defined?(ActionController::API) && klass < ActionController::API
|
|
128
|
+
# Skip base ApplicationController classes - these are Rails infrastructure, not entrypoints
|
|
129
|
+
next if klass.name&.end_with?("::ApplicationController")
|
|
130
|
+
location = Object.const_source_location(klass.name)&.first
|
|
131
|
+
location && location.start_with?(engine_root) && location.include?("/controllers/")
|
|
132
|
+
end
|
|
133
|
+
end
|
|
134
|
+
let(:queries) { classes_in_engine(Rampart::Application::Query) }
|
|
135
|
+
let(:commands) { classes_in_engine(Rampart::Application::Command) }
|
|
136
|
+
|
|
137
|
+
describe "DI and Wiring Policies" do
|
|
138
|
+
it "services depend only on Ports or Adapters" do
|
|
139
|
+
service_keys = container_class.keys.map(&:to_sym).select { |k| k.to_s.end_with?("_service") }
|
|
140
|
+
|
|
141
|
+
service_keys.each do |key|
|
|
142
|
+
service = container_class.resolve(key)
|
|
143
|
+
|
|
144
|
+
service.instance_variables.each do |ivar|
|
|
145
|
+
dep = service.instance_variable_get(ivar)
|
|
146
|
+
next unless dep
|
|
147
|
+
|
|
148
|
+
next if [String, Integer, TrueClass, FalseClass, Symbol, Array, Hash].any? { |t| dep.is_a?(t) }
|
|
149
|
+
|
|
150
|
+
if defined?(ActiveRecord::Base) && dep.is_a?(ActiveRecord::Base)
|
|
151
|
+
fail "Service #{key} has ActiveRecord dependency in #{ivar}: #{dep.class}"
|
|
152
|
+
end
|
|
153
|
+
end
|
|
154
|
+
end
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
it "controllers only resolve Application Services or allowed Adapters" do
|
|
158
|
+
allowed_keys = container_class.keys.map(&:to_sym).select do |k|
|
|
159
|
+
s = k.to_s
|
|
160
|
+
s.end_with?("_service") || s.end_with?("_query")
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
controller_files = Dir[File.join(engine_root, "app/controllers/**/*.rb")]
|
|
164
|
+
.reject { |f| f.end_with?("AGENTS.md") || f.end_with?("README.md") }
|
|
165
|
+
|
|
166
|
+
controller_files.each do |file|
|
|
167
|
+
expect(file).to only_resolve_allowed_dependencies(allowed_keys)
|
|
168
|
+
end
|
|
169
|
+
end
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
describe "Base Class Contracts" do
|
|
173
|
+
it "aggregates inherit from Rampart::Domain::AggregateRoot" do
|
|
174
|
+
expect(aggregates).to all(inherit_from_rampart_base(Rampart::Domain::AggregateRoot))
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
it "entities inherit from Rampart::Domain::Entity" do
|
|
178
|
+
expect(entities).to all(inherit_from_rampart_base(Rampart::Domain::Entity))
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
it "value objects inherit from Rampart::Domain::ValueObject" do
|
|
182
|
+
expect(value_objects).to all(inherit_from_rampart_base(Rampart::Domain::ValueObject))
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
it "ports inherit from Rampart::Ports::SecondaryPort and are implemented" do
|
|
186
|
+
expect(ports).to all(inherit_from_rampart_base(Rampart::Ports::SecondaryPort))
|
|
187
|
+
|
|
188
|
+
ports.each do |port|
|
|
189
|
+
implementations = classes_in_engine(port)
|
|
190
|
+
expect(implementations).not_to be_empty, "expected #{port} to have at least one implementation"
|
|
191
|
+
|
|
192
|
+
implementations.each do |implementation|
|
|
193
|
+
expect(implementation).to implement_all_abstract_methods(port)
|
|
194
|
+
end
|
|
195
|
+
end
|
|
196
|
+
end
|
|
197
|
+
|
|
198
|
+
it "commands and queries inherit from Rampart base classes" do
|
|
199
|
+
expect(queries).to all(inherit_from_rampart_base(Rampart::Application::Query))
|
|
200
|
+
expect(commands).to all(inherit_from_rampart_base(Rampart::Application::Command))
|
|
201
|
+
end
|
|
202
|
+
end
|
|
203
|
+
|
|
204
|
+
describe "Immutability" do
|
|
205
|
+
it "value objects are immutable" do
|
|
206
|
+
expect(value_objects).to all(be_immutable)
|
|
207
|
+
expect(value_objects).to all(have_no_mutable_instance_variables)
|
|
208
|
+
end
|
|
209
|
+
|
|
210
|
+
it "aggregates are immutable" do
|
|
211
|
+
expect(aggregates).to all(be_immutable)
|
|
212
|
+
end
|
|
213
|
+
end
|
|
214
|
+
|
|
215
|
+
describe "Public API" do
|
|
216
|
+
it "loads the public engine module" do
|
|
217
|
+
module_name = container_class.name.split("::").first
|
|
218
|
+
const = Object.const_get(module_name)
|
|
219
|
+
expect(const).to be_truthy
|
|
220
|
+
end
|
|
221
|
+
|
|
222
|
+
# Note: We rely on Packwerk's enforce_privacy to prevent external access to
|
|
223
|
+
# infrastructure internals. No namespace-based hiding is required—all classes
|
|
224
|
+
# use the flat {Context}::{ClassName} convention.
|
|
225
|
+
end
|
|
226
|
+
|
|
227
|
+
describe "Architecture JSON Sync" do
|
|
228
|
+
def get_names(objects)
|
|
229
|
+
objects.map { |o| o.name.split("::").last }.sort
|
|
230
|
+
end
|
|
231
|
+
|
|
232
|
+
def json_names(path)
|
|
233
|
+
items = architecture_json.dig(*path) || []
|
|
234
|
+
items.map { |i| i.is_a?(Hash) ? i["name"] : i }.sort
|
|
235
|
+
end
|
|
236
|
+
|
|
237
|
+
describe "Aggregates" do
|
|
238
|
+
let(:json_aggregates) { json_names(["layers", "domain", "aggregates"]) }
|
|
239
|
+
let(:code_aggregates) { get_names(aggregates) }
|
|
240
|
+
|
|
241
|
+
it "match between JSON and Code" do
|
|
242
|
+
check_architecture_sync(
|
|
243
|
+
component_type: "Aggregates",
|
|
244
|
+
json_items: json_aggregates,
|
|
245
|
+
code_items: code_aggregates,
|
|
246
|
+
json_path: architecture_json_path,
|
|
247
|
+
add_to_code_hint: "Add these aggregate classes to the codebase",
|
|
248
|
+
add_to_json_hint: "Add these aggregates to #{architecture_json_path}"
|
|
249
|
+
)
|
|
250
|
+
end
|
|
251
|
+
end
|
|
252
|
+
|
|
253
|
+
describe "Events" do
|
|
254
|
+
let(:json_events) { json_names(["layers", "domain", "events"]) }
|
|
255
|
+
let(:code_events) { get_names(events) }
|
|
256
|
+
|
|
257
|
+
it "match between JSON and Code" do
|
|
258
|
+
check_architecture_sync(
|
|
259
|
+
component_type: "Events",
|
|
260
|
+
json_items: json_events,
|
|
261
|
+
code_items: code_events,
|
|
262
|
+
json_path: architecture_json_path,
|
|
263
|
+
add_to_code_hint: "Add these event classes to the codebase",
|
|
264
|
+
add_to_json_hint: "Add these events to #{architecture_json_path}"
|
|
265
|
+
)
|
|
266
|
+
end
|
|
267
|
+
end
|
|
268
|
+
|
|
269
|
+
describe "Ports" do
|
|
270
|
+
let(:json_ports) do
|
|
271
|
+
repos = architecture_json.dig("layers", "domain", "ports", "repositories") || []
|
|
272
|
+
external = (architecture_json.dig("layers", "domain", "ports", "external") || []).map { |p| p["name"] }
|
|
273
|
+
(repos + external).sort
|
|
274
|
+
end
|
|
275
|
+
let(:code_ports) { get_names(ports) }
|
|
276
|
+
|
|
277
|
+
it "match between JSON and Code" do
|
|
278
|
+
check_architecture_sync(
|
|
279
|
+
component_type: "Ports",
|
|
280
|
+
json_items: json_ports,
|
|
281
|
+
code_items: code_ports,
|
|
282
|
+
json_path: architecture_json_path,
|
|
283
|
+
add_to_code_hint: "Add these port interfaces to the domain layer",
|
|
284
|
+
add_to_json_hint: "Add these ports to #{architecture_json_path}"
|
|
285
|
+
)
|
|
286
|
+
end
|
|
287
|
+
end
|
|
288
|
+
|
|
289
|
+
describe "Services" do
|
|
290
|
+
let(:json_services) { json_names(["layers", "application", "services"]) }
|
|
291
|
+
let(:code_services) { get_names(services) }
|
|
292
|
+
|
|
293
|
+
it "match between JSON and Code" do
|
|
294
|
+
check_architecture_sync(
|
|
295
|
+
component_type: "Services",
|
|
296
|
+
json_items: json_services,
|
|
297
|
+
code_items: code_services,
|
|
298
|
+
json_path: architecture_json_path,
|
|
299
|
+
add_to_code_hint: "Add these service classes to the application layer",
|
|
300
|
+
add_to_json_hint: "Add these services to #{architecture_json_path}"
|
|
301
|
+
)
|
|
302
|
+
end
|
|
303
|
+
end
|
|
304
|
+
|
|
305
|
+
describe "Adapters" do
|
|
306
|
+
let(:json_adapters) do
|
|
307
|
+
persistence = (architecture_json.dig("layers", "infrastructure", "adapters", "persistence") || []).map { |a| a["name"] }
|
|
308
|
+
external = (architecture_json.dig("layers", "infrastructure", "adapters", "external") || []).map { |a| a["name"] }
|
|
309
|
+
(persistence + external).sort
|
|
310
|
+
end
|
|
311
|
+
let(:code_adapters) { get_names(adapters) }
|
|
312
|
+
|
|
313
|
+
it "match between JSON and Code" do
|
|
314
|
+
check_architecture_sync(
|
|
315
|
+
component_type: "Adapters",
|
|
316
|
+
json_items: json_adapters,
|
|
317
|
+
code_items: code_adapters,
|
|
318
|
+
json_path: architecture_json_path,
|
|
319
|
+
add_to_code_hint: "Add these adapter implementations to the infrastructure layer",
|
|
320
|
+
add_to_json_hint: "Add these adapters to #{architecture_json_path}"
|
|
321
|
+
)
|
|
322
|
+
end
|
|
323
|
+
end
|
|
324
|
+
|
|
325
|
+
describe "Controllers" do
|
|
326
|
+
let(:json_controllers) do
|
|
327
|
+
(architecture_json.dig("layers", "infrastructure", "entrypoints", "http") || []).map { |c| c["name"] }.sort
|
|
328
|
+
end
|
|
329
|
+
let(:code_controllers) do
|
|
330
|
+
get_names(controllers)
|
|
331
|
+
end
|
|
332
|
+
|
|
333
|
+
it "match between JSON and Code" do
|
|
334
|
+
check_architecture_sync(
|
|
335
|
+
component_type: "Controllers",
|
|
336
|
+
json_items: json_controllers,
|
|
337
|
+
code_items: code_controllers,
|
|
338
|
+
json_path: architecture_json_path,
|
|
339
|
+
add_to_code_hint: "Add these controller classes to app/controllers",
|
|
340
|
+
add_to_json_hint: "Add these controllers to #{architecture_json_path}"
|
|
341
|
+
)
|
|
342
|
+
end
|
|
343
|
+
end
|
|
344
|
+
end
|
|
345
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Rampart
|
|
4
|
+
module Testing
|
|
5
|
+
end
|
|
6
|
+
end
|
|
7
|
+
|
|
8
|
+
if defined?(RSpec)
|
|
9
|
+
require_relative "testing/architecture_matchers"
|
|
10
|
+
require_relative "testing/engine_architecture_shared_spec"
|
|
11
|
+
|
|
12
|
+
RSpec.configure do |config|
|
|
13
|
+
config.include Rampart::Testing::ArchitectureMatchers
|
|
14
|
+
end
|
|
15
|
+
end
|
data/lib/rampart.rb
ADDED
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
require "dry-types"
|
|
2
|
+
require "dry-struct"
|
|
3
|
+
require "dry-container"
|
|
4
|
+
require "dry-auto_inject"
|
|
5
|
+
require "dry-monads"
|
|
6
|
+
require "dry-initializer"
|
|
7
|
+
|
|
8
|
+
require_relative "rampart/version"
|
|
9
|
+
require_relative "rampart/support/types"
|
|
10
|
+
require_relative "rampart/support/result"
|
|
11
|
+
require_relative "rampart/support/container"
|
|
12
|
+
require_relative "rampart/domain/entity"
|
|
13
|
+
require_relative "rampart/domain/aggregate_root"
|
|
14
|
+
require_relative "rampart/domain/value_object"
|
|
15
|
+
require_relative "rampart/domain/domain_event"
|
|
16
|
+
require_relative "rampart/domain/domain_exception"
|
|
17
|
+
require_relative "rampart/domain/domain_service"
|
|
18
|
+
require_relative "rampart/application/command"
|
|
19
|
+
require_relative "rampart/application/query"
|
|
20
|
+
require_relative "rampart/application/service"
|
|
21
|
+
require_relative "rampart/application/transaction"
|
|
22
|
+
require_relative "rampart/ports/secondary_port"
|
|
23
|
+
require_relative "rampart/ports/event_bus_port"
|
|
24
|
+
require_relative "rampart/engine_loader"
|
|
25
|
+
require_relative "rampart/testing" if defined?(RSpec)
|
|
26
|
+
|
|
27
|
+
module Rampart
|
|
28
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: rampart-core
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.1.1
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Rampart Team
|
|
8
|
+
autorequire:
|
|
9
|
+
bindir: bin
|
|
10
|
+
cert_chain: []
|
|
11
|
+
date: 2026-01-05 00:00:00.000000000 Z
|
|
12
|
+
dependencies:
|
|
13
|
+
- !ruby/object:Gem::Dependency
|
|
14
|
+
name: dry-types
|
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
|
16
|
+
requirements:
|
|
17
|
+
- - "~>"
|
|
18
|
+
- !ruby/object:Gem::Version
|
|
19
|
+
version: '1.7'
|
|
20
|
+
type: :runtime
|
|
21
|
+
prerelease: false
|
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
23
|
+
requirements:
|
|
24
|
+
- - "~>"
|
|
25
|
+
- !ruby/object:Gem::Version
|
|
26
|
+
version: '1.7'
|
|
27
|
+
- !ruby/object:Gem::Dependency
|
|
28
|
+
name: dry-struct
|
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
|
30
|
+
requirements:
|
|
31
|
+
- - "~>"
|
|
32
|
+
- !ruby/object:Gem::Version
|
|
33
|
+
version: '1.6'
|
|
34
|
+
type: :runtime
|
|
35
|
+
prerelease: false
|
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
37
|
+
requirements:
|
|
38
|
+
- - "~>"
|
|
39
|
+
- !ruby/object:Gem::Version
|
|
40
|
+
version: '1.6'
|
|
41
|
+
- !ruby/object:Gem::Dependency
|
|
42
|
+
name: dry-container
|
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
|
44
|
+
requirements:
|
|
45
|
+
- - "~>"
|
|
46
|
+
- !ruby/object:Gem::Version
|
|
47
|
+
version: '0.11'
|
|
48
|
+
type: :runtime
|
|
49
|
+
prerelease: false
|
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
51
|
+
requirements:
|
|
52
|
+
- - "~>"
|
|
53
|
+
- !ruby/object:Gem::Version
|
|
54
|
+
version: '0.11'
|
|
55
|
+
- !ruby/object:Gem::Dependency
|
|
56
|
+
name: dry-auto_inject
|
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
|
58
|
+
requirements:
|
|
59
|
+
- - "~>"
|
|
60
|
+
- !ruby/object:Gem::Version
|
|
61
|
+
version: '1.0'
|
|
62
|
+
type: :runtime
|
|
63
|
+
prerelease: false
|
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
65
|
+
requirements:
|
|
66
|
+
- - "~>"
|
|
67
|
+
- !ruby/object:Gem::Version
|
|
68
|
+
version: '1.0'
|
|
69
|
+
- !ruby/object:Gem::Dependency
|
|
70
|
+
name: dry-monads
|
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
|
72
|
+
requirements:
|
|
73
|
+
- - "~>"
|
|
74
|
+
- !ruby/object:Gem::Version
|
|
75
|
+
version: '1.6'
|
|
76
|
+
type: :runtime
|
|
77
|
+
prerelease: false
|
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
79
|
+
requirements:
|
|
80
|
+
- - "~>"
|
|
81
|
+
- !ruby/object:Gem::Version
|
|
82
|
+
version: '1.6'
|
|
83
|
+
- !ruby/object:Gem::Dependency
|
|
84
|
+
name: dry-initializer
|
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
|
86
|
+
requirements:
|
|
87
|
+
- - "~>"
|
|
88
|
+
- !ruby/object:Gem::Version
|
|
89
|
+
version: '3.1'
|
|
90
|
+
type: :runtime
|
|
91
|
+
prerelease: false
|
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
93
|
+
requirements:
|
|
94
|
+
- - "~>"
|
|
95
|
+
- !ruby/object:Gem::Version
|
|
96
|
+
version: '3.1'
|
|
97
|
+
description: A pure-Ruby framework for building DDD applications with Hexagonal Architecture
|
|
98
|
+
email:
|
|
99
|
+
- team@rampart.dev
|
|
100
|
+
executables: []
|
|
101
|
+
extensions: []
|
|
102
|
+
extra_rdoc_files: []
|
|
103
|
+
files:
|
|
104
|
+
- LICENSE
|
|
105
|
+
- README.md
|
|
106
|
+
- lib/rampart.rb
|
|
107
|
+
- lib/rampart/application/command.rb
|
|
108
|
+
- lib/rampart/application/query.rb
|
|
109
|
+
- lib/rampart/application/service.rb
|
|
110
|
+
- lib/rampart/application/transaction.rb
|
|
111
|
+
- lib/rampart/domain/aggregate_root.rb
|
|
112
|
+
- lib/rampart/domain/domain_event.rb
|
|
113
|
+
- lib/rampart/domain/domain_exception.rb
|
|
114
|
+
- lib/rampart/domain/domain_service.rb
|
|
115
|
+
- lib/rampart/domain/entity.rb
|
|
116
|
+
- lib/rampart/domain/value_object.rb
|
|
117
|
+
- lib/rampart/engine_loader.rb
|
|
118
|
+
- lib/rampart/ports/event_bus_port.rb
|
|
119
|
+
- lib/rampart/ports/secondary_port.rb
|
|
120
|
+
- lib/rampart/support/container.rb
|
|
121
|
+
- lib/rampart/support/result.rb
|
|
122
|
+
- lib/rampart/support/types.rb
|
|
123
|
+
- lib/rampart/testing.rb
|
|
124
|
+
- lib/rampart/testing/architecture_matchers.rb
|
|
125
|
+
- lib/rampart/testing/engine_architecture_shared_spec.rb
|
|
126
|
+
- lib/rampart/version.rb
|
|
127
|
+
homepage: https://github.com/pacaplan/rampart
|
|
128
|
+
licenses:
|
|
129
|
+
- Apache-2.0
|
|
130
|
+
metadata:
|
|
131
|
+
homepage_uri: https://github.com/pacaplan/rampart
|
|
132
|
+
source_code_uri: https://github.com/pacaplan/rampart
|
|
133
|
+
post_install_message:
|
|
134
|
+
rdoc_options: []
|
|
135
|
+
require_paths:
|
|
136
|
+
- lib
|
|
137
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
138
|
+
requirements:
|
|
139
|
+
- - ">="
|
|
140
|
+
- !ruby/object:Gem::Version
|
|
141
|
+
version: 3.3.0
|
|
142
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
143
|
+
requirements:
|
|
144
|
+
- - ">="
|
|
145
|
+
- !ruby/object:Gem::Version
|
|
146
|
+
version: '0'
|
|
147
|
+
requirements: []
|
|
148
|
+
rubygems_version: 3.5.22
|
|
149
|
+
signing_key:
|
|
150
|
+
specification_version: 4
|
|
151
|
+
summary: Architecture on Rails
|
|
152
|
+
test_files: []
|