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.
Files changed (80) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +1 -1
  3. data/config/locales/en.yml +3 -3
  4. data/lib/treaty/engine.rb +1 -1
  5. data/lib/treaty/{attribute/entity → entity/attribute}/attribute.rb +4 -4
  6. data/lib/treaty/entity/attribute/base.rb +184 -0
  7. data/lib/treaty/entity/attribute/builder/base.rb +275 -0
  8. data/lib/treaty/entity/attribute/collection.rb +67 -0
  9. data/lib/treaty/entity/attribute/dsl.rb +92 -0
  10. data/lib/treaty/entity/attribute/helper_mapper.rb +74 -0
  11. data/lib/treaty/entity/attribute/option/base.rb +190 -0
  12. data/lib/treaty/entity/attribute/option/conditionals/base.rb +92 -0
  13. data/lib/treaty/entity/attribute/option/conditionals/if_conditional.rb +136 -0
  14. data/lib/treaty/entity/attribute/option/conditionals/unless_conditional.rb +153 -0
  15. data/lib/treaty/entity/attribute/option/modifiers/as_modifier.rb +93 -0
  16. data/lib/treaty/entity/attribute/option/modifiers/cast_modifier.rb +285 -0
  17. data/lib/treaty/entity/attribute/option/modifiers/computed_modifier.rb +128 -0
  18. data/lib/treaty/entity/attribute/option/modifiers/default_modifier.rb +105 -0
  19. data/lib/treaty/entity/attribute/option/modifiers/transform_modifier.rb +114 -0
  20. data/lib/treaty/entity/attribute/option/registry.rb +157 -0
  21. data/lib/treaty/entity/attribute/option/registry_initializer.rb +117 -0
  22. data/lib/treaty/entity/attribute/option/validators/format_validator.rb +222 -0
  23. data/lib/treaty/entity/attribute/option/validators/inclusion_validator.rb +94 -0
  24. data/lib/treaty/entity/attribute/option/validators/required_validator.rb +100 -0
  25. data/lib/treaty/entity/attribute/option/validators/type_validator.rb +219 -0
  26. data/lib/treaty/entity/attribute/option_normalizer.rb +168 -0
  27. data/lib/treaty/entity/attribute/option_orchestrator.rb +192 -0
  28. data/lib/treaty/entity/attribute/validation/attribute_validator.rb +147 -0
  29. data/lib/treaty/entity/attribute/validation/base.rb +76 -0
  30. data/lib/treaty/entity/attribute/validation/nested_array_validator.rb +207 -0
  31. data/lib/treaty/entity/attribute/validation/nested_object_validator.rb +105 -0
  32. data/lib/treaty/entity/attribute/validation/nested_transformer.rb +432 -0
  33. data/lib/treaty/entity/attribute/validation/orchestrator/base.rb +262 -0
  34. data/lib/treaty/entity/base.rb +90 -0
  35. data/lib/treaty/entity/builder.rb +44 -0
  36. data/lib/treaty/{info/entity → entity/info}/builder.rb +8 -8
  37. data/lib/treaty/{info/entity → entity/info}/dsl.rb +2 -2
  38. data/lib/treaty/{info/entity → entity/info}/result.rb +2 -2
  39. data/lib/treaty/entity.rb +7 -79
  40. data/lib/treaty/request/attribute/attribute.rb +1 -1
  41. data/lib/treaty/request/attribute/builder.rb +2 -2
  42. data/lib/treaty/request/entity.rb +1 -1
  43. data/lib/treaty/request/factory.rb +5 -5
  44. data/lib/treaty/request/validator.rb +1 -1
  45. data/lib/treaty/response/attribute/attribute.rb +1 -1
  46. data/lib/treaty/response/attribute/builder.rb +2 -2
  47. data/lib/treaty/response/entity.rb +1 -1
  48. data/lib/treaty/response/factory.rb +5 -5
  49. data/lib/treaty/response/validator.rb +1 -1
  50. data/lib/treaty/version.rb +1 -1
  51. metadata +35 -34
  52. data/lib/treaty/attribute/base.rb +0 -182
  53. data/lib/treaty/attribute/builder/base.rb +0 -273
  54. data/lib/treaty/attribute/collection.rb +0 -65
  55. data/lib/treaty/attribute/dsl.rb +0 -90
  56. data/lib/treaty/attribute/entity/builder.rb +0 -46
  57. data/lib/treaty/attribute/helper_mapper.rb +0 -72
  58. data/lib/treaty/attribute/option/base.rb +0 -188
  59. data/lib/treaty/attribute/option/conditionals/base.rb +0 -90
  60. data/lib/treaty/attribute/option/conditionals/if_conditional.rb +0 -134
  61. data/lib/treaty/attribute/option/conditionals/unless_conditional.rb +0 -151
  62. data/lib/treaty/attribute/option/modifiers/as_modifier.rb +0 -91
  63. data/lib/treaty/attribute/option/modifiers/cast_modifier.rb +0 -283
  64. data/lib/treaty/attribute/option/modifiers/computed_modifier.rb +0 -126
  65. data/lib/treaty/attribute/option/modifiers/default_modifier.rb +0 -103
  66. data/lib/treaty/attribute/option/modifiers/transform_modifier.rb +0 -112
  67. data/lib/treaty/attribute/option/registry.rb +0 -155
  68. data/lib/treaty/attribute/option/registry_initializer.rb +0 -115
  69. data/lib/treaty/attribute/option/validators/format_validator.rb +0 -220
  70. data/lib/treaty/attribute/option/validators/inclusion_validator.rb +0 -92
  71. data/lib/treaty/attribute/option/validators/required_validator.rb +0 -98
  72. data/lib/treaty/attribute/option/validators/type_validator.rb +0 -217
  73. data/lib/treaty/attribute/option_normalizer.rb +0 -166
  74. data/lib/treaty/attribute/option_orchestrator.rb +0 -190
  75. data/lib/treaty/attribute/validation/attribute_validator.rb +0 -145
  76. data/lib/treaty/attribute/validation/base.rb +0 -74
  77. data/lib/treaty/attribute/validation/nested_array_validator.rb +0 -205
  78. data/lib/treaty/attribute/validation/nested_object_validator.rb +0 -103
  79. data/lib/treaty/attribute/validation/nested_transformer.rb +0 -430
  80. data/lib/treaty/attribute/validation/orchestrator/base.rb +0 -260
