treaty 0.18.0 → 0.20.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 (129) 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/action/base.rb +11 -0
  5. data/lib/treaty/action/context/callable.rb +90 -0
  6. data/lib/treaty/action/context/dsl.rb +56 -0
  7. data/lib/treaty/action/context/workspace.rb +92 -0
  8. data/lib/treaty/action/executor/inventory.rb +136 -0
  9. data/lib/treaty/{info/rest → action/info}/builder.rb +2 -2
  10. data/lib/treaty/{info/rest → action/info}/dsl.rb +2 -2
  11. data/lib/treaty/{info/rest → action/info}/result.rb +2 -2
  12. data/lib/treaty/action/inventory/collection.rb +77 -0
  13. data/lib/treaty/action/inventory/factory.rb +108 -0
  14. data/lib/treaty/action/inventory/inventory.rb +146 -0
  15. data/lib/treaty/action/request/attribute/attribute.rb +76 -0
  16. data/lib/treaty/action/request/attribute/builder.rb +98 -0
  17. data/lib/treaty/action/request/entity.rb +78 -0
  18. data/lib/treaty/action/request/factory.rb +116 -0
  19. data/lib/treaty/action/request/validator.rb +120 -0
  20. data/lib/treaty/action/response/attribute/attribute.rb +79 -0
  21. data/lib/treaty/action/response/attribute/builder.rb +96 -0
  22. data/lib/treaty/action/response/entity.rb +79 -0
  23. data/lib/treaty/action/response/factory.rb +129 -0
  24. data/lib/treaty/action/response/validator.rb +111 -0
  25. data/lib/treaty/action/result.rb +81 -0
  26. data/lib/treaty/action/versions/collection.rb +47 -0
  27. data/lib/treaty/action/versions/dsl.rb +116 -0
  28. data/lib/treaty/action/versions/execution/request.rb +287 -0
  29. data/lib/treaty/action/versions/executor.rb +61 -0
  30. data/lib/treaty/action/versions/factory.rb +253 -0
  31. data/lib/treaty/action/versions/resolver.rb +150 -0
  32. data/lib/treaty/action/versions/semantic.rb +64 -0
  33. data/lib/treaty/action/versions/workspace.rb +106 -0
  34. data/lib/treaty/action.rb +31 -0
  35. data/lib/treaty/controller/dsl.rb +1 -1
  36. data/lib/treaty/engine.rb +1 -1
  37. data/lib/treaty/{attribute/entity → entity/attribute}/attribute.rb +4 -4
  38. data/lib/treaty/entity/attribute/base.rb +184 -0
  39. data/lib/treaty/entity/attribute/builder/base.rb +275 -0
  40. data/lib/treaty/entity/attribute/collection.rb +67 -0
  41. data/lib/treaty/entity/attribute/dsl.rb +92 -0
  42. data/lib/treaty/entity/attribute/helper_mapper.rb +74 -0
  43. data/lib/treaty/entity/attribute/option/base.rb +190 -0
  44. data/lib/treaty/entity/attribute/option/conditionals/base.rb +92 -0
  45. data/lib/treaty/entity/attribute/option/conditionals/if_conditional.rb +136 -0
  46. data/lib/treaty/entity/attribute/option/conditionals/unless_conditional.rb +153 -0
  47. data/lib/treaty/entity/attribute/option/modifiers/as_modifier.rb +93 -0
  48. data/lib/treaty/entity/attribute/option/modifiers/cast_modifier.rb +285 -0
  49. data/lib/treaty/entity/attribute/option/modifiers/computed_modifier.rb +128 -0
  50. data/lib/treaty/entity/attribute/option/modifiers/default_modifier.rb +105 -0
  51. data/lib/treaty/entity/attribute/option/modifiers/transform_modifier.rb +114 -0
  52. data/lib/treaty/entity/attribute/option/registry.rb +157 -0
  53. data/lib/treaty/entity/attribute/option/registry_initializer.rb +117 -0
  54. data/lib/treaty/entity/attribute/option/validators/format_validator.rb +222 -0
  55. data/lib/treaty/entity/attribute/option/validators/inclusion_validator.rb +94 -0
  56. data/lib/treaty/entity/attribute/option/validators/required_validator.rb +100 -0
  57. data/lib/treaty/entity/attribute/option/validators/type_validator.rb +219 -0
  58. data/lib/treaty/entity/attribute/option_normalizer.rb +168 -0
  59. data/lib/treaty/entity/attribute/option_orchestrator.rb +192 -0
  60. data/lib/treaty/entity/attribute/validation/attribute_validator.rb +147 -0
  61. data/lib/treaty/entity/attribute/validation/base.rb +76 -0
  62. data/lib/treaty/entity/attribute/validation/nested_array_validator.rb +207 -0
  63. data/lib/treaty/entity/attribute/validation/nested_object_validator.rb +105 -0
  64. data/lib/treaty/entity/attribute/validation/nested_transformer.rb +432 -0
  65. data/lib/treaty/entity/attribute/validation/orchestrator/base.rb +262 -0
  66. data/lib/treaty/entity/base.rb +90 -0
  67. data/lib/treaty/entity/builder.rb +101 -0
  68. data/lib/treaty/{info/entity → entity/info}/builder.rb +8 -8
  69. data/lib/treaty/{info/entity → entity/info}/dsl.rb +2 -2
  70. data/lib/treaty/{info/entity → entity/info}/result.rb +2 -2
  71. data/lib/treaty/entity.rb +7 -79
  72. data/lib/treaty/version.rb +1 -1
  73. metadata +66 -64
  74. data/lib/treaty/attribute/base.rb +0 -182
  75. data/lib/treaty/attribute/builder/base.rb +0 -273
  76. data/lib/treaty/attribute/collection.rb +0 -65
  77. data/lib/treaty/attribute/dsl.rb +0 -90
  78. data/lib/treaty/attribute/entity/builder.rb +0 -46
  79. data/lib/treaty/attribute/helper_mapper.rb +0 -72
  80. data/lib/treaty/attribute/option/base.rb +0 -188
  81. data/lib/treaty/attribute/option/conditionals/base.rb +0 -90
  82. data/lib/treaty/attribute/option/conditionals/if_conditional.rb +0 -134
  83. data/lib/treaty/attribute/option/conditionals/unless_conditional.rb +0 -151
  84. data/lib/treaty/attribute/option/modifiers/as_modifier.rb +0 -91
  85. data/lib/treaty/attribute/option/modifiers/cast_modifier.rb +0 -283
  86. data/lib/treaty/attribute/option/modifiers/computed_modifier.rb +0 -126
  87. data/lib/treaty/attribute/option/modifiers/default_modifier.rb +0 -103
  88. data/lib/treaty/attribute/option/modifiers/transform_modifier.rb +0 -112
  89. data/lib/treaty/attribute/option/registry.rb +0 -155
  90. data/lib/treaty/attribute/option/registry_initializer.rb +0 -115
  91. data/lib/treaty/attribute/option/validators/format_validator.rb +0 -220
  92. data/lib/treaty/attribute/option/validators/inclusion_validator.rb +0 -92
  93. data/lib/treaty/attribute/option/validators/required_validator.rb +0 -98
  94. data/lib/treaty/attribute/option/validators/type_validator.rb +0 -217
  95. data/lib/treaty/attribute/option_normalizer.rb +0 -166
  96. data/lib/treaty/attribute/option_orchestrator.rb +0 -190
  97. data/lib/treaty/attribute/validation/attribute_validator.rb +0 -145
  98. data/lib/treaty/attribute/validation/base.rb +0 -74
  99. data/lib/treaty/attribute/validation/nested_array_validator.rb +0 -205
  100. data/lib/treaty/attribute/validation/nested_object_validator.rb +0 -103
  101. data/lib/treaty/attribute/validation/nested_transformer.rb +0 -430
  102. data/lib/treaty/attribute/validation/orchestrator/base.rb +0 -260
  103. data/lib/treaty/base.rb +0 -9
  104. data/lib/treaty/context/callable.rb +0 -26
  105. data/lib/treaty/context/dsl.rb +0 -12
  106. data/lib/treaty/context/workspace.rb +0 -32
  107. data/lib/treaty/executor/inventory.rb +0 -122
  108. data/lib/treaty/inventory/collection.rb +0 -71
  109. data/lib/treaty/inventory/factory.rb +0 -91
  110. data/lib/treaty/inventory/inventory.rb +0 -92
  111. data/lib/treaty/request/attribute/attribute.rb +0 -25
  112. data/lib/treaty/request/attribute/builder.rb +0 -46
  113. data/lib/treaty/request/entity.rb +0 -33
  114. data/lib/treaty/request/factory.rb +0 -81
  115. data/lib/treaty/request/validator.rb +0 -60
  116. data/lib/treaty/response/attribute/attribute.rb +0 -25
  117. data/lib/treaty/response/attribute/builder.rb +0 -46
  118. data/lib/treaty/response/entity.rb +0 -33
  119. data/lib/treaty/response/factory.rb +0 -87
  120. data/lib/treaty/response/validator.rb +0 -53
  121. data/lib/treaty/result.rb +0 -23
  122. data/lib/treaty/versions/collection.rb +0 -15
  123. data/lib/treaty/versions/dsl.rb +0 -42
  124. data/lib/treaty/versions/execution/request.rb +0 -177
  125. data/lib/treaty/versions/executor.rb +0 -14
  126. data/lib/treaty/versions/factory.rb +0 -112
  127. data/lib/treaty/versions/resolver.rb +0 -70
  128. data/lib/treaty/versions/semantic.rb +0 -22
  129. data/lib/treaty/versions/workspace.rb +0 -43
