treaty 0.18.0 → 0.19.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.
- checksums.yaml +4 -4
- data/README.md +1 -1
- data/config/locales/en.yml +3 -3
- data/lib/treaty/engine.rb +1 -1
- data/lib/treaty/{attribute/entity → entity/attribute}/attribute.rb +4 -4
- data/lib/treaty/entity/attribute/base.rb +184 -0
- data/lib/treaty/entity/attribute/builder/base.rb +275 -0
- data/lib/treaty/entity/attribute/collection.rb +67 -0
- data/lib/treaty/entity/attribute/dsl.rb +92 -0
- data/lib/treaty/entity/attribute/helper_mapper.rb +74 -0
- data/lib/treaty/entity/attribute/option/base.rb +190 -0
- data/lib/treaty/entity/attribute/option/conditionals/base.rb +92 -0
- data/lib/treaty/entity/attribute/option/conditionals/if_conditional.rb +136 -0
- data/lib/treaty/entity/attribute/option/conditionals/unless_conditional.rb +153 -0
- data/lib/treaty/entity/attribute/option/modifiers/as_modifier.rb +93 -0
- data/lib/treaty/entity/attribute/option/modifiers/cast_modifier.rb +285 -0
- data/lib/treaty/entity/attribute/option/modifiers/computed_modifier.rb +128 -0
- data/lib/treaty/entity/attribute/option/modifiers/default_modifier.rb +105 -0
- data/lib/treaty/entity/attribute/option/modifiers/transform_modifier.rb +114 -0
- data/lib/treaty/entity/attribute/option/registry.rb +157 -0
- data/lib/treaty/entity/attribute/option/registry_initializer.rb +117 -0
- data/lib/treaty/entity/attribute/option/validators/format_validator.rb +222 -0
- data/lib/treaty/entity/attribute/option/validators/inclusion_validator.rb +94 -0
- data/lib/treaty/entity/attribute/option/validators/required_validator.rb +100 -0
- data/lib/treaty/entity/attribute/option/validators/type_validator.rb +219 -0
- data/lib/treaty/entity/attribute/option_normalizer.rb +168 -0
- data/lib/treaty/entity/attribute/option_orchestrator.rb +192 -0
- data/lib/treaty/entity/attribute/validation/attribute_validator.rb +147 -0
- data/lib/treaty/entity/attribute/validation/base.rb +76 -0
- data/lib/treaty/entity/attribute/validation/nested_array_validator.rb +207 -0
- data/lib/treaty/entity/attribute/validation/nested_object_validator.rb +105 -0
- data/lib/treaty/entity/attribute/validation/nested_transformer.rb +432 -0
- data/lib/treaty/entity/attribute/validation/orchestrator/base.rb +262 -0
- data/lib/treaty/entity/base.rb +90 -0
- data/lib/treaty/entity/builder.rb +44 -0
- data/lib/treaty/{info/entity → entity/info}/builder.rb +8 -8
- data/lib/treaty/{info/entity → entity/info}/dsl.rb +2 -2
- data/lib/treaty/{info/entity → entity/info}/result.rb +2 -2
- data/lib/treaty/entity.rb +7 -79
- data/lib/treaty/request/attribute/attribute.rb +1 -1
- data/lib/treaty/request/attribute/builder.rb +2 -2
- data/lib/treaty/request/entity.rb +1 -1
- data/lib/treaty/request/factory.rb +5 -5
- data/lib/treaty/request/validator.rb +1 -1
- data/lib/treaty/response/attribute/attribute.rb +1 -1
- data/lib/treaty/response/attribute/builder.rb +2 -2
- data/lib/treaty/response/entity.rb +1 -1
- data/lib/treaty/response/factory.rb +5 -5
- data/lib/treaty/response/validator.rb +1 -1
- data/lib/treaty/version.rb +1 -1
- metadata +35 -34
- data/lib/treaty/attribute/base.rb +0 -182
- data/lib/treaty/attribute/builder/base.rb +0 -273
- data/lib/treaty/attribute/collection.rb +0 -65
- data/lib/treaty/attribute/dsl.rb +0 -90
- data/lib/treaty/attribute/entity/builder.rb +0 -46
- data/lib/treaty/attribute/helper_mapper.rb +0 -72
- data/lib/treaty/attribute/option/base.rb +0 -188
- data/lib/treaty/attribute/option/conditionals/base.rb +0 -90
- data/lib/treaty/attribute/option/conditionals/if_conditional.rb +0 -134
- data/lib/treaty/attribute/option/conditionals/unless_conditional.rb +0 -151
- data/lib/treaty/attribute/option/modifiers/as_modifier.rb +0 -91
- data/lib/treaty/attribute/option/modifiers/cast_modifier.rb +0 -283
- data/lib/treaty/attribute/option/modifiers/computed_modifier.rb +0 -126
- data/lib/treaty/attribute/option/modifiers/default_modifier.rb +0 -103
- data/lib/treaty/attribute/option/modifiers/transform_modifier.rb +0 -112
- data/lib/treaty/attribute/option/registry.rb +0 -155
- data/lib/treaty/attribute/option/registry_initializer.rb +0 -115
- data/lib/treaty/attribute/option/validators/format_validator.rb +0 -220
- data/lib/treaty/attribute/option/validators/inclusion_validator.rb +0 -92
- data/lib/treaty/attribute/option/validators/required_validator.rb +0 -98
- data/lib/treaty/attribute/option/validators/type_validator.rb +0 -217
- data/lib/treaty/attribute/option_normalizer.rb +0 -166
- data/lib/treaty/attribute/option_orchestrator.rb +0 -190
- data/lib/treaty/attribute/validation/attribute_validator.rb +0 -145
- data/lib/treaty/attribute/validation/base.rb +0 -74
- data/lib/treaty/attribute/validation/nested_array_validator.rb +0 -205
- data/lib/treaty/attribute/validation/nested_object_validator.rb +0 -103
- data/lib/treaty/attribute/validation/nested_transformer.rb +0 -430
- data/lib/treaty/attribute/validation/orchestrator/base.rb +0 -260
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Treaty
|
|
4
|
+
module Entity
|
|
5
|
+
module Attribute
|
|
6
|
+
module Option
|
|
7
|
+
module Modifiers
|
|
8
|
+
# Sets default values for attributes when value is nil.
|
|
9
|
+
#
|
|
10
|
+
# ## Usage Examples
|
|
11
|
+
#
|
|
12
|
+
# Simple mode with static value:
|
|
13
|
+
# integer :limit, default: 12
|
|
14
|
+
# string :status, default: "pending"
|
|
15
|
+
# boolean :active, default: false
|
|
16
|
+
#
|
|
17
|
+
# Simple mode with dynamic value (Proc):
|
|
18
|
+
# datetime :created_at, default: -> { Time.current }
|
|
19
|
+
# string :uuid, default: -> { SecureRandom.uuid }
|
|
20
|
+
#
|
|
21
|
+
# Advanced mode:
|
|
22
|
+
# integer :limit, default: { is: 12, message: nil }
|
|
23
|
+
#
|
|
24
|
+
# ## Use Cases
|
|
25
|
+
#
|
|
26
|
+
# 1. **Response defaults** (most common):
|
|
27
|
+
# ```ruby
|
|
28
|
+
# response 200 do
|
|
29
|
+
# object :meta do
|
|
30
|
+
# integer :limit, default: 12
|
|
31
|
+
# integer :page, default: 1
|
|
32
|
+
# end
|
|
33
|
+
# end
|
|
34
|
+
# # Service returns: { meta: { page: 1 } }
|
|
35
|
+
# # Output: { meta: { page: 1, limit: 12 } }
|
|
36
|
+
# ```
|
|
37
|
+
#
|
|
38
|
+
# 2. **Request defaults**:
|
|
39
|
+
# ```ruby
|
|
40
|
+
# request do
|
|
41
|
+
# string :format, default: "json"
|
|
42
|
+
# end
|
|
43
|
+
# # Input: {}
|
|
44
|
+
# # Service receives: { format: "json" }
|
|
45
|
+
# ```
|
|
46
|
+
#
|
|
47
|
+
# ## Important Notes
|
|
48
|
+
#
|
|
49
|
+
# - Default is applied ONLY when value is nil
|
|
50
|
+
# - Empty strings, empty arrays, false are NOT replaced
|
|
51
|
+
# - Proc defaults are called at transformation time
|
|
52
|
+
# - Procs receive no arguments
|
|
53
|
+
#
|
|
54
|
+
# ## Array and Object Types
|
|
55
|
+
#
|
|
56
|
+
# NOTE: DO NOT use `default: []` or `default: {}` for array/object types!
|
|
57
|
+
# Array and object types automatically represent empty collections.
|
|
58
|
+
#
|
|
59
|
+
# Incorrect:
|
|
60
|
+
# array :tags, default: [] # Wrong! Redundant
|
|
61
|
+
# object :meta, default: {} # Wrong! Redundant
|
|
62
|
+
#
|
|
63
|
+
# Correct:
|
|
64
|
+
# array :tags # Automatically handles empty array
|
|
65
|
+
# object :meta # Automatically handles empty object
|
|
66
|
+
#
|
|
67
|
+
# ## Advanced Mode
|
|
68
|
+
#
|
|
69
|
+
# Schema format: `{ is: value_or_proc, message: nil }`
|
|
70
|
+
class DefaultModifier < Treaty::Entity::Attribute::Option::Base
|
|
71
|
+
# Validates schema (no validation needed)
|
|
72
|
+
# Default value can be any type
|
|
73
|
+
#
|
|
74
|
+
# @return [void]
|
|
75
|
+
def validate_schema!
|
|
76
|
+
# Schema structure is already normalized by OptionNormalizer.
|
|
77
|
+
# Default value can be any type, so nothing specific to validate here.
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
# Applies default value if current value is nil
|
|
81
|
+
# Empty strings, empty arrays, and false are NOT replaced
|
|
82
|
+
#
|
|
83
|
+
# @param value [Object] The current value
|
|
84
|
+
# @param _root_data [Hash] Unused root data parameter
|
|
85
|
+
# @return [Object] Default value if original is nil, otherwise original value
|
|
86
|
+
def transform_value(value, _root_data = {})
|
|
87
|
+
# Only apply default if value is nil
|
|
88
|
+
# Empty strings, empty arrays, false are NOT replaced
|
|
89
|
+
return value unless value.nil?
|
|
90
|
+
|
|
91
|
+
default_value = option_value
|
|
92
|
+
|
|
93
|
+
# If default value is a Proc, call it to get the value
|
|
94
|
+
if default_value.is_a?(Proc)
|
|
95
|
+
default_value.call
|
|
96
|
+
else
|
|
97
|
+
default_value
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
end
|
|
102
|
+
end
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
end
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Treaty
|
|
4
|
+
module Entity
|
|
5
|
+
module Attribute
|
|
6
|
+
module Option
|
|
7
|
+
module Modifiers
|
|
8
|
+
# Transforms attribute values using custom lambda functions.
|
|
9
|
+
#
|
|
10
|
+
# ## Usage Examples
|
|
11
|
+
#
|
|
12
|
+
# Simple mode:
|
|
13
|
+
# integer :amount, transform: ->(value:) { value * 100 }
|
|
14
|
+
# string :title, transform: ->(value:) { value.strip.upcase }
|
|
15
|
+
#
|
|
16
|
+
# Advanced mode with custom error message:
|
|
17
|
+
# integer :amount, transform: {
|
|
18
|
+
# is: ->(value:) { value * 100 },
|
|
19
|
+
# message: "Failed to transform amount"
|
|
20
|
+
# }
|
|
21
|
+
#
|
|
22
|
+
# ## Use Cases
|
|
23
|
+
#
|
|
24
|
+
# 1. **Request transformation**:
|
|
25
|
+
# ```ruby
|
|
26
|
+
# request do
|
|
27
|
+
# integer :amount_cents, transform: ->(value:) { value * 100 }
|
|
28
|
+
# end
|
|
29
|
+
# # Input: { amount_cents: 10 }
|
|
30
|
+
# # Service receives: { amount_cents: 1000 }
|
|
31
|
+
# ```
|
|
32
|
+
#
|
|
33
|
+
# 2. **Response transformation**:
|
|
34
|
+
# ```ruby
|
|
35
|
+
# response 200 do
|
|
36
|
+
# string :title, transform: ->(value:) { value.titleize }
|
|
37
|
+
# end
|
|
38
|
+
# # Service returns: { title: "hello world" }
|
|
39
|
+
# # Output: { title: "Hello World" }
|
|
40
|
+
# ```
|
|
41
|
+
#
|
|
42
|
+
# 3. **Complex transformations**:
|
|
43
|
+
# ```ruby
|
|
44
|
+
# string :email, transform: ->(value:) { value.downcase.strip }
|
|
45
|
+
# datetime :timestamp, transform: ->(value:) { value.iso8601 }
|
|
46
|
+
# ```
|
|
47
|
+
#
|
|
48
|
+
# ## Important Notes
|
|
49
|
+
#
|
|
50
|
+
# - Lambda must accept named argument `value:`
|
|
51
|
+
# - All exceptions raised in lambda are caught and re-raised as Validation errors
|
|
52
|
+
# - Transformation is applied during Phase 3 (after validation)
|
|
53
|
+
# - Can be combined with other options (required, default, as, etc.)
|
|
54
|
+
#
|
|
55
|
+
# ## Error Handling
|
|
56
|
+
#
|
|
57
|
+
# If the lambda raises any exception, it's caught and converted to a
|
|
58
|
+
# Treaty::Exceptions::Validation with appropriate error message.
|
|
59
|
+
#
|
|
60
|
+
# ## Advanced Mode
|
|
61
|
+
#
|
|
62
|
+
# Schema format: `{ is: lambda, message: nil }`
|
|
63
|
+
class TransformModifier < Treaty::Entity::Attribute::Option::Base
|
|
64
|
+
# Validates that transform value is a lambda
|
|
65
|
+
#
|
|
66
|
+
# @raise [Treaty::Exceptions::Validation] If transform is not a Proc/lambda
|
|
67
|
+
# @return [void]
|
|
68
|
+
def validate_schema!
|
|
69
|
+
transform_lambda = option_value
|
|
70
|
+
|
|
71
|
+
return if transform_lambda.respond_to?(:call)
|
|
72
|
+
|
|
73
|
+
raise Treaty::Exceptions::Validation,
|
|
74
|
+
I18n.t(
|
|
75
|
+
"treaty.attributes.modifiers.transform.invalid_type",
|
|
76
|
+
attribute: @attribute_name,
|
|
77
|
+
type: transform_lambda.class
|
|
78
|
+
)
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
# Applies transformation to the value using the provided lambda
|
|
82
|
+
# Catches all exceptions and re-raises as Validation errors
|
|
83
|
+
# Skips transformation for nil values (handled by RequiredValidator)
|
|
84
|
+
#
|
|
85
|
+
# @param value [Object] The current value
|
|
86
|
+
# @param _root_data [Hash] Unused root data parameter
|
|
87
|
+
# @return [Object] Transformed value
|
|
88
|
+
def transform_value(value, _root_data = {}) # rubocop:disable Metrics/MethodLength
|
|
89
|
+
return value if value.nil? # Transform doesn't modify nil, required validator handles it.
|
|
90
|
+
|
|
91
|
+
transform_lambda = option_value
|
|
92
|
+
|
|
93
|
+
# Call lambda with named argument
|
|
94
|
+
transform_lambda.call(value:)
|
|
95
|
+
rescue StandardError => e
|
|
96
|
+
attributes = {
|
|
97
|
+
attribute: @attribute_name,
|
|
98
|
+
error: e.message
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
# Catch all exceptions from lambda execution
|
|
102
|
+
error_message = resolve_custom_message(**attributes) || I18n.t(
|
|
103
|
+
"treaty.attributes.modifiers.transform.execution_error",
|
|
104
|
+
**attributes
|
|
105
|
+
)
|
|
106
|
+
|
|
107
|
+
raise Treaty::Exceptions::Validation, error_message
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
end
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Treaty
|
|
4
|
+
module Entity
|
|
5
|
+
module Attribute
|
|
6
|
+
module Option
|
|
7
|
+
# Central registry for all option processors (validators, modifiers, and conditionals).
|
|
8
|
+
#
|
|
9
|
+
# ## Purpose
|
|
10
|
+
#
|
|
11
|
+
# Provides a centralized registry pattern for managing all option processors.
|
|
12
|
+
# Enables dynamic discovery and extensibility of the option system.
|
|
13
|
+
#
|
|
14
|
+
# ## Responsibilities
|
|
15
|
+
#
|
|
16
|
+
# 1. **Registration** - Stores option processor classes
|
|
17
|
+
# 2. **Retrieval** - Provides access to registered processors
|
|
18
|
+
# 3. **Categorization** - Organizes processors by category (validator/modifier/conditional)
|
|
19
|
+
# 4. **Validation** - Checks if options are registered
|
|
20
|
+
#
|
|
21
|
+
# ## Registered Options
|
|
22
|
+
#
|
|
23
|
+
# ### Validators (sorted by position)
|
|
24
|
+
# - `:type` → TypeValidator (position: 100)
|
|
25
|
+
# - `:required` → RequiredValidator (position: 200)
|
|
26
|
+
# - `:inclusion` → InclusionValidator (position: 300)
|
|
27
|
+
# - `:format` → FormatValidator (position: 400)
|
|
28
|
+
#
|
|
29
|
+
# ### Modifiers (sorted by position)
|
|
30
|
+
# - `:transform` → TransformModifier (position: 500)
|
|
31
|
+
# - `:cast` → CastModifier (position: 600)
|
|
32
|
+
# - `:computed` → ComputedModifier (position: 700)
|
|
33
|
+
# - `:default` → DefaultModifier (position: 800)
|
|
34
|
+
# - `:as` → AsModifier (position: 900)
|
|
35
|
+
#
|
|
36
|
+
# ### Conditionals (no position - handled separately)
|
|
37
|
+
# - `:if` → IfConditional
|
|
38
|
+
# - `:unless` → UnlessConditional
|
|
39
|
+
#
|
|
40
|
+
# ## Usage
|
|
41
|
+
#
|
|
42
|
+
# Registration (done in RegistryInitializer):
|
|
43
|
+
# Registry.register(:required, RequiredValidator, category: :validator, position: 200)
|
|
44
|
+
# Registry.register(:if, IfConditional, category: :conditional)
|
|
45
|
+
#
|
|
46
|
+
# Retrieval (done in OptionOrchestrator):
|
|
47
|
+
# processor_class = Registry.processor_for(:required)
|
|
48
|
+
# processor = processor_class.new(...)
|
|
49
|
+
#
|
|
50
|
+
# ## Extensibility
|
|
51
|
+
#
|
|
52
|
+
# To add a new option:
|
|
53
|
+
# 1. Create processor class inheriting from Option::Base
|
|
54
|
+
# 2. Register it: `Registry.register(:my_option, MyProcessor, category: :validator)`
|
|
55
|
+
# 3. Option becomes available in DSL immediately
|
|
56
|
+
#
|
|
57
|
+
# ## Architecture
|
|
58
|
+
#
|
|
59
|
+
# Works with:
|
|
60
|
+
# - RegistryInitializer - Populates registry with built-in options
|
|
61
|
+
# - OptionOrchestrator - Uses registry to build processors
|
|
62
|
+
# - Option::Base - Base class for all registered processors
|
|
63
|
+
class Registry
|
|
64
|
+
class << self
|
|
65
|
+
# Register an option processor
|
|
66
|
+
#
|
|
67
|
+
# @param option_name [Symbol] The name of the option (e.g., :required, :as, :default)
|
|
68
|
+
# @param processor_class [Class] The processor class
|
|
69
|
+
# @param category [Symbol] The category (:validator, :modifier, or :conditional)
|
|
70
|
+
# @param position [Integer, nil] Execution order position (nil for conditionals)
|
|
71
|
+
def register(option_name, processor_class, category:, position: nil)
|
|
72
|
+
registry[option_name] = {
|
|
73
|
+
processor_class:,
|
|
74
|
+
category:,
|
|
75
|
+
position:
|
|
76
|
+
}
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
# Get processor class for an option
|
|
80
|
+
#
|
|
81
|
+
# @param option_name [Symbol] The name of the option
|
|
82
|
+
# @return [Class, nil] The processor class or nil if not found
|
|
83
|
+
def processor_for(option_name)
|
|
84
|
+
registry.dig(option_name, :processor_class)
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
# Get category for an option
|
|
88
|
+
#
|
|
89
|
+
# @param option_name [Symbol] The name of the option
|
|
90
|
+
# @return [Symbol, nil] The category (:validator or :modifier) or nil if not found
|
|
91
|
+
def category_for(option_name)
|
|
92
|
+
registry.dig(option_name, :category)
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
# Get position for an option
|
|
96
|
+
#
|
|
97
|
+
# @param option_name [Symbol] The name of the option
|
|
98
|
+
# @return [Integer, nil] The execution order position or nil if not set
|
|
99
|
+
def position_for(option_name)
|
|
100
|
+
registry.dig(option_name, :position)
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
# Check if an option is registered
|
|
104
|
+
#
|
|
105
|
+
# @param option_name [Symbol] The name of the option
|
|
106
|
+
# @return [Boolean]
|
|
107
|
+
def registered?(option_name)
|
|
108
|
+
registry.key?(option_name)
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
# Get all registered option names
|
|
112
|
+
#
|
|
113
|
+
# @return [Array<Symbol>]
|
|
114
|
+
def all_options
|
|
115
|
+
registry.keys
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
# Get all validators
|
|
119
|
+
#
|
|
120
|
+
# @return [Hash] Hash of option_name => processor_class for validators
|
|
121
|
+
def validators
|
|
122
|
+
registry.select { |_, info| info.fetch(:category) == :validator }
|
|
123
|
+
.transform_values { |info| info.fetch(:processor_class) }
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
# Get all modifiers
|
|
127
|
+
#
|
|
128
|
+
# @return [Hash] Hash of option_name => processor_class for modifiers
|
|
129
|
+
def modifiers
|
|
130
|
+
registry.select { |_, info| info.fetch(:category) == :modifier }
|
|
131
|
+
.transform_values { |info| info.fetch(:processor_class) }
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
# Get all conditionals
|
|
135
|
+
#
|
|
136
|
+
# @return [Hash] Hash of option_name => processor_class for conditionals
|
|
137
|
+
def conditionals
|
|
138
|
+
registry.select { |_, info| info.fetch(:category) == :conditional }
|
|
139
|
+
.transform_values { |info| info.fetch(:processor_class) }
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
# Reset registry (mainly for testing)
|
|
143
|
+
def reset!
|
|
144
|
+
@registry = nil
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
private
|
|
148
|
+
|
|
149
|
+
def registry
|
|
150
|
+
@registry ||= {}
|
|
151
|
+
end
|
|
152
|
+
end
|
|
153
|
+
end
|
|
154
|
+
end
|
|
155
|
+
end
|
|
156
|
+
end
|
|
157
|
+
end
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Treaty
|
|
4
|
+
module Entity
|
|
5
|
+
module Attribute
|
|
6
|
+
module Option
|
|
7
|
+
# Initializes and registers all built-in option processors with the Registry.
|
|
8
|
+
#
|
|
9
|
+
# ## Purpose
|
|
10
|
+
#
|
|
11
|
+
# Centralized registration point for all option processors (validators, modifiers, and conditionals).
|
|
12
|
+
# Automatically registers all built-in options when loaded.
|
|
13
|
+
#
|
|
14
|
+
# ## Responsibilities
|
|
15
|
+
#
|
|
16
|
+
# 1. **Validator Registration** - Registers all built-in validators
|
|
17
|
+
# 2. **Modifier Registration** - Registers all built-in modifiers
|
|
18
|
+
# 3. **Conditional Registration** - Registers all built-in conditionals
|
|
19
|
+
# 4. **Auto-Loading** - Executes automatically when file is loaded
|
|
20
|
+
#
|
|
21
|
+
# ## Built-in Validators (sorted by position)
|
|
22
|
+
#
|
|
23
|
+
# - `:type` → TypeValidator (position: 100) - Validates value types
|
|
24
|
+
# - `:required` → RequiredValidator (position: 200) - Validates required/optional attributes
|
|
25
|
+
# - `:inclusion` → InclusionValidator (position: 300) - Validates value is in allowed set
|
|
26
|
+
# - `:format` → FormatValidator (position: 400) - Validates string values match specific formats
|
|
27
|
+
#
|
|
28
|
+
# ## Built-in Modifiers (sorted by position)
|
|
29
|
+
#
|
|
30
|
+
# - `:transform` → TransformModifier (position: 500) - Transforms values using custom lambdas
|
|
31
|
+
# - `:cast` → CastModifier (position: 600) - Converts values between types automatically
|
|
32
|
+
# - `:computed` → ComputedModifier (position: 700) - Computes values from all raw data
|
|
33
|
+
# - `:default` → DefaultModifier (position: 800) - Provides default values
|
|
34
|
+
# - `:as` → AsModifier (position: 900) - Renames attributes
|
|
35
|
+
#
|
|
36
|
+
# ## Built-in Conditionals (no position - handled separately)
|
|
37
|
+
#
|
|
38
|
+
# - `:if` → IfConditional - Conditionally includes attributes based on runtime data
|
|
39
|
+
# - `:unless` → UnlessConditional - Conditionally excludes attributes based on runtime data
|
|
40
|
+
#
|
|
41
|
+
# ## Auto-Registration
|
|
42
|
+
#
|
|
43
|
+
# This file calls `register_all!` when loaded, ensuring all processors
|
|
44
|
+
# are available immediately.
|
|
45
|
+
#
|
|
46
|
+
# ## Adding New Options
|
|
47
|
+
#
|
|
48
|
+
# To add a new option processor:
|
|
49
|
+
#
|
|
50
|
+
# 1. Create the processor class (inherit from Option::Base)
|
|
51
|
+
# 2. Add registration call here:
|
|
52
|
+
# ```ruby
|
|
53
|
+
# def register_validators!
|
|
54
|
+
# Registry.register(:required, Validators::RequiredValidator, category: :validator)
|
|
55
|
+
# Registry.register(:my_option, Validators::MyValidator, category: :validator)
|
|
56
|
+
# end
|
|
57
|
+
# ```
|
|
58
|
+
#
|
|
59
|
+
# ## Architecture
|
|
60
|
+
#
|
|
61
|
+
# Works with:
|
|
62
|
+
# - Registry - Stores processor registrations
|
|
63
|
+
# - Option::Base - Base class for all processors
|
|
64
|
+
# - OptionOrchestrator - Uses registered processors
|
|
65
|
+
module RegistryInitializer
|
|
66
|
+
class << self
|
|
67
|
+
# Registers all built-in option processors
|
|
68
|
+
# Called automatically when this file is loaded
|
|
69
|
+
#
|
|
70
|
+
# @return [void]
|
|
71
|
+
def register_all!
|
|
72
|
+
register_validators!
|
|
73
|
+
register_modifiers!
|
|
74
|
+
register_conditionals!
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
private
|
|
78
|
+
|
|
79
|
+
# Registers all built-in validators
|
|
80
|
+
# Position determines execution order (lower = earlier)
|
|
81
|
+
#
|
|
82
|
+
# @return [void]
|
|
83
|
+
def register_validators!
|
|
84
|
+
Registry.register(:type, Validators::TypeValidator, category: :validator, position: 100)
|
|
85
|
+
Registry.register(:required, Validators::RequiredValidator, category: :validator, position: 200)
|
|
86
|
+
Registry.register(:inclusion, Validators::InclusionValidator, category: :validator, position: 300)
|
|
87
|
+
Registry.register(:format, Validators::FormatValidator, category: :validator, position: 400)
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
# Registers all built-in modifiers
|
|
91
|
+
# Position determines execution order (lower = earlier)
|
|
92
|
+
#
|
|
93
|
+
# @return [void]
|
|
94
|
+
def register_modifiers!
|
|
95
|
+
Registry.register(:transform, Modifiers::TransformModifier, category: :modifier, position: 500)
|
|
96
|
+
Registry.register(:cast, Modifiers::CastModifier, category: :modifier, position: 600)
|
|
97
|
+
Registry.register(:computed, Modifiers::ComputedModifier, category: :modifier, position: 700)
|
|
98
|
+
Registry.register(:default, Modifiers::DefaultModifier, category: :modifier, position: 800)
|
|
99
|
+
Registry.register(:as, Modifiers::AsModifier, category: :modifier, position: 900)
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
# Registers all built-in conditionals
|
|
103
|
+
#
|
|
104
|
+
# @return [void]
|
|
105
|
+
def register_conditionals!
|
|
106
|
+
Registry.register(:if, Conditionals::IfConditional, category: :conditional)
|
|
107
|
+
Registry.register(:unless, Conditionals::UnlessConditional, category: :conditional)
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
end
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
# Auto-register all options when this file is loaded
|
|
117
|
+
Treaty::Entity::Attribute::Option::RegistryInitializer.register_all!
|