@@ -1,145 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Treaty
4
- module Attribute
5
- module Validation
6
- # Validates and transforms individual attributes.
7
- #
8
- # ## Purpose
9
- #
10
- # Acts as the main interface for attribute validation and transformation.
11
- # Delegates option processing to OptionOrchestrator and handles nested validation.
12
- #
13
- # ## Responsibilities
14
- #
15
- # 1. **Schema Validation** - Validates DSL definition correctness
16
- # 2. **Value Validation** - Validates runtime data values
17
- # 3. **Value Transformation** - Transforms values (defaults, etc.)
18
- # 4. **Name Transformation** - Provides target name (for `as:` option)
19
- # 5. **Nested Validation** - Delegates to NestedObjectValidator/NestedArrayValidator
20
- #
21
- # ## Usage
22
- #
23
- # Used by Orchestrator to validate each attribute:
24
- #
25
- # validator = AttributeValidator.new(attribute)
26
- # validator.validate_schema!
27
- # validator.validate_value!(value)
28
- # transformed = validator.transform_value(value)
29
- # target_name = validator.target_name
30
- #
31
- # ## Architecture
32
- #
33
- # Delegates to:
34
- # - `OptionOrchestrator` - Coordinates all option processors
35
- # - `NestedObjectValidator` - Validates nested object structures
36
- # - `NestedArrayValidator` - Validates nested array structures
37
- class AttributeValidator
38
- attr_reader :attribute, :option_orchestrator
39
-
40
- # Creates a new attribute validator instance
41
- #
42
- # @param attribute [Attribute::Base] The attribute to validate
43
- def initialize(attribute)
44
- @attribute = attribute
45
- @option_orchestrator = OptionOrchestrator.new(attribute)
46
- @nested_object_validator = nil
47
- @nested_array_validator = nil
48
- end
49
-
50
- # Validates the attribute schema (DSL definition)
51
- #
52
- # @raise [Treaty::Exceptions::Validation] If schema is invalid
53
- # @return [void]
54
- def validate_schema!
55
- option_orchestrator.validate_schema!
56
- end
57
-
58
- # Validates attribute value against all constraints
59
- #
60
- # @param value [Object] The value to validate
61
- # @raise [Treaty::Exceptions::Validation] If validation fails
62
- # @return [void]
63
- def validate_value!(value)
64
- option_orchestrator.validate_value!(value)
65
- validate_nested!(value) if attribute.nested? && !value.nil?
66
- end
67
-
68
- # Transforms attribute value through all modifiers
69
- #
70
- # @param value [Object] The value to transform
71
- # @param root_data [Hash] Full raw data from root level (used by computed modifier)
72
- # @return [Object] Transformed value
73
- def transform_value(value, root_data = {})
74
- option_orchestrator.transform_value(value, root_data)
75
- end
76
-
77
- # Checks if attribute name is transformed
78
- #
79
- # @return [Boolean] True if name is transformed (as: option)
80
- def transforms_name?
81
- option_orchestrator.transforms_name?
82
- end
83
-
84
- # Gets the target attribute name
85
- #
86
- # @return [Symbol] The target name (or original if not transformed)
87
- def target_name
88
- option_orchestrator.target_name
89
- end
90
-
91
- # Validates only the type constraint
92
- # Used by nested transformers to validate types before nested validation
93
- #
94
- # @param value [Object] The value to validate
95
- # @raise [Treaty::Exceptions::Validation] If type validation fails
96
- # @return [void]
97
- def validate_type!(value)
98
- type_processor = option_orchestrator.processor_for(:type)
99
- type_processor&.validate_value!(value)
100
- end
101
-
102
- # Validates only the required constraint
103
- # Used by nested transformers to validate presence before nested validation
104
- #
105
- # @param value [Object] The value to validate
106
- # @raise [Treaty::Exceptions::Validation] If required validation fails
107
- # @return [void]
108
- def validate_required!(value)
109
- required_processor = option_orchestrator.processor_for(:required)
110
- required_processor&.validate_value!(value) if attribute.options.key?(:required)
111
- end
112
-
113
- private
114
-
115
- # Validates nested attributes for object/array types
116
- #
117
- # @param value [Object] The value to validate
118
- # @raise [Treaty::Exceptions::Validation] If nested validation fails
119
- # @return [void]
120
- def validate_nested!(value)
121
- case attribute.type
122
- when :object
123
- nested_object_validator.validate!(value)
124
- when :array
125
- nested_array_validator.validate!(value)
126
- end
127
- end
128
-
129
- # Gets or creates nested object validator
130
- #
131
- # @return [NestedObjectValidator] Validator for nested objects
132
- def nested_object_validator
133
- @nested_object_validator ||= NestedObjectValidator.new(attribute)
134
- end
135
-
136
- # Gets or creates nested array validator
137
- #
138
- # @return [NestedArrayValidator] Validator for nested arrays
139
- def nested_array_validator
140
- @nested_array_validator ||= NestedArrayValidator.new(attribute)
141
- end
142
- end
143
- end
144
- end
145
- end
@@ -1,74 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Treaty
4
- module Attribute
5
- module Validation
6
- # Base class for request and response validation.
7
- #
8
- # ## Purpose
9
- #
10
- # Provides common interface for validation used in Treaty.
11
- # Subclasses implement specific validation logic for requests and responses.
12
- #
13
- # ## Responsibilities
14
- #
15
- # 1. **Validation Interface** - Defines common validation interface
16
- # 2. **Factory Pattern** - Provides class-level validate! method
17
- #
18
- # ## Subclasses
19
- #
20
- # - Request::Validation - Validates request data (uses Orchestrator::Request)
21
- # - Response::Validation - Validates response data (uses Orchestrator::Response)
22
- #
23
- # ## Usage
24
- #
25
- # Subclasses must implement:
26
- # - `validate!` - Performs validation and returns transformed data
27
- #
28
- # Example usage:
29
- # Request::Validation.validate!(version_factory: factory, data: params)
30
- #
31
- # ## Factory Method
32
- #
33
- # The `self.validate!(...)` class method provides a convenient factory pattern:
34
- # ```ruby
35
- # Request::Validation.validate!(version_factory: factory, data: params)
36
- # # Equivalent to:
37
- # Request::Validation.new(version_factory: factory).validate!(data: params)
38
- # ```
39
- #
40
- # ## Architecture
41
- #
42
- # Works with:
43
- # - VersionFactory - Provides version information
44
- # - Orchestrator::Base - Performs actual validation and transformation
45
- class Base
46
- # Class-level factory method for validation
47
- # Creates instance and calls validate!
48
- #
49
- # @param args [Hash] Arguments passed to initialize and validate!
50
- # @return [Hash] Validated and transformed data
51
- def self.validate!(...)
52
- new(...).validate!
53
- end
54
-
55
- # Creates a new validation instance
56
- #
57
- # @param version_factory [VersionFactory] Factory containing version information
58
- def initialize(version_factory:)
59
- @version_factory = version_factory
60
- end
61
-
62
- # Performs validation and transformation
63
- # Must be implemented in subclasses
64
- #
65
- # @raise [Treaty::Exceptions::NotImplemented] If subclass doesn't implement
66
- # @return [Hash] Validated and transformed data
67
- def validate!
68
- raise Treaty::Exceptions::Validation,
69
- I18n.t("treaty.attributes.validators.nested.orchestrator.collection_not_implemented")
70
- end
71
- end
72
- end
73
- end
74
- end
@@ -1,205 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Treaty
4
- module Attribute
5
- module Validation
6
- # Validates array elements against nested attribute definitions.
7
- #
8
- # ## Purpose
9
- #
10
- # Performs validation for nested array attributes during the validation phase.
11
- # Handles both simple arrays (with :_self attribute) and complex arrays (objects).
12
- #
13
- # ## Responsibilities
14
- #
15
- # 1. **Simple Array Validation** - Validates primitive values in arrays
16
- # 2. **Complex Array Validation** - Validates hash objects within arrays
17
- # 3. **Error Context** - Provides clear error messages with array index
18
- # 4. **Type Checking** - Ensures elements match expected types
19
- #
20
- # ## Array Types
21
- #
22
- # ### Simple Array (`:_self` attribute)
23
- # Array containing primitive values (strings, integers, etc.)
24
- #
25
- # ```ruby
26
- # array :tags do
27
- # string :_self # Array of strings
28
- # end
29
- # ```
30
- #
31
- # Validates: `["ruby", "rails", "api"]`
32
- #
33
- # ### Complex Array (regular attributes)
34
- # Array containing hash objects with defined structure
35
- #
36
- # ```ruby
37
- # array :authors do
38
- # string :name, :required
39
- # string :email
40
- # end
41
- # ```
42
- #
43
- # Validates: `[{ name: "Alice", email: "alice@example.com" }, ...]`
44
- #
45
- # ## Usage
46
- #
47
- # Called by AttributeValidator for nested arrays:
48
- #
49
- # validator = NestedArrayValidator.new(attribute)
50
- # validator.validate!(array_value)
51
- #
52
- # ## Error Handling
53
- #
54
- # Provides contextual error messages including:
55
- # - Array attribute name
56
- # - Element index (0-based)
57
- # - Specific validation error
58
- #
59
- # Example error:
60
- # "Error in array 'tags' at index 2: Element must match one of the defined types"
61
- #
62
- # ## Architecture
63
- #
64
- # Uses:
65
- # - `AttributeValidator` - Validates individual elements
66
- # - Caches validators for performance
67
- # - Separates self validators from regular validators
68
- class NestedArrayValidator
69
- # Creates a new nested array validator
70
- #
71
- # @param attribute [Attribute::Base] The array-type attribute with nested attributes
72
- def initialize(attribute)
73
- @attribute = attribute
74
- @self_validators = nil
75
- @regular_validators = nil
76
- end
77
-
78
- # Validates all items in an array
79
- # Skips validation if value is not an Array
80
- #
81
- # @param array [Array] The array to validate
82
- # @raise [Treaty::Exceptions::Validation] If any item validation fails
83
- # @return [void]
84
- def validate!(array)
85
- return unless array.is_a?(Array)
86
-
87
- array.each_with_index do |array_item, index|
88
- validate_self_array_item!(array_item, index) if self_validators.any?
89
-
90
- validate_regular_array_item!(array_item, index) if regular_validators.any?
91
- end
92
- end
93
-
94
- private
95
-
96
- # Validates array item for simple arrays (with :_self attribute)
97
- # Simple array contains primitive values: strings, integers, datetimes, etc.
98
- # Example: ["ruby", "rails", "api"] where each item is a String
99
- #
100
- # @param array_item [String, Integer, DateTime] Primitive value from simple array
101
- # @param index [Integer] Array index for error messages
102
- # @raise [Treaty::Exceptions::Validation] If primitive value doesn't match defined type
103
- # @return [void]
104
- def validate_self_array_item!(array_item, index) # rubocop:disable Metrics/MethodLength
105
- errors = []
106
-
107
- validated = self_validators.any? do |validator|
108
- validator.validate_value!(array_item)
109
- true
110
- rescue Treaty::Exceptions::Validation => e
111
- errors << e.message
112
- false
113
- end
114
-
115
- return if validated
116
-
117
- raise Treaty::Exceptions::Validation,
118
- I18n.t(
119
- "treaty.attributes.validators.nested.array.element_validation_error",
120
- attribute: @attribute.name,
121
- index:,
122
- errors: errors.join("; ")
123
- )
124
- end
125
-
126
- # Validates array item for complex arrays (with regular attributes)
127
- # Complex array contains hash objects with defined structure
128
- # Example: [{ name: "Alice", email: "alice@example.com" }, ...] where each item is a Hash
129
- #
130
- # @param array_item [Hash] Hash object from complex array
131
- # @param index [Integer] Array index for error messages
132
- # @raise [Treaty::Exceptions::Validation] If item is not Hash or nested validation fails
133
- # @return [void]
134
- def validate_regular_array_item!(array_item, index) # rubocop:disable Metrics/MethodLength
135
- unless array_item.is_a?(Hash)
136
- raise Treaty::Exceptions::Validation,
137
- I18n.t(
138
- "treaty.attributes.validators.nested.array.element_type_error",
139
- attribute: @attribute.name,
140
- index:,
141
- actual: array_item.class
142
- )
143
- end
144
-
145
- regular_validators.each do |nested_attribute, validator|
146
- nested_value = array_item.fetch(nested_attribute.name, nil)
147
- validator.validate_value!(nested_value)
148
- rescue Treaty::Exceptions::Validation => e
149
- raise Treaty::Exceptions::Validation,
150
- I18n.t(
151
- "treaty.attributes.validators.nested.array.attribute_error",
152
- attribute: @attribute.name,
153
- index:,
154
- message: e.message
155
- )
156
- end
157
- end
158
-
159
- ########################################################################
160
-
161
- # Gets cached self validators or builds them
162
- #
163
- # @return [Array<AttributeValidator>] Validators for :_self attributes
164
- def self_validators
165
- @self_validators ||= build_self_validators
166
- end
167
-
168
- # Gets cached regular validators or builds them
169
- #
170
- # @return [Hash] Hash of nested_attribute => validator
171
- def regular_validators
172
- @regular_validators ||= build_regular_validators
173
- end
174
-
175
- ########################################################################
176
-
177
- # Builds validators for :_self attributes (simple array elements)
178
- #
179
- # @return [Array<AttributeValidator>] Array of validators
180
- def build_self_validators
181
- @attribute.collection_of_attributes
182
- .select { |attr| attr.name == :_self }
183
- .map do |self_attribute|
184
- validator = AttributeValidator.new(self_attribute)
185
- validator.validate_schema!
186
- validator
187
- end
188
- end
189
-
190
- # Builds validators for regular attributes (complex array elements)
191
- #
192
- # @return [Hash] Hash of nested_attribute => validator
193
- def build_regular_validators
194
- @attribute.collection_of_attributes
195
- .reject { |attr| attr.name == :_self }
196
- .each_with_object({}) do |nested_attribute, cache|
197
- validator = AttributeValidator.new(nested_attribute)
198
- validator.validate_schema!
199
- cache[nested_attribute] = validator
200
- end
201
- end
202
- end
203
- end
204
- end
205
- end
@@ -1,103 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Treaty
4
- module Attribute
5
- module Validation
6
- # Validates nested object (hash) attributes against their defined structure.
7
- #
8
- # ## Purpose
9
- #
10
- # Performs validation for nested object attributes during the validation phase.
11
- # Ensures hash values conform to the nested attribute definitions.
12
- #
13
- # ## Responsibilities
14
- #
15
- # 1. **Structure Validation** - Validates hash structure matches definition
16
- # 2. **Attribute Validation** - Validates each nested attribute's value
17
- # 3. **Type Safety** - Ensures value is a Hash before validation
18
- # 4. **Validator Caching** - Builds and caches validators for performance
19
- #
20
- # ## Usage
21
- #
22
- # Used for object-type attributes with nested definitions:
23
- #
24
- # ```ruby
25
- # object :author do
26
- # string :name, :required
27
- # string :email
28
- # integer :age
29
- # end
30
- # ```
31
- #
32
- # Validates: `{ name: "Alice", email: "alice@example.com", age: 30 }`
33
- #
34
- # ## Usage in Code
35
- #
36
- # Called by AttributeValidator for nested objects:
37
- #
38
- # validator = NestedObjectValidator.new(attribute)
39
- # validator.validate!(hash_value)
40
- #
41
- # ## Validation Flow
42
- #
43
- # 1. Check if value is a Hash
44
- # 2. Build validators for all nested attributes (cached)
45
- # 3. For each nested attribute:
46
- # - Extract value from hash
47
- # - Validate using AttributeValidator
48
- # 4. Raise exception if any validation fails
49
- #
50
- # ## Architecture
51
- #
52
- # Uses:
53
- # - `AttributeValidator` - Validates individual nested attributes
54
- # - Caches validators to avoid rebuilding on each validation
55
- class NestedObjectValidator
56
- attr_reader :attribute
57
-
58
- # Creates a new nested object validator
59
- #
60
- # @param attribute [Attribute::Base] The object-type attribute with nested attributes
61
- def initialize(attribute)
62
- @attribute = attribute
63
- @validators_cache = nil
64
- end
65
-
66
- # Validates all nested attributes in a hash
67
- # Skips validation if value is not a Hash
68
- #
69
- # @param hash [Hash] The hash to validate
70
- # @raise [Treaty::Exceptions::Validation] If any nested validation fails
71
- # @return [void]
72
- def validate!(hash)
73
- return unless hash.is_a?(Hash)
74
-
75
- validators.each do |nested_attribute, nested_validator|
76
- nested_value = hash.fetch(nested_attribute.name, nil)
77
- nested_validator.validate_value!(nested_value)
78
- end
79
- end
80
-
81
- private
82
-
83
- # Gets cached validators or builds them
84
- #
85
- # @return [Hash] Hash of nested_attribute => validator
86
- def validators
87
- @validators ||= build_validators
88
- end
89
-
90
- # Builds validators for all nested attributes
91
- #
92
- # @return [Hash] Hash of nested_attribute => validator
93
- def build_validators
94
- attribute.collection_of_attributes.each_with_object({}) do |nested_attribute, cache|
95
- validator = AttributeValidator.new(nested_attribute)
96
- validator.validate_schema!
97
- cache[nested_attribute] = validator
98
- end
99
- end
100
- end
101
- end
102
- end
103
- end