servactory 3.0.0.rc1 → 3.0.0.rc3

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: a81d492854b21f7fec57aae3bfea4093da15b1e1ffb3cad330761983471bc39c
4
- data.tar.gz: 54500fceb644df98c89d66d25ab53d9bc0317d0bde0f8216be364aaa630a710a
3
+ metadata.gz: 5972f03405d88ae923f1e000479449e281af67b9d22b52010d2131dc1023cc15
4
+ data.tar.gz: 6c7c495d158deee0453114fb637897a2431d7ce4efc4e522a0716ec28a7dd89b
5
5
  SHA512:
6
- metadata.gz: 695eceb38259b25d69e04a2614256a65be9e49ee1b7ea56064cb67f9e11e2a71143545bedaa37d3d669897d3d36091416f1d98a2ca1606c556391801275ecd19
7
- data.tar.gz: b4550c2c7c995049df7be5d6291e5b2f381b0647317b236d7cce91254f61fdbdbd29400cdbeb993da2bd63df88244c259eb26a6d662483b711ad3bebfd94d043
6
+ metadata.gz: 82e84edd70b3ee47a91944bd60e5d9bec1cf33b18ca5d008d40973685c796cfa31b48de2f0599764c864db535959cd86a073ed30725c1fe1af49a98ce4bd72ab
7
+ data.tar.gz: 585a53ba4491246e5e4aaec23568e074a2d142d467b9d44bc551d629bce2047fcfd99d89c0bdcb897e9a28e9f7037b9128396107fe6c01083ff0b4298ee11f71
@@ -16,17 +16,17 @@ module Servactory
16
16
  end
17
17
  end
18
18
 
19
- Stroma::Registry.register(:configuration, Configuration::DSL)
20
- Stroma::Registry.register(:info, Info::DSL)
21
- Stroma::Registry.register(:context, Context::DSL)
22
- Stroma::Registry.register(:inputs, Inputs::DSL)
23
- Stroma::Registry.register(:internals, Internals::DSL)
24
- Stroma::Registry.register(:outputs, Outputs::DSL)
25
- Stroma::Registry.register(:actions, Actions::DSL)
26
- Stroma::Registry.finalize!
19
+ ::Stroma::Registry.register(:configuration, Configuration::DSL)
20
+ ::Stroma::Registry.register(:info, Info::DSL)
21
+ ::Stroma::Registry.register(:context, Context::DSL)
22
+ ::Stroma::Registry.register(:inputs, Inputs::DSL)
23
+ ::Stroma::Registry.register(:internals, Internals::DSL)
24
+ ::Stroma::Registry.register(:outputs, Outputs::DSL)
25
+ ::Stroma::Registry.register(:actions, Actions::DSL)
26
+ ::Stroma::Registry.finalize!
27
27
 
28
28
  def self.included(base)
29
- base.include(Stroma::DSL)
29
+ base.include(::Stroma::DSL)
30
30
 
31
31
  Extensions.registry.each { |extension| base.include(extension) }
32
32
  end
@@ -136,11 +136,7 @@ module Servactory
136
136
  return if @define_methods.blank?
137
137
 
138
138
  @define_methods.map do |define_method|
139
- <<-RUBY.squish
140
- def #{define_method.name};
141
- #{define_method.content.call(option: @body)};
142
- end
143
- RUBY
139
+ "def #{define_method.name}; #{define_method.content.call(option: @body)}; end"
144
140
  end.join("; ")
145
141
  end
146
142
  end
@@ -3,19 +3,64 @@
3
3
  module Servactory
4
4
  module Maintenance
5
5
  module Attributes
