treaty 0.7.0 → 0.9.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 (49) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +5 -0
  3. data/config/locales/en.yml +8 -0
  4. data/lib/treaty/attribute/base.rb +13 -5
  5. data/lib/treaty/attribute/dsl.rb +90 -0
  6. data/lib/treaty/attribute/entity/attribute.rb +25 -0
  7. data/lib/treaty/attribute/entity/builder.rb +23 -0
  8. data/lib/treaty/attribute/option/base.rb +17 -1
  9. data/lib/treaty/attribute/option/modifiers/as_modifier.rb +5 -3
  10. data/lib/treaty/attribute/option/registry_initializer.rb +2 -0
  11. data/lib/treaty/attribute/option/validators/format_validator.rb +220 -0
  12. data/lib/treaty/attribute/option/validators/inclusion_validator.rb +20 -8
  13. data/lib/treaty/attribute/option/validators/required_validator.rb +8 -2
  14. data/lib/treaty/attribute/option/validators/type_validator.rb +51 -40
  15. data/lib/treaty/attribute/option_orchestrator.rb +7 -5
  16. data/lib/treaty/attribute/validation/nested_array_validator.rb +18 -12
  17. data/lib/treaty/attribute/validation/nested_transformer.rb +18 -12
  18. data/lib/treaty/base.rb +1 -1
  19. data/lib/treaty/controller/dsl.rb +4 -1
  20. data/lib/treaty/entity.rb +84 -0
  21. data/lib/treaty/info/entity/builder.rb +50 -0
  22. data/lib/treaty/info/entity/dsl.rb +28 -0
  23. data/lib/treaty/info/entity/result.rb +15 -0
  24. data/lib/treaty/info/rest/builder.rb +110 -0
  25. data/lib/treaty/info/rest/dsl.rb +28 -0
  26. data/lib/treaty/info/rest/result.rb +15 -0
  27. data/lib/treaty/request/attribute/attribute.rb +1 -0
  28. data/lib/treaty/request/attribute/builder.rb +1 -0
  29. data/lib/treaty/request/entity.rb +33 -0
  30. data/lib/treaty/request/factory.rb +61 -14
  31. data/lib/treaty/request/validator.rb +65 -0
  32. data/lib/treaty/response/attribute/attribute.rb +1 -0
  33. data/lib/treaty/response/attribute/builder.rb +1 -0
  34. data/lib/treaty/response/entity.rb +33 -0
  35. data/lib/treaty/response/factory.rb +61 -14
  36. data/lib/treaty/response/validator.rb +57 -0
  37. data/lib/treaty/version.rb +1 -1
  38. data/lib/treaty/versions/execution/request.rb +10 -5
  39. data/lib/treaty/versions/factory.rb +16 -5
  40. data/lib/treaty/versions/resolver.rb +8 -2
  41. data/lib/treaty/versions/workspace.rb +2 -2
  42. metadata +16 -8
  43. data/lib/treaty/info/builder.rb +0 -108
  44. data/lib/treaty/info/dsl.rb +0 -26
  45. data/lib/treaty/info/result.rb +0 -13
  46. data/lib/treaty/request/attribute/validation/orchestrator.rb +0 -19
  47. data/lib/treaty/request/attribute/validator.rb +0 -50
  48. data/lib/treaty/response/attribute/validation/orchestrator.rb +0 -19
  49. data/lib/treaty/response/attribute/validator.rb +0 -44
@@ -53,10 +53,12 @@ module Treaty
53
53
  return if ALLOWED_TYPES.include?(@attribute_type)
54
54
 
55
55
  raise Treaty::Exceptions::Validation,
56
- I18n.t("treaty.attributes.validators.type.unknown_type",
57
- type: @attribute_type,
58
- attribute: @attribute_name,
59
- allowed: ALLOWED_TYPES.join(", "))
56
+ I18n.t(
57
+ "treaty.attributes.validators.type.unknown_type",
58
+ type: @attribute_type,
59
+ attribute: @attribute_name,
60
+ allowed: ALLOWED_TYPES.join(", ")
61
+ )
60
62
  end
61
63
 
62
64
  # Validates that the value matches the declared type
@@ -86,18 +88,52 @@ module Treaty
86
88
 