@@ -1,182 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Treaty
4
- module Attribute
5
- # Base class for all attribute definitions in Treaty DSL.
6
- #
7
- # ## Purpose
8
- #
9
- # Represents a single attribute defined in request/response definitions.
10
- # Handles:
11
- # - Attribute metadata (name, type, nesting level)
12
- # - Helper mode to simple mode conversion
13
- # - Simple mode to advanced mode normalization
14
- # - Nested attributes (for object and array types)
15
- #
16
- # ## Usage
17
- #
18
- # Attributes are created through DSL methods:
19
- # string :title, :required
20
- # integer :age, default: 18
21
- # object :author do
22
- # string :name
23
- # end
24
- #
25
- # ## Processing Flow
26
- #
27
- # 1. Extract helpers from arguments (`:required`, `:optional`)
28
- # 2. Convert helpers to simple mode options
29
- # 3. Merge with explicit options
30
- # 4. Normalize all options to advanced mode
31
- # 5. Apply defaults (required: true for request, false for response)
32
- # 6. Process nested attributes if block given
33
- #
34
- # ## Nested Attributes
35
- #
36
- # Object and array types can have nested attributes:
37
- # - `object` - nested attributes as direct children
38
- # - `array` - nested attributes define array element structure
39
- #
40
- # Special attribute name `:_self` is used for simple arrays:
41
- # array :tags do
42
- # string :_self # Array of strings
43
- # end
44
- class Base
45
- attr_reader :name,
46
- :type,
47
- :options,
48
- :nesting_level
49
-
50
- # Creates a new attribute instance
51
- #
52
- # @param name [Symbol] The attribute name
53
- # @param type [Symbol] The attribute type (:string, :integer, :object, :array, etc.)
54
- # @param helpers [Array<Symbol>] Helper symbols (:required, :optional)
55
- # @param nesting_level [Integer] Current nesting depth (default: 0)
56
- # @param options [Hash] Attribute options (required, default, as, etc.)
57
- # @param block [Proc] Block for defining nested attributes (for object/array types)
58
- def initialize(name, type, *helpers, nesting_level: 0, **options, &block)
59
- @name = name
60
- @type = type
61
- @nesting_level = nesting_level
62
-
63
- validate_nesting_level!
64
-
65
- # Separate helpers from non-helper symbols.
66
- @helpers = extract_helpers(helpers)
67
-
68
- # Merge helper options with explicit options.
69
- merged_options = merge_options(@helpers, options)
70
-
71
- # Normalize all options to advanced mode.
72
- @options = OptionNormalizer.normalize(merged_options)
73
-
74
- apply_defaults!
75
-
76
- # Process nested attributes for object and array types.
77
- process_nested_attributes(&block) if block_given?
78
- end
79
-
80
- # Returns collection of nested attributes for this attribute
81
- #
82
- # @return [Collection] Collection of nested attributes
83
- def collection_of_attributes
84
- @collection_of_attributes ||= Collection.new
85
- end
86
-
87
- # Checks if this attribute has nested attributes
88
- #
89
- # @return [Boolean] True if attribute is object/array with nested attributes
90
- def nested?
91
- object_or_array? && collection_of_attributes.exists?
92
- end
93
-
94
- # Checks if this attribute is an object or array type
95
- #
96
- # @return [Boolean] True if type is :object or :array
97
- def object_or_array?
98
- object? || array?
99
- end
100
-
101
- # Checks if this attribute is an object type
102
- #
103
- # @return [Boolean] True if type is :object
104
- def object?
105
- @type == :object
106
- end
107
-
108
- # Checks if this attribute is an array type
109
- #
110
- # @return [Boolean] True if type is :array
111
- def array?
112
- @type == :array
113
- end
114
-
115
- private
116
-
117
- # Validates that nesting level doesn't exceed maximum allowed depth
118
- #
119
- # @raise [Treaty::Exceptions::NestedAttributes] If nesting exceeds limit
120
- # @return [void]
121
- def validate_nesting_level!
122
- return unless @nesting_level > Treaty::Engine.config.treaty.attribute_nesting_level
123
-
124
- raise Treaty::Exceptions::NestedAttributes,
125
- I18n.t(
126
- "treaty.attributes.errors.nesting_level_exceeded",
127
- level: @nesting_level,
128
- max_level: Treaty::Engine.config.treaty.attribute_nesting_level
129
- )
130
- end
131
-
132
- # Extracts helper symbols from arguments
133
- #
134
- # @param helpers [Array] Mixed array that may contain helper symbols
135
- # @return [Array<Symbol>] Filtered array of valid helper symbols
136
- def extract_helpers(helpers)
137
- helpers.select do |helper|
138
- helper.is_a?(Symbol) && HelperMapper.helper?(helper)
139
- end
140
- end
141
-
142
- # Merges helper-derived options with explicit options
143
- #
144
- # @param helpers [Array<Symbol>] Helper symbols to convert
145
- # @param explicit_options [Hash] Explicitly provided options
146
- # @return [Hash] Merged options hash
147
- def merge_options(helpers, explicit_options)
148
- helper_options = HelperMapper.map(helpers)
149
- helper_options.merge(explicit_options)
150
- end
151
-
152
- # Applies default values for options based on context (request/response)
153
- # Must be implemented in subclasses
154
- #
155
- # @raise [Treaty::Exceptions::NotImplemented] If subclass doesn't implement
156
- # @return [void]
157
- def apply_defaults!
158
- # Must be implemented in subclasses
159
- raise Treaty::Exceptions::NotImplemented,
160
- I18n.t(
161
- "treaty.attributes.errors.apply_defaults_not_implemented",
162
- class: self.class
163
- )
164
- end
165
-
166
- # Processes nested attributes block for object/array types
167
- # Must be implemented in subclasses
168
- #
169
- # @param block [Proc] Block containing nested attribute definitions
170
- # @raise [Treaty::Exceptions::NotImplemented] If subclass doesn't implement
171
- # @return [void]
172
- def process_nested_attributes
173
- # Must be implemented in subclasses
174
- raise Treaty::Exceptions::NotImplemented,
175
- I18n.t(
176
- "treaty.attributes.errors.process_nested_not_implemented",
177
- class: self.class
178
- )
179
- end
180
- end
181
- end
182
- end
@@ -1,273 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Treaty
4
- module Attribute
5
- module Builder
6
- # Base DSL builder for defining attributes in request/response definitions.
7
- #
8
- # ## Purpose
9
- #
10
- # Provides the DSL interface for defining attributes within objects.
11
- # Handles method_missing magic to support type-based method calls.
12
- #
13
- # ## Responsibilities
14
- #
15
- # 1. **DSL Interface** - Provides clean syntax for attribute definitions
16
- # 2. **Method Dispatch** - Routes type methods (string, integer, etc.) to attribute creation
17
- # 3. **Helper Support** - Handles helper symbols in various positions
18
- # 4. **Nesting Tracking** - Tracks nesting level for nested attributes
19
- # 5. **Entity Reuse** - Supports use_entity for copying attributes from Entity classes
20
- #
21
- # ## DSL Usage
22
- #
23
- # The builder enables this clean DSL syntax:
24
- #
25
- # ```ruby
26
- # request do
27
- # object :user do
28
- # string :name
29
- # integer :age, default: 18
30
- # object :profile do
31
- # string :bio
32
- # end
33
- # end
34
- # end
35
- # ```
36
- #
37
- # ## Entity Reuse
38
- #
39
- # You can use `use_entity` to copy attributes from an Entity class:
40
- #
41
- # ```ruby
42
- # object :author do
43
- # use_entity(AuthorEntity)
44
- # end
45
- # ```
46
- #
47
- # Note: `use_entity` must be the only statement in the block.
48
- #
49
- # ## Method Dispatch
50
- #
51
- # ### Type-based Methods
52
- # When you call `string :name`, it routes through `method_missing`:
53
- # 1. `string` becomes the type
54
- # 2. `:name` becomes the attribute name
55
- # 3. Calls `attribute(:name, :string, ...)`
56
- #
57
- # ### Helper Position Handling
58
- # Handles helpers in different positions:
59
- #
60
- # ```ruby
61
- # string :required, :name # Helper first, then name
62
- # string :name, :required # Name first, then helper
63
- # ```
64
- #
65
- # Both resolve to the same attribute definition.
66
- #
67
- # ## Nesting
68
- #
69
- # Tracks nesting level for:
70
- # - Validation (enforcing maximum nesting depth)
71
- # - Error messages (showing context)
72
- #
73
- # Maximum nesting level is configured in Treaty::Engine.config.
74
- #
75
- # ## Subclass Requirements
76
- #
77
- # Subclasses must implement:
78
- # - `create_attribute` - Creates the appropriate attribute type (Request/Response)
79
- # - `deep_copy_attribute` - Deep copies an attribute with adjusted nesting level
80
- #
81
- # ## Architecture
82
- #
83
- # Used by:
84
- # - Request::Builder - For request attribute definitions
85
- # - Response::Builder - For response attribute definitions
86
- # - Entity::Builder - For entity attribute definitions
87
- class Base
88
- attr_reader :nesting_level,
89
- :collection_of_attributes
90
-
91
- # Creates a new builder instance
92
- #
93
- # @param collection_of_attributes [Collection] Collection to add attributes to
94
- # @param nesting_level [Integer] Current nesting depth
95
- def initialize(collection_of_attributes, nesting_level)
96
- @collection_of_attributes = collection_of_attributes
97
- @nesting_level = nesting_level
98
- @use_entity_called = false
99
- @attributes_defined = false
100
- end
101
-
102
- # Uses an Entity class to copy its attributes into this builder's collection.
103
- # Must be the ONLY statement in the block - no other attributes allowed.
104
- #
105
- # @param entity_class [Class] Entity class (must be Treaty::Entity subclass)
106
- # @raise [Treaty::Exceptions::Validation] if entity_class is invalid
107
- # @raise [Treaty::Exceptions::Validation] if mixed with other attributes
108
- # @return [void]
109
- #
110
- # @example Using an Entity in a nested object
111
- # object :author do
112
- # use_entity(AuthorEntity)
113
- # end
114
- #
115
- # @example Using an Entity in a nested array
116
- # array :items, :optional do
117
- # use_entity(ItemEntity)
118
- # end
119
- def use_entity(entity_class)
120
- validate_use_entity_preconditions!
121
- validate_entity_class!(entity_class)
122
-
123
- @use_entity_called = true
124
-
125
- copy_attributes_from_entity(entity_class)
126
- end
127
-
128
- # Defines an attribute with explicit type
129
- #
130
- # @param name [Symbol] The attribute name
131
- # @param type [Symbol] The attribute type
132
- # @param helpers [Array<Symbol>] Helper symbols (:required, :optional)
133
- # @param options [Hash] Attribute options
134
- # @param block [Proc] Block for nested attributes
135
- # @return [void]
136
- def attribute(name, type, *helpers, **options, &block)
137
- validate_no_use_entity_called!
138
-
139
- @attributes_defined = true
140
-
141
- @collection_of_attributes << create_attribute(
142
- name,
143
- type,
144
- *helpers,
145
- nesting_level: @nesting_level,
146
- **options,
147
- &block
148
- )
149
- end
150
-
151
- # Handles DSL methods like `string :name` where method name is the type
152
- #
153
- # @param type [Symbol] The attribute type (method name)
154
- # @param name [Symbol] The attribute name (first argument)
155
- # @param helpers [Array<Symbol>] Helper symbols
156
- # @param options [Hash] Attribute options
157
- # @param block [Proc] Block for nested attributes
158
- # @return [void]
159
- def method_missing(type, name, *helpers, **options, &block)
160
- if name.is_a?(Symbol) && HelperMapper.helper?(name)
161
- helpers.unshift(name)
162
- name = helpers.shift
163
- end
164
-
165
- attribute(name, type, *helpers, **options, &block)
166
- end
167
-
168
- # Checks if method should be handled by method_missing
169
- #
170
- # @param name [Symbol] Method name
171
- # @return [Boolean]
172
- def respond_to_missing?(name, *)
173
- super
174
- end
175
-
176
- private
177
-
178
- # Creates an attribute instance (must be implemented in subclasses)
179
- #
180
- # @raise [Treaty::Exceptions::NotImplemented] If subclass doesn't implement
181
- # @return [Attribute::Base] Created attribute instance
182
- def create_attribute(*)
183
- raise Treaty::Exceptions::NotImplemented,
184
- I18n.t("treaty.attributes.builder.not_implemented", class: self.class)
185
- end
186
-
187
- # Validates that use_entity can be called (no attributes defined before)
188
- #
189
- # @raise [Treaty::Exceptions::Validation] if attributes were defined before use_entity
190
- def validate_use_entity_preconditions!
191
- return unless @attributes_defined
192
-
193
- raise Treaty::Exceptions::Validation,
194
- I18n.t("treaty.attributes.builder.use_entity_after_attributes")
195
- end
196
-
197
- # Validates that no use_entity was called before defining attributes
198
- #
199
- # @raise [Treaty::Exceptions::Validation] if use_entity was already called
200
- def validate_no_use_entity_called!
201
- return unless @use_entity_called
202
-
203
- raise Treaty::Exceptions::Validation,
204
- I18n.t("treaty.attributes.builder.attributes_after_use_entity")
205
- end
206
-
207
- # Validates that entity_class is a valid Treaty::Entity subclass
208
- #
209
- # @param entity_class [Class] Entity class to validate
210
- # @raise [Treaty::Exceptions::Validation] if entity_class is not valid
211
- def validate_entity_class!(entity_class)
212
- return if entity_class.is_a?(Class) && entity_class < Treaty::Entity
213
-
214
- raise Treaty::Exceptions::Validation,
215
- I18n.t(
216
- "treaty.attributes.builder.invalid_entity_class",
217
- type: entity_class.class,
218
- value: entity_class
219
- )
220
- end
221
-
222
- # Copies all attributes from entity_class to this builder's collection
223
- # with adjusted nesting levels.
224
- #
225
- # @param entity_class [Class] Source entity class
226
- def copy_attributes_from_entity(entity_class)
227
- entity_class.collection_of_attributes.each do |source_attribute|
228
- copied_attribute = deep_copy_attribute(source_attribute, @nesting_level)
229
- @collection_of_attributes << copied_attribute
230
- end
231
- end
232
-
233
- # Deep copies an attribute with adjusted nesting level.
234
- # Must be implemented by subclasses to use proper attribute types.
235
- #
236
- # @param source_attribute [Attribute::Base] Attribute to copy
237
- # @param new_nesting_level [Integer] New nesting level for copied attribute
238
- # @return [Attribute::Base] Copied attribute with correct type
239
- def deep_copy_attribute(_source_attribute, _new_nesting_level)
240
- raise Treaty::Exceptions::NotImplemented,
241
- I18n.t(
242
- "treaty.attributes.builder.deep_copy_not_implemented",
243
- class: self.class
244
- )
245
- end
246
-
247
- # Deep copies options hash, preserving Proc references
248
- # and recursively handling nested Hash/Array structures.
249
- #
250
- # @param options [Hash] Options to copy
251
- # @return [Hash] Copied options
252
- def deep_copy_options(options)
253
- options.transform_values { |value| deep_copy_value(value) }
254
- end
255
-
256
- # Deep copies a single value, handling nested structures.
257
- # Immutable types (Proc, Symbol, Numeric, nil, true, false) are returned as-is.
258
- # Hash and Array are recursively copied. Strings are duplicated if not frozen.
259
- #
260
- # @param value [Object] Value to copy
261
- # @return [Object] Copied value
262
- def deep_copy_value(value)
263
- case value
264
- when Hash then value.transform_values { |v| deep_copy_value(v) }
265
- when Array then value.map { |v| deep_copy_value(v) }
266
- when String then value.frozen? ? value : value.dup
267
- else value
268
- end
269
- end
270
- end
271
- end
272
- end
273
- end
@@ -1,65 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "forwardable"
4
-
5
- module Treaty
6
- module Attribute
7
- # Collection wrapper for sets of attributes.
8
- #
9
- # ## Purpose
10
- #
11
- # Provides a unified interface for working with collections of attributes.
12
- # Uses Ruby Set internally for uniqueness but exposes Array-like interface.
13
- #
14
- # ## Usage
15
- #
16
- # Used internally by:
17
- # - Request/Response factories (to store attributes)
18
- # - Attribute::Base (to store nested attributes)
19
- #
20
- # ## Methods
21
- #
22
- # Delegates common collection methods to internal Set:
23
- # - `<<` - Add attribute
24
- # - `each`, `map`, `select`, `reject` - Iteration
25
- # - `find`, `first` - Access
26
- # - `size`, `empty?` - Size checks
27
- # - `to_h` - Convert to hash
28
- #
29
- # Custom methods:
30
- # - `exists?` - Returns true if collection is not empty
31
- #
32
- # ## Example
33
- #
34
- # collection = Collection.new
35
- # collection << Attribute::Base.new(:name, :string)
36
- # collection << Attribute::Base.new(:age, :integer)
37
- # collection.size # => 2
38
- # collection.exists? # => true
39
- class Collection
40
- extend Forwardable
41
-
42
- def_delegators :@collection,
43
- :<<,
44
- :to_h, :map,
45
- :each_with_object, :each,
46
- :select, :reject, :size,
47
- :find, :first,
48
- :empty?
49
-
50
- # Creates a new collection instance
51
- #
52
- # @param collection [Set] Initial collection (default: empty Set)
53
- def initialize(collection = Set.new)
54
- @collection = collection
55
- end
56
-
57
- # Checks if collection has any elements
58
- #
59
- # @return [Boolean] True if collection is not empty
60
- def exists?
61
- !empty?
62
- end
63
- end
64
- end
65
- end
@@ -1,90 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Treaty
4
- module Attribute
5
- # DSL module for defining attributes in Entity-like classes.
6
- #
7
- # This module provides the class-level DSL for defining attributes.
8
- # It can be included in any class that needs attribute definition capabilities.
9
- #
10
- # ## Usage
11
- #
12
- # ```ruby
13
- # class MyEntity
14
- # include Treaty::Attribute::DSL
15
- #
16
- # string :name
17
- # integer :age
18
- # end
19
- # ```
20
- module DSL
21
- def self.included(base)
22
- base.extend(ClassMethods)
23
- end
24
-
25
- module ClassMethods
26
- # Defines an attribute with explicit type
27
- #
28
- # @param name [Symbol] The attribute name
29
- # @param type [Symbol] The attribute type
30
- # @param helpers [Array<Symbol>] Helper symbols (:required, :optional)
31
- # @param options [Hash] Attribute options
32
- # @param block [Proc] Block for nested attributes
33
- # @return [void]
34
- def attribute(name, type, *helpers, **options, &block)
35
- collection_of_attributes << create_attribute(
36
- name,
37
- type,
38
- *helpers,
39
- nesting_level: 0,
40
- **options,
41
- &block
42
- )
43
- end
44
-
45
- # Returns collection of attributes for this class
46
- #
47
- # @return [Collection] Collection of attributes
48
- def collection_of_attributes
49
- @collection_of_attributes ||= Treaty::Attribute::Collection.new
50
- end
51
-
52
- # Handles DSL methods like `string :name` where method name is the type
53
- #
54
- # @param type [Symbol] The attribute type (method name)
55
- # @param name [Symbol] The attribute name (first argument)
56
- # @param helpers [Array<Symbol>] Helper symbols
57
- # @param options [Hash] Attribute options
58
- # @param block [Proc] Block for nested attributes
59
- # @return [void]
60
- def method_missing(type, *helpers, **options, &block)
61
- name = helpers.shift
62
-
63
- # If no attribute name provided, this is not an attribute definition
64
- # Pass to super to handle it properly (e.g., for methods like 'info', 'call!', etc.)
65
- return super if name.nil?
66
-
67
- attribute(name, type, *helpers, **options, &block)
68
- end
69
-
70
- def respond_to_missing?(name, *)
71
- super
72
- end
73
-
74
- private
75
-
76
- # Creates an attribute instance (must be implemented by including class)
77
- #
78
- # @raise [Treaty::Exceptions::NotImplemented] If not implemented
79
- # @return [Attribute::Base] Created attribute instance
80
- def create_attribute(*)
81
- raise Treaty::Exceptions::NotImplemented,
82
- I18n.t(
83
- "treaty.attributes.dsl.create_attribute_not_implemented",
84
- class: self
85
- )
86
- end
87
- end
88
- end
89
- end
90
- end
@@ -1,46 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Treaty
4
- module Attribute
5
- module Entity
6
- # Entity-specific attribute builder
7
- class Builder < Treaty::Attribute::Builder::Base
8
- private
9
-
10
- def create_attribute(name, type, *helpers, nesting_level:, **options, &block)
11
- Attribute.new(
12
- name,
13
- type,
14
- *helpers,
15
- nesting_level:,
16
- **options,
17
- &block
18
- )
19
- end
20
-
21
- # Deep copies an attribute with adjusted nesting level for Entity context.
22
- #
23
- # @param source_attribute [Treaty::Attribute::Base] Attribute to copy
24
- # @param new_nesting_level [Integer] New nesting level
25
- # @return [Entity::Attribute] Copied attribute
26
- def deep_copy_attribute(source_attribute, new_nesting_level) # rubocop:disable Metrics/MethodLength
27
- copied = Attribute.new(
28
- source_attribute.name,
29
- source_attribute.type,
30
- nesting_level: new_nesting_level,
31
- **deep_copy_options(source_attribute.options)
32
- )
33
-
34
- return copied unless source_attribute.nested?
35
-
36
- source_attribute.collection_of_attributes.each do |nested_source|
37
- nested_copied = deep_copy_attribute(nested_source, new_nesting_level + 1)
38
- copied.collection_of_attributes << nested_copied
39
- end
40
-
41
- copied
42
- end
43
- end
44
- end
45
- end
46
- end