6
+ # Collection wrapper for managing Option objects.
7
+ #
8
+ # ## Purpose
9
+ #
10
+ # OptionsCollection provides a unified interface for storing and querying
11
+ # Option instances associated with service attributes (inputs, internals, outputs).
12
+ # It wraps a Set to ensure uniqueness and delegates common enumeration methods.
13
+ #
14
+ # ## Usage
15
+ #
16
+ # The collection is used internally by Input, Internal, and Output classes
17
+ # to manage their registered options:
18
+ #
19
+ # ```ruby
20
+ # collection = OptionsCollection.new
21
+ # collection << Option.new(name: :required, ...)
22
+ # collection << Option.new(name: :types, ...)
23
+ #
24
+ # collection.names # => [:required, :types]
25
+ # collection.find_by(name: :required) # => Option instance
26
+ # ```
27
+ #
28
+ # ## Performance
29
+ #
30
+ # The collection uses memoization for frequently accessed data:
31
+ # - `validation_classes` - cached list of unique validation classes
32
+ # - `options_for_checks` - cached hash for validation pipeline
33
+ # - `options_index` - cached hash for O(1) lookups by name
34
+ #
6
35
  class OptionsCollection
7
36
  extend Forwardable
8
37
 
9
- def_delegators :@collection, :<<, :filter, :each, :map, :flat_map, :find, :empty?, :size
38
+ def_delegators :@collection,
39
+ :<<,
40
+ :filter,
41
+ :each, :each_with_object,
42
+ :map, :flat_map,
43
+ :find,
44
+ :size,
45
+ :empty?
10
46
 
47
+ # Initializes an empty collection.
48
+ #
49
+ # @return [OptionsCollection]
11
50
  def initialize
12
51
  @collection = Set.new
13
52
  end
14
53
 
54
+ # Returns all option names in the collection.
55
+ #
56
+ # @return [Array<Symbol>] list of option names
15
57
  def names
16
58
  map(&:name)
17
59
  end
18
60
 
61
+ # Returns unique validation classes from all options.
62
+ #
63
+ # @return [Array<Class>] deduplicated list of validation classes
19
64
  def validation_classes
20
65
  @validation_classes ||=
21
66
  filter { |option| option.validation_class.present? }
@@ -23,24 +68,47 @@ module Servactory
23
68
  .uniq
24
69
  end
25
70
 
71
+ # Returns options that need validation checks as a hash.
72
+ #
73
+ # @return [Hash{Symbol => Object}] option names mapped to normalized bodies
26
74
  def options_for_checks
27
- filter(&:need_for_checks?).to_h do |option|
75
+ @options_for_checks ||= filter(&:need_for_checks?).to_h do |option|
28
76
  [option.name, extract_normalized_body_from(option:)]
29
77
  end
30
78
  end
31
79
 
80
+ # Returns the first conflict code found among options.
81
+ #
82
+ # @return [Object, nil] conflict code or nil if no conflicts
32
83
  def defined_conflict_code
33
84
  flat_map { |option| resolve_conflicts_from(option:) }
34
85
  .reject(&:blank?)
35
86
  .first
36
87
  end
37
88
 
89
+ # Finds an option by its name using indexed lookup.
90
+ #
91
+ # @param name [Symbol] the option name to find
92
+ # @return [Option, nil] the found option or nil
38
93
  def find_by(name:)
39
- find { |option| option.name == name }
94
+ options_index[name]
40
95
  end
41
96
 
42
97
  private
43
98
 
99
+ # Builds and caches a hash index for O(1) option lookups.
100
+ #
101
+ # @return [Hash{Symbol => Option}] option names mapped to Option instances
102
+ def options_index
103
+ @options_index ||= each_with_object({}) do |option, index|
104
+ index[option.name] = option
105
+ end
106
+ end
107
+
108
+ # Extracts the normalized body value from an option.
109
+ #
110
+ # @param option [Option] the option to extract from
111
+ # @return [Object] the :is value if body is a Hash with :is key, otherwise the full body
44
112
  def extract_normalized_body_from(option:)
45
113
  body = option.body
46
114
  return body unless body.is_a?(Hash)
@@ -48,6 +116,10 @@ module Servactory
48
116
  body.key?(:is) ? body.fetch(:is) : body
49
117
  end
50
118
 
119
+ # Resolves conflict codes from an option's define_conflicts.
120
+ #
121
+ # @param option [Option] the option to check for conflicts
122
+ # @return [Array<Object>] array of conflict codes (may contain nils/blanks)
51
123
  def resolve_conflicts_from(option:)
52
124
  return [] unless option.define_conflicts
53
125
 
@@ -3,15 +3,15 @@
3
3
  module Servactory
4
4
  module ToolKit
5
5
  module DynamicOptions