87
89
  private
88
90
 
91
+ # Common type validation logic
92
+ # Checks if value matches expected type and raises exception with appropriate message
93
+ #
94
+ # @param value [Object] The value to validate
95
+ # @param expected_type [Symbol] The expected type symbol
96
+ # @yield Block that returns true if value is valid
97
+ # @raise [Treaty::Exceptions::Validation] If type validation fails
98
+ # @return [void]
99
+ def validate_type!(value, expected_type)
100
+ return if yield(value)
101
+
102
+ actual_type = value.class
103
+
104
+ attributes = {
105
+ attribute: @attribute_name,
106
+ value:,
107
+ expected_type:,
108
+ actual_type:
109
+ }
110
+
111
+ message = resolve_custom_message(**attributes) || default_message(**attributes)
112
+
113
+ raise Treaty::Exceptions::Validation, message
114
+ end
115
+
116
+ # Generates default error message for type mismatch using I18n
117
+ #
118
+ # @param attribute [Symbol] The attribute name
119
+ # @param expected_type [Symbol] The expected type
120
+ # @param actual_type [Class] The actual class of the value
121
+ # @return [String] Default error message
122
+ def default_message(attribute:, expected_type:, actual_type:, **)
123
+ I18n.t(
124
+ "treaty.attributes.validators.type.mismatch.#{expected_type}",
125
+ attribute:,
126
+ actual: actual_type
127
+ )
128
+ end
129
+
89
130
  # Validates that value is an Integer
90
131
  #
91
132
  # @param value [Object] The value to validate
92
133
  # @raise [Treaty::Exceptions::Validation] If value is not an Integer
93
134
  # @return [void]
94
135
  def validate_integer!(value)
95
- return if value.is_a?(Integer)
96
-
97
- raise Treaty::Exceptions::Validation,
98
- I18n.t("treaty.attributes.validators.type.mismatch.integer",
99
- attribute: @attribute_name,
100
- actual: value.class)
136
+ validate_type!(value, :integer) { |v| v.is_a?(Integer) }
101
137
  end
102
138
 
103
139
  # Validates that value is a String
@@ -106,12 +142,7 @@ module Treaty
106
142
  # @raise [Treaty::Exceptions::Validation] If value is not a String
107
143
  # @return [void]
108
144
  def validate_string!(value)
109
- return if value.is_a?(String)
110
-
111
- raise Treaty::Exceptions::Validation,
112
- I18n.t("treaty.attributes.validators.type.mismatch.string",
113
- attribute: @attribute_name,
114
- actual: value.class)
145
+ validate_type!(value, :string) { |v| v.is_a?(String) }
115
146
  end
116
147
 
117
148
  # Validates that value is a Boolean (TrueClass or FalseClass)
@@ -120,12 +151,7 @@ module Treaty
120
151
  # @raise [Treaty::Exceptions::Validation] If value is not a Boolean
121
152
  # @return [void]
122
153
  def validate_boolean!(value)
123
- return if value.is_a?(TrueClass) || value.is_a?(FalseClass)
124
-
125
- raise Treaty::Exceptions::Validation,
126
- I18n.t("treaty.attributes.validators.type.mismatch.boolean",
127
- attribute: @attribute_name,
128
- actual: value.class)
154
+ validate_type!(value, :boolean) { |v| v.is_a?(TrueClass) || v.is_a?(FalseClass) }
129
155
  end
130
156
 
131
157
  # Validates that value is a Hash (object type)
@@ -134,12 +160,7 @@ module Treaty
134
160
  # @raise [Treaty::Exceptions::Validation] If value is not a Hash
135
161
  # @return [void]
136
162
  def validate_object!(value)
137
- return if value.is_a?(Hash)
138
-
139
- raise Treaty::Exceptions::Validation,
140
- I18n.t("treaty.attributes.validators.type.mismatch.object",
141
- attribute: @attribute_name,
142
- actual: value.class)
163
+ validate_type!(value, :object) { |v| v.is_a?(Hash) }
143
164
  end
144
165
 
145
166
  # Validates that value is an Array
@@ -148,12 +169,7 @@ module Treaty
148
169
  # @raise [Treaty::Exceptions::Validation] If value is not an Array
149
170
  # @return [void]
150
171
  def validate_array!(value)
151
- return if value.is_a?(Array)
152
-
153
- raise Treaty::Exceptions::Validation,
154
- I18n.t("treaty.attributes.validators.type.mismatch.array",
155
- attribute: @attribute_name,
156
- actual: value.class)
172
+ validate_type!(value, :array) { |v| v.is_a?(Array) }
157
173
  end
158
174
 
159
175
  # Validates that value is a DateTime, Time, or Date
@@ -163,12 +179,7 @@ module Treaty
163
179
  # @return [void]
164
180
  def validate_datetime!(value)
165
181
  # TODO: It is better to divide it into different methods for each class.
166
- return if value.is_a?(DateTime) || value.is_a?(Time) || value.is_a?(Date)
167
-
168
- raise Treaty::Exceptions::Validation,
169
- I18n.t("treaty.attributes.validators.type.mismatch.datetime",
170
- attribute: @attribute_name,
171
- actual: value.class)
182
+ validate_type!(value, :datetime) { |v| v.is_a?(DateTime) || v.is_a?(Time) || v.is_a?(Date) }
172
183
  end
173
184
  end
174
185
  end
@@ -146,7 +146,7 @@ module Treaty
146
146
  @attribute.options.each do |option_name, option_schema|
147
147
  processor_class = Option::Registry.processor_for(option_name)
148
148
 
149
- next unless processor_class
149
+ next if processor_class.nil?
150
150
 