6
- # Validates that attribute value matches one of the target values.
6
+ # Validates that Class-typed attribute value matches one of the target classes.
7
7
  #
8
8
  # ## Purpose
9
9
  #
10
- # Target provides exact value matching validation for attributes.
11
- # It ensures that the value is one of the specified target values,
12
- # supporting both single values and arrays of acceptable values.
13
- # This is useful for enum-like validations where only specific
14
- # values are allowed.
10
+ # Target provides class matching validation for Class-typed attributes.
11
+ # It ensures that the passed class is one of the specified target classes,
12
+ # supporting both single class and arrays of acceptable classes.
13
+ # This is useful for validating service classes, strategy patterns,
14
+ # or any scenario where specific classes are expected.
15
15
  #
16
16
  # ## Usage
17
17
  #
@@ -38,22 +38,18 @@ module Servactory
38
38
  #
39
39
  # ```ruby
40
40
  # class ProcessOrderService < ApplicationService::Base
41
- # input :status, type: Symbol, target: { in: [:pending, :processing, :complete] }
42
- # input :priority, type: Integer, target: { in: [1, 2, 3] }
43
- # input :model_class, type: Class, target: { in: [User, Admin] }
41
+ # input :service_class, type: Class, target: UserService
42
+ # input :handler_class, type: Class, target: [CreateHandler, UpdateHandler]
44
43
  # end
45
44
  # ```
46
45
  #
47
46
  # ## Simple Mode
48
47
  #
49
- # Specify target values directly:
48
+ # Specify target class directly or as an array:
50
49
  #
51
50
  # ```ruby
52
- # class ProcessOrderService < ApplicationService::Base
53
- # input :status, type: Symbol, target: :pending
54
- # input :priority, type: Integer, target: [1, 2, 3]
55
- # input :model_class, type: Class, target: [User, Admin]
56
- # end
51
+ # input :service_class, type: Class, target: UserService
52
+ # input :handler_class, type: Class, target: [CreateHandler, UpdateHandler]
57
53
  # ```
58
54
  #
59
55
  # ## Advanced Mode
@@ -64,19 +60,19 @@ module Servactory
64
60
  # With static message:
65
61
  #
66
62
  # ```ruby
67
- # input :status, type: Symbol, target: {
68
- # in: [:pending, :processing, :complete],
69
- # message: "Input `status` must be one of: pending, processing, complete"
63
+ # input :handler_class, type: Class, target: {
64
+ # in: [CreateHandler, UpdateHandler],
65
+ # message: "Input `handler_class` must be one of: CreateHandler, UpdateHandler"
70
66
  # }
71
67
  # ```
72
68
  #
73
69
  # With dynamic lambda message:
74
70
  #
75
71
  # ```ruby
76
- # input :status, type: Symbol, target: {
77
- # in: [:pending, :processing, :complete],
72
+ # input :handler_class, type: Class, target: {
73
+ # in: [CreateHandler, UpdateHandler],
78
74
  # message: lambda do |input:, value:, option_value:, **|
79
- # "Input `#{input.name}` has invalid value `#{value}`, expected: #{option_value.inspect}"
75
+ # "Input `#{input.name}` received `#{value}`, expected: #{Array(option_value).map(&:name).join(', ')}"
80
76
  # end
81
77
  # }
82
78
  # ```
@@ -88,8 +84,8 @@ module Servactory
88
84
  #
89
85
  # ## Validation Rules
90
86
  #
91
- # - Value must exactly match one of the target values
92
- # - Supports single value or array of values
87
+ # - Class must exactly match one of the target classes
88
+ # - Supports single class or array of classes
93
89
  # - Optional inputs with nil value validate against default
94
90
  #
95
91
  # ## Important Notes
@@ -5,7 +5,7 @@ module Servactory
5
5
  MAJOR = 3
6
6
  MINOR = 0
7
7
  PATCH = 0
8
- PRE = "rc1"
8
+ PRE = "rc3"
9
9
 
10
10
  STRING = [MAJOR, MINOR, PATCH, PRE].compact.join(".")
11
11
  end
data/lib/servactory.rb CHANGED
@@ -2,6 +2,8 @@
2
2
 
3
3
  require "zeitwerk"
4
4
 