151
151
  processors_hash[option_name] = processor_class.new(
152
152
  attribute_name: @attribute.name,
@@ -177,10 +177,12 @@ module Treaty
177
177
  return if unknown_options.empty?
178
178
 
179
179
  raise Treaty::Exceptions::Validation,
180
- I18n.t("treaty.attributes.options.unknown",
181
- attribute: @attribute.name,
182
- unknown: unknown_options.join(", "),
183
- known: Option::Registry.all_options.join(", "))
180
+ I18n.t(
181
+ "treaty.attributes.options.unknown",
182
+ attribute: @attribute.name,
183
+ unknown: unknown_options.join(", "),
184
+ known: Option::Registry.all_options.join(", ")
185
+ )
184
186
  end
185
187
  end
186
188
  end
@@ -115,10 +115,12 @@ module Treaty
115
115
  return if validated
116
116
 
117
117
  raise Treaty::Exceptions::Validation,
118
- I18n.t("treaty.attributes.validators.nested.array.element_validation_error",
119
- attribute: @attribute.name,
120
- index:,
121
- errors: errors.join("; "))
118
+ I18n.t(
119
+ "treaty.attributes.validators.nested.array.element_validation_error",
120
+ attribute: @attribute.name,
121
+ index:,
122
+ errors: errors.join("; ")
123
+ )
122
124
  end
123
125
 
124
126
  # Validates array item for complex arrays (with regular attributes)
@@ -132,10 +134,12 @@ module Treaty
132
134
  def validate_regular_array_item!(array_item, index) # rubocop:disable Metrics/MethodLength
133
135
  unless array_item.is_a?(Hash)
134
136
  raise Treaty::Exceptions::Validation,
135
- I18n.t("treaty.attributes.validators.nested.array.element_type_error",
136
- attribute: @attribute.name,
137
- index:,
138
- actual: array_item.class)
137
+ I18n.t(
138
+ "treaty.attributes.validators.nested.array.element_type_error",
139
+ attribute: @attribute.name,
140
+ index:,
141
+ actual: array_item.class
142
+ )
139
143
  end
140
144
 
141
145
  regular_validators.each do |nested_attribute, validator|
@@ -143,10 +147,12 @@ module Treaty
143
147
  validator.validate_value!(nested_value)
144
148
  rescue Treaty::Exceptions::Validation => e
145
149
  raise Treaty::Exceptions::Validation,
146
- I18n.t("treaty.attributes.validators.nested.array.attribute_error",
147
- attribute: @attribute.name,
148
- index:,
149
- message: e.message)
150
+ I18n.t(
151
+ "treaty.attributes.validators.nested.array.attribute_error",
152
+ attribute: @attribute.name,
153
+ index:,
154
+ message: e.message
155
+ )
150
156
  end
151
157
  end
152
158
 
@@ -171,10 +171,12 @@ module Treaty
171
171
  validator.validate_value!(item)
172
172
  rescue Treaty::Exceptions::Validation => e
173
173
  raise Treaty::Exceptions::Validation,
174
- I18n.t("treaty.attributes.validators.nested.array.element_validation_error",
175
- attribute: attribute.name,
176
- index:,
177
- errors: e.message)
174
+ I18n.t(
175
+ "treaty.attributes.validators.nested.array.element_validation_error",
176
+ attribute: attribute.name,
177
+ index:,
178
+ errors: e.message
179
+ )
178
180
  end
179
181
  end
180
182
 
@@ -187,10 +189,12 @@ module Treaty
187
189
  def transform_array_item(item, index) # rubocop:disable Metrics/MethodLength
188
190
  unless item.is_a?(Hash)
189
191
  raise Treaty::Exceptions::Validation,
190
- I18n.t("treaty.attributes.validators.nested.array.element_type_error",
191
- attribute: attribute.name,
192
- index:,
193
- actual: item.class)
192
+ I18n.t(
193
+ "treaty.attributes.validators.nested.array.element_type_error",
194
+ attribute: attribute.name,
195
+ index:,
196
+ actual: item.class
197
+ )
194
198
  end
195
199
 
196
200
  transformed = {}
@@ -230,10 +234,12 @@ module Treaty
230
234
  end
231
235
  rescue Treaty::Exceptions::Validation => e
232
236
  raise Treaty::Exceptions::Validation,
233
- I18n.t("treaty.attributes.validators.nested.array.attribute_error",
234
- attribute: attribute.name,
235
- index:,
236
- message: e.message)
237
+ I18n.t(
238
+ "treaty.attributes.validators.nested.array.attribute_error",
239
+ attribute: attribute.name,
240
+ index:,
241
+ message: e.message
242
+ )
237
243
  end
238
244
 
239
245
  target_name = validator.target_name
data/lib/treaty/base.rb CHANGED
@@ -2,7 +2,7 @@
2
2
 
3
3
  module Treaty
4
4
  class Base
5
- include Info::DSL
5
+ include Info::Rest::DSL
6
6
  include Context::DSL
7
7
  include Versions::DSL
8
8
  end
@@ -25,7 +25,10 @@ module Treaty
25
25
  treaty_class_name.constantize
26
26
  rescue NameError
27
27
  raise Treaty::Exceptions::ClassName,
28
- I18n.t("treaty.controller.treaty_class_not_found", class_name: treaty_class_name)
28
+ I18n.t(
29
+ "treaty.controller.treaty_class_not_found",
30
+ class_name: treaty_class_name
31
+ )
29
32
  end
30
33
 
31
34
  def treaty_class_name
@@ -0,0 +1,84 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Treaty
4
+ # Base class for defining DTO (Data Transfer Object) entities in Treaty.
5
+ #
6
+ # ## Purpose
7
+ #
8
+ # Treaty::Entity provides a base class for creating reusable DTO classes
9
+ # that can be used in both request and response definitions. This allows
10
+ # for better code organization and reusability of common data structures.
11
+ #
12
+ # ## Usage
13
+ #
14
+ # Create a DTO class by inheriting from Treaty::Entity:
15
+ #
16
+ # ```ruby
17
+ # class PostEntity < Treaty::Entity
18
+ # string :id
19
+ # string :title
20
+ # string :content
21
+ # datetime :created_at
22
+ # end
23
+ # ```
24
+ #
25
+ # Then use it in your treaty definitions:
26
+ #
27
+ # ```ruby
28
+ # class CreateTreaty < ApplicationTreaty
29
+ # version 1 do
30
+ # request PostEntity
31
+ # response 201, PostEntity
32
+ # end
33
+ # end
34
+ # ```
35
+ #
36
+ # ## Attribute Defaults
37
+ #
38
+ # Unlike request/response blocks, Entity attributes are required by default:
39
+ # - All attributes have `required: true` unless explicitly marked as `:optional`
40
+ # - Use `:optional` helper to make attributes optional:
41
+ # ```ruby
42
+ # string :title # required by default
43
+ # string :summary, :optional # optional
44
+ # ```
45
+ #
46
+ # ## Features
47
+ #
48
+ # - **Type Safety** - Enforce strict type checking for all attributes
49
+ # - **Nested Structures** - Support for nested objects and arrays
50
+ # - **Validation** - Built-in validation for all attribute types
51
+ # - **Reusability** - Define once, use in multiple treaties
52
+ # - **Options** - Full support for attribute options (required, default, as, etc.)
53
+ #
54
+ # ## Supported Types
55
+ #
56
+ # - `string` - String values
57
+ # - `integer` - Integer values
58
+ # - `boolean` - Boolean values (true/false)
59
+ # - `datetime` - DateTime values
60
+ # - `array` - Array values (with nested type definition)
61
+ # - `object` - Object values (with nested attributes)
62
+ class Entity
63
+ include Info::Entity::DSL
64
+ include Attribute::DSL
65
+
66
+ class << self
67
+ private
68
+
69
+ # Creates an Attribute::Entity::Attribute for this Entity class
70
+ #
71
+ # @return [Attribute::Entity::Attribute] Created attribute instance
72
+ def create_attribute(name, type, *helpers, nesting_level:, **options, &block)
73
+ Attribute::Entity::Attribute.new(
74
+ name,
75
+ type,
76
+ *helpers,
77
+ nesting_level:,
78
+ **options,
79
+ &block
80
+ )
81
+ end
82
+ end
83
+ end
84
+ end
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Treaty
4
+ module Info
5
+ module Entity
6
+ class Builder
7
+ attr_reader :attributes
8
+
9
+ def self.build(...)
10
+ new.build(...)
11
+ end
12
+
13
+ def build(collection_of_attributes:)
14
+ build_all(
15
+ attributes: collection_of_attributes
16
+ )
17
+
18
+ self
19
+ end
20
+
21
+ private
22
+
23
+ def build_all(attributes:)
24
+ @attributes = build_versions_with(attributes)
25
+ end
26
+
27
+ ##########################################################################
28
+
29
+ def build_versions_with(collection, current_level = 0)
30
+ collection.to_h do |attribute|
31
+ [
32
+ attribute.name,
33
+ {
34
+ type: attribute.type,
35
+ options: attribute.options,
36
+ attributes: build_nested_attributes(attribute, current_level)
37
+ }
38
+ ]
39
+ end
40
+ end
41
+
42
+ def build_nested_attributes(attribute, current_level)
43
+ return {} unless attribute.nested?
44
+
45
+ build_versions_with(attribute.collection_of_attributes, current_level + 1)
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Treaty
4
+ module Info
5
+ module Entity
6
+ module DSL
7
+ def self.included(base)
8
+ base.extend(ClassMethods)
9
+ end
10
+
11
+ module ClassMethods
12
+ def info
13
+ builder = Builder.build(
14
+ collection_of_attributes:
15
+ )
16
+
17
+ Result.new(builder)
18
+ end
19
+
20
+ # API: Treaty Web
21
+ def treaty?
22
+ true
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Treaty
4
+ module Info
5
+ module Entity
6
+ class Result
7
+ attr_reader :attributes
8
+
9
+ def initialize(builder)
10
+ @attributes = builder.attributes
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,110 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Treaty
4
+ module Info
5
+ module Rest
6
+ class Builder
7
+ attr_reader :versions
8
+
9
+ def self.build(...)
10
+ new.build(...)
11
+ end
12
+
13
+ def build(collection_of_versions:)
14
+ build_all(
15
+ versions: collection_of_versions
16
+ )
17
+
18
+ self
19
+ end
20
+
21
+ private
22
+
23
+ def build_all(versions:)
24
+ build_versions_with(
25
+ collection: versions
26
+ )
27
+ end
28
+
29
+ ##########################################################################
30
+
31
+ def build_versions_with(collection:) # rubocop:disable Metrics/MethodLength
32
+ @versions = collection.map do |version|
33
+ gem_version = version.version.version
34
+ {
35
+ version: gem_version.version,
36
+ segments: gem_version.segments,
37
+ default: version.default_result,
38
+ summary: version.summary_text,
39
+ strategy: version.strategy_instance.code,
40
+ deprecated: version.deprecated_result,
41
+ executor: build_executor_with(version),
42
+ request: build_request_with(version),
43
+ response: build_response_with(version)
44
+ }
45
+ end
46
+ end
47
+
48
+ ##########################################################################
49
+
50
+ def build_executor_with(version)
51
+ {
52
+ executor: version.executor.executor,
53
+ method: version.executor.method
54
+ }
55
+ end
56
+
57
+ ##########################################################################
58
+
59
+ def build_request_with(version)
60
+ build_attributes_structure(version.request_factory)
61
+ end
62
+
63
+ def build_response_with(version)
64
+ response_factory = version.response_factory
65
+ {
66
+ status: response_factory.status
67
+ }.merge(build_attributes_structure(response_factory))
68
+ end
69
+
70
+ ##########################################################################
71
+
72
+ def build_attributes_structure(factory)
73
+ {
74
+ attributes: build_attributes_hash(factory.collection_of_attributes)
75
+ }
76
+ end
77
+
78
+ def build_attributes_hash(collection, current_level = 0)
79
+ # validate_nesting_level!(current_level)
80
+
81
+ collection.to_h do |attribute|
82
+ [
83
+ attribute.name,
84
+ {
85
+ type: attribute.type,
86
+ options: attribute.options,
87
+ attributes: build_nested_attributes(attribute, current_level)
88
+ }
89
+ ]
90
+ end
91
+ end
92
+
93
+ def build_nested_attributes(attribute, current_level)
94
+ return {} unless attribute.nested?
95
+
96
+ build_attributes_hash(attribute.collection_of_attributes, current_level + 1)
97
+ end
98
+
99
+ # def validate_nesting_level!(level)
100
+ # return unless level > Treaty::Engine.config.treaty.attribute_nesting_level
101
+ #
102
+ # raise Treaty::Exceptions::NestedAttributes,
103
+ # I18n.t("treaty.attributes.errors.nesting_level_exceeded",
104
+ # level:,
105
+ # max_level: Treaty::Engine.config.treaty.attribute_nesting_level)
106
+ # end
107
+ end
108
+ end
109
+ end
110
+ end
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Treaty
4
+ module Info
5
+ module Rest
6
+ module DSL
7
+ def self.included(base)
8
+ base.extend(ClassMethods)
9
+ end
10
+
11
+ module ClassMethods
12
+ def info
13
+ builder = Builder.build(
14
+ collection_of_versions:
15
+ )
16
+
17
+ Result.new(builder)
18
+ end
19
+
20
+ # API: Treaty Web
21
+ def treaty?
22
+ true
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Treaty
4
+ module Info
5
+ module Rest
6
+ class Result
7
+ attr_reader :versions
8
+
9
+ def initialize(builder)
10
+ @versions = builder.versions
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -3,6 +3,7 @@
3
3
  module Treaty
4
4
  module Request
5
5
  module Attribute
6
+ # Request-specific attribute that defaults to required: true
6
7
  class Attribute < Treaty::Attribute::Base
7
8
  private
8
9
 
@@ -3,6 +3,7 @@
3
3
  module Treaty
4
4
  module Request
5
5
  module Attribute
6
+ # Request-specific attribute builder
6
7
  class Builder < Treaty::Attribute::Builder::Base
7
8
  private
8
9
 
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Treaty
4
+ module Request
5
+ # Entity class for request definitions.
6
+ # Attributes are required by default.
7
+ #
8
+ # This class is used internally when defining request blocks.
9
+ # When you write a request block, Treaty creates an anonymous
10
+ # class based on Request::Entity.
11
+ class Entity
12
+ include Treaty::Attribute::DSL
13
+
14
+ class << self
15
+ private
16
+
17
+ # Creates a Request::Attribute::Attribute for this Request::Entity class
18
+ #
19
+ # @return [Request::Attribute::Attribute] Created attribute instance
20
+ def create_attribute(name, type, *helpers, nesting_level:, **options, &block)
21
+ Attribute::Attribute.new(
22
+ name,
23
+ type,
24
+ *helpers,
25
+ nesting_level:,
26
+ **options,
27
+ &block
28
+ )
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end