5
+ require "stroma"
6
+
5
7
  require "active_support/all"
6
8
 
7
9
  require "uri"
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: servactory
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.0.0.rc1
4
+ version: 3.0.0.rc3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Anton Sokolov
@@ -23,34 +23,6 @@ dependencies:
23
23
  - - ">="
24
24
  - !ruby/object:Gem::Version
25
25
  version: '5.1'
26
- - !ruby/object:Gem::Dependency
27
- name: base64
28
- requirement: !ruby/object:Gem::Requirement
29
- requirements:
30
- - - ">="
31
- - !ruby/object:Gem::Version
32
- version: '0.2'
33
- type: :runtime
34
- prerelease: false
35
- version_requirements: !ruby/object:Gem::Requirement
36
- requirements:
37
- - - ">="
38
- - !ruby/object:Gem::Version
39
- version: '0.2'
40
- - !ruby/object:Gem::Dependency
41
- name: bigdecimal
42
- requirement: !ruby/object:Gem::Requirement
43
- requirements:
44
- - - ">="
45
- - !ruby/object:Gem::Version
46
- version: '3.1'
47
- type: :runtime
48
- prerelease: false
49
- version_requirements: !ruby/object:Gem::Requirement
50
- requirements:
51
- - - ">="
52
- - !ruby/object:Gem::Version
53
- version: '3.1'
54
26
  - !ruby/object:Gem::Dependency
55
27
  name: i18n
56
28
  requirement: !ruby/object:Gem::Requirement
@@ -66,7 +38,7 @@ dependencies:
66
38
  - !ruby/object:Gem::Version
67
39
  version: '1.14'
68
40
  - !ruby/object:Gem::Dependency
69
- name: mutex_m
41
+ name: stroma
70
42
  requirement: !ruby/object:Gem::Requirement
71
43
  requirements:
72
44
  - - ">="
@@ -312,23 +284,6 @@ files:
312
284
  - lib/servactory/outputs/dsl.rb
313
285
  - lib/servactory/outputs/output.rb
314
286
  - lib/servactory/result.rb
315
- - lib/servactory/stroma/dsl.rb
316
- - lib/servactory/stroma/entry.rb
317
- - lib/servactory/stroma/exceptions/base.rb
318
- - lib/servactory/stroma/exceptions/invalid_hook_type.rb
319
- - lib/servactory/stroma/exceptions/key_already_registered.rb
320
- - lib/servactory/stroma/exceptions/registry_frozen.rb
321
- - lib/servactory/stroma/exceptions/registry_not_finalized.rb
322
- - lib/servactory/stroma/exceptions/unknown_hook_target.rb
323
- - lib/servactory/stroma/hooks/applier.rb
324
- - lib/servactory/stroma/hooks/collection.rb
325
- - lib/servactory/stroma/hooks/factory.rb
326
- - lib/servactory/stroma/hooks/hook.rb
327
- - lib/servactory/stroma/registry.rb
328
- - lib/servactory/stroma/settings/collection.rb
329
- - lib/servactory/stroma/settings/registry_settings.rb
330
- - lib/servactory/stroma/settings/setting.rb
331
- - lib/servactory/stroma/state.rb
332
287
  - lib/servactory/test_kit/fake_type.rb
333
288
  - lib/servactory/test_kit/result.rb
334
289
  - lib/servactory/test_kit/rspec/helpers.rb
@@ -1,118 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Servactory
4
- module Stroma
5
- # Main integration point between Stroma and service classes.
6
- #
7
- # ## Purpose
8
- #
9
- # Module that provides the core Stroma functionality to service classes:
10
- # - Includes all registered DSL modules
11
- # - Provides extensions block for hook registration
12
- # - Handles inheritance with proper state copying
13
- #
14
- # ## Usage
15
- #
16
- # ```ruby
17
- # class MyService
18
- # include Servactory::Stroma::DSL
19
- #
20
- # extensions do
21
- # before :actions, MyExtension
22
- # end
23
- # end
24
- # ```
25
- #
26
- # ## Extension Settings Access
27
- #
28
- # Extensions access their settings through the stroma.settings hierarchy:
29
- #
30
- # ```ruby
31
- # # In ClassMethods:
32
- # stroma.settings[:actions][:authorization][:method_name] = :authorize
33
- #
34
- # # In InstanceMethods:
35
- # self.class.stroma.settings[:actions][:authorization][:method_name]
36
- # ```
37
- #
38
- # ## Integration
39
- #
40
- # Included by Servactory::DSL which is included by Servactory::Base.
41
- # Provides ClassMethods with: stroma, inherited, extensions.
42
- module DSL
43
- def self.included(base)
44
- base.extend(ClassMethods)
45
-
46
- Registry.entries.each do |entry|
47
- base.include(entry.extension)
48
- end
49
- end
50
-
51
- # Class-level methods for Stroma integration.
52
- #
53
- # ## Purpose
54
- #
55
- # Provides access to Stroma state and hooks DSL at the class level.
56
- # Handles proper duplication during inheritance.
57
- #
58
- # ## Key Methods
59
- #
60
- # - `stroma` - Access the State container
61
- # - `inherited` - Copy state to child classes
62
- # - `extensions` - DSL block for hook registration
63
- module ClassMethods
64
- def self.extended(base)
65
- base.instance_variable_set(:@stroma, State.new)
66
- end
67
-
68
- # Handles inheritance by duplicating Stroma state.
69
- #
70
- # Creates an independent copy of hooks and settings for the child class,
71
- # then applies all registered hooks to the child.
72
- #
73
- # @param child [Class] The child class being created
74
- # @return [void]
75
- def inherited(child)
76
- super
77
-
78
- child.instance_variable_set(:@stroma, stroma.dup)
79
-
80
- Hooks::Applier.new(child, child.stroma.hooks).apply!
81
- end
82
-
83
- # Returns the Stroma state for this service class.
84
- #
85
- # @return [State] The Stroma state container
86
- #
87
- # @example Accessing hooks
88
- # stroma.hooks.before(:actions)
89
- #
90
- # @example Accessing settings
91
- # stroma.settings[:actions][:authorization][:method_name]
92
- def stroma
93
- @stroma ||= State.new
94
- end
95
-
96
- private
97
-
98
- # DSL block for registering hooks.
99
- #
100
- # Evaluates the block in the context of a Hooks::Factory,
101
- # allowing before/after hook registration.
102
- #
103
- # @yield Block with before/after DSL calls
104
- # @return [void]
105
- #
106
- # @example
107
- # extensions do
108
- # before :actions, AuthorizationExtension
109
- # after :outputs, LoggingExtension
110
- # end
111
- def extensions(&block)
112
- @stroma_hooks_factory ||= Hooks::Factory.new(stroma.hooks)
113
- @stroma_hooks_factory.instance_eval(&block)
114
- end
115
- end
116
- end
117
- end
118
- end
@@ -1,32 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Servactory
4
- module Stroma
5
- # Represents a registered DSL entry in the Stroma registry.
6
- #
7
- # ## Purpose
8
- #
9
- # Immutable value object that holds information about a DSL module
10
- # registered in the Stroma system. Each entry has a unique key
11
- # and references a Module that will be included in service classes.
12
- #
13
- # ## Attributes
14
- #
15
- # - `key` (Symbol): Unique identifier for the DSL module (:inputs, :outputs, :actions)
16
- # - `extension` (Module): The actual DSL module to be included
17
- #
18
- # ## Usage
19
- #
20
- # Entries are created internally by Registry.register:
21
- #
22
- # ```ruby
23
- # Stroma::Registry.register(:inputs, Servactory::Inputs::DSL)
24
- # # Creates: Entry.new(key: :inputs, extension: Servactory::Inputs::DSL)
25
- # ```
26
- #
27
- # ## Immutability
28
- #
29
- # Entry is immutable (Data object) - once created, it cannot be modified.
30
- Entry = Data.define(:key, :extension)
31
- end
32
- end
@@ -1,45 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Servactory
4
- module Stroma
5
- module Exceptions
6
- # Base exception class for all Stroma-specific exceptions
7
- #
8
- # ## Purpose
9
- #
10
- # Serves as the parent class for all custom exceptions in the Stroma subsystem.
11
- # Allows catching all Stroma-related exceptions with a single rescue clause.
12
- #
13
- # ## Usage
14
- #
15
- # All Stroma exceptions inherit from this base class:
16
- #
17
- # ```ruby
18
- # begin
19
- # Servactory::Stroma::Registry.register(:custom, CustomModule)
20
- # rescue Servactory::Stroma::Exceptions::Base => e
21
- # # Catches any Stroma-specific exception
22
- # handle_stroma_error(e)
23
- # end
24
- # ```
25
- #
26
- # ## Integration
27
- #
28
- # Can be used in application error handlers for centralized error handling:
29
- #
30
- # ```ruby
31
- # rescue_from Servactory::Stroma::Exceptions::Base, with: :handle_stroma_error
32
- # ```
33
- #
34
- # ## Subclasses
35
- #
36
- # - RegistryFrozen - Raised when modifying a finalized registry
37
- # - RegistryNotFinalized - Raised when accessing registry before finalization
38
- # - KeyAlreadyRegistered - Raised when registering a duplicate key
39
- # - UnknownHookTarget - Raised when using an invalid hook target key
40
- # - InvalidHookType - Raised when using an invalid hook type (:before/:after)
41
- class Base < StandardError
42
- end
43
- end
44
- end
45
- end
@@ -1,29 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Servactory
4
- module Stroma
5
- module Exceptions
6
- # Raised when an invalid hook type is provided.
7
- #
8
- # ## Purpose
9
- #
10
- # Ensures that only valid hook types (:before, :after) are used
11
- # when creating Servactory::Stroma::Hooks::Hook objects. Provides fail-fast
12
- # behavior during class definition rather than silent failures at runtime.
13
- #
14
- # ## Usage
15
- #
16
- # ```ruby
17
- # # This will raise InvalidHookType:
18
- # Servactory::Stroma::Hooks::Hook.new(
19
- # type: :invalid,
20
- # target_key: :actions,
21
- # extension: MyModule
22
- # )
23
- # # => Servactory::Stroma::Exceptions::InvalidHookType:
24
- # # Invalid hook type: :invalid. Valid types: :before, :after
25
- # ```
26
- class InvalidHookType < Base; end
27
- end
28
- end
29
- end
@@ -1,32 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Servactory
4
- module Stroma
5
- module Exceptions
6
- # Raised when registering a duplicate key in the registry
7
- #
8
- # ## Purpose
9
- #
10
- # Indicates that a DSL module key has already been registered.
11
- # Each DSL module must have a unique key in the registry.
12
- #
13
- # ## Usage
14
- #
15
- # Raised when attempting to register a duplicate key:
16
- #
17
- # ```ruby
18
- # Servactory::Stroma::Registry.register(:inputs, Inputs::DSL)
19
- # Servactory::Stroma::Registry.register(:inputs, AnotherModule)
20
- # # Raises: Servactory::Stroma::Exceptions::KeyAlreadyRegistered
21
- # ```
22
- #
23
- # ## Integration
24
- #
25
- # This exception typically indicates a configuration error - each
26
- # DSL module should only be registered once. Check for duplicate
27
- # registrations in your initialization code.
28
- class KeyAlreadyRegistered < Base
29
- end
30
- end
31
- end
32
- end
@@ -1,33 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Servactory
4
- module Stroma
5
- module Exceptions
6
- # Raised when attempting to modify a finalized registry
7
- #
8
- # ## Purpose
9
- #
10
- # Indicates that the Stroma::Registry has been finalized and cannot accept
11
- # new module registrations. The registry is finalized once during gem
12
- # initialization and remains immutable thereafter.
13
- #
14
- # ## Usage
15
- #
16
- # Raised when attempting to register modules after finalize!:
17
- #
18
- # ```ruby
19
- # Servactory::Stroma::Registry.finalize!
20
- # Servactory::Stroma::Registry.register(:custom, CustomModule)
21
- # # Raises: Servactory::Stroma::Exceptions::RegistryFrozen
22
- # ```
23
- #
24
- # ## Integration
25
- #
26
- # This exception typically indicates a programming error - module
27
- # registration should only occur during application boot, before
28
- # any service classes are defined.
29
- class RegistryFrozen < Base
30
- end
31
- end
32
- end
33
- end