treaty 0.6.0 → 0.8.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 (57) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +9 -4
  3. data/config/locales/en.yml +6 -4
  4. data/lib/treaty/attribute/base.rb +15 -7
  5. data/lib/treaty/attribute/builder/base.rb +4 -4
  6. data/lib/treaty/attribute/collection.rb +1 -1
  7. data/lib/treaty/attribute/dsl.rb +90 -0
  8. data/lib/treaty/attribute/entity/attribute.rb +25 -0
  9. data/lib/treaty/attribute/entity/builder.rb +23 -0
  10. data/lib/treaty/attribute/option/base.rb +17 -1
  11. data/lib/treaty/attribute/option/modifiers/as_modifier.rb +5 -3
  12. data/lib/treaty/attribute/option/modifiers/default_modifier.rb +1 -1
  13. data/lib/treaty/attribute/option/registry.rb +4 -4
  14. data/lib/treaty/attribute/option/validators/inclusion_validator.rb +20 -8
  15. data/lib/treaty/attribute/option/validators/required_validator.rb +8 -2
  16. data/lib/treaty/attribute/option/validators/type_validator.rb +51 -40
  17. data/lib/treaty/attribute/option_orchestrator.rb +8 -6
  18. data/lib/treaty/attribute/validation/nested_array_validator.rb +21 -15
  19. data/lib/treaty/attribute/validation/nested_transformer.rb +24 -18
  20. data/lib/treaty/attribute/validation/orchestrator/base.rb +67 -83
  21. data/lib/treaty/base.rb +1 -1
  22. data/lib/treaty/controller/dsl.rb +4 -1
  23. data/lib/treaty/entity.rb +84 -0
  24. data/lib/treaty/exceptions/nested_attributes.rb +2 -2
  25. data/lib/treaty/info/entity/builder.rb +50 -0
  26. data/lib/treaty/info/entity/dsl.rb +28 -0
  27. data/lib/treaty/info/entity/result.rb +15 -0
  28. data/lib/treaty/info/rest/builder.rb +110 -0
  29. data/lib/treaty/info/rest/dsl.rb +28 -0
  30. data/lib/treaty/info/rest/result.rb +15 -0
  31. data/lib/treaty/request/attribute/attribute.rb +1 -0
  32. data/lib/treaty/request/attribute/builder.rb +1 -0
  33. data/lib/treaty/request/entity.rb +33 -0
  34. data/lib/treaty/request/factory.rb +63 -14
  35. data/lib/treaty/request/validator.rb +65 -0
  36. data/lib/treaty/response/attribute/attribute.rb +1 -0
  37. data/lib/treaty/response/attribute/builder.rb +1 -0
  38. data/lib/treaty/response/entity.rb +33 -0
  39. data/lib/treaty/response/factory.rb +63 -14
  40. data/lib/treaty/response/validator.rb +57 -0
  41. data/lib/treaty/version.rb +1 -1
  42. data/lib/treaty/versions/execution/request.rb +10 -5
  43. data/lib/treaty/versions/factory.rb +16 -5
  44. data/lib/treaty/versions/resolver.rb +8 -2
  45. data/lib/treaty/versions/workspace.rb +2 -2
  46. metadata +15 -12
  47. data/lib/treaty/info/builder.rb +0 -122
  48. data/lib/treaty/info/dsl.rb +0 -26
  49. data/lib/treaty/info/result.rb +0 -13
  50. data/lib/treaty/request/attribute/validation/orchestrator.rb +0 -27
  51. data/lib/treaty/request/attribute/validator.rb +0 -50
  52. data/lib/treaty/request/scope/collection.rb +0 -21
  53. data/lib/treaty/request/scope/factory.rb +0 -42
  54. data/lib/treaty/response/attribute/validation/orchestrator.rb +0 -27
  55. data/lib/treaty/response/attribute/validator.rb +0 -44
  56. data/lib/treaty/response/scope/collection.rb +0 -21
  57. data/lib/treaty/response/scope/factory.rb +0 -42
@@ -8,7 +8,7 @@ module Treaty
8
8
  # ## Purpose
9
9
  #
10
10
  # Performs validation for nested array attributes during the validation phase.
11
- # Handles both simple arrays (with :_self scope) and complex arrays (objects).
11
+ # Handles both simple arrays (with :_self attribute) and complex arrays (objects).
12
12
  #
13
13
  # ## Responsibilities
14
14
  #
@@ -19,7 +19,7 @@ module Treaty
19
19
  #
20
20
  # ## Array Types
21
21
  #
22
- # ### Simple Array (`:_self` scope)
22
+ # ### Simple Array (`:_self` attribute)
23
23
  # Array containing primitive values (strings, integers, etc.)
24
24
  #
25
25
  # ```ruby
@@ -93,7 +93,7 @@ module Treaty
93
93
 
94
94
  private
95
95
 
96
- # Validates array item for simple arrays (with :_self scope)
96
+ # Validates array item for simple arrays (with :_self attribute)
97
97
  # Simple array contains primitive values: strings, integers, datetimes, etc.
98
98
  # Example: ["ruby", "rails", "api"] where each item is a String
99
99
  #
@@ -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
 
@@ -6,8 +6,8 @@ module Treaty
6
6
  # Handles transformation of nested attributes (objects and arrays).
7
7
  # Extracted from Orchestrator::Base to reduce complexity.
8
8
  class NestedTransformer
9
- SELF_SCOPE = :_self
10
- private_constant :SELF_SCOPE
9
+ SELF_OBJECT = :_self
10
+ private_constant :SELF_OBJECT
11
11
 
12
12
  attr_reader :attribute
13
13
 
@@ -118,8 +118,8 @@ module Treaty
118
118
 
119
119
  # Transforms array with nested attributes
120
120
  class ArrayTransformer
121
- SELF_SCOPE = :_self
122
- private_constant :SELF_SCOPE
121
+ SELF_OBJECT = :_self
122
+ private_constant :SELF_OBJECT
123
123
 
124
124
  attr_reader :attribute
125
125
 
@@ -150,10 +150,10 @@ module Treaty
150
150
 
151
151
  # Checks if this is a simple array (primitive values)
152
152
  #
153
- # @return [Boolean] True if array contains primitive values with :_self scope
153
+ # @return [Boolean] True if array contains primitive values with :_self attribute
154
154
  def simple_array?
155
155
  attribute.collection_of_attributes.size == 1 &&
156
- attribute.collection_of_attributes.first.name == SELF_SCOPE
156
+ attribute.collection_of_attributes.first.name == SELF_OBJECT
157
157
  end
158
158
 
159
159
  # Validates a simple array element (primitive value)
@@ -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
@@ -9,12 +9,12 @@ module Treaty
9
9
  # ## Purpose
10
10
  #
11
11
  # Coordinates the validation and transformation of request/response data for a specific
12
- # API version. Processes all scopes and their attributes, applying validations and
13
- # transformations defined in the treaty DSL.
12
+ # API version. Processes all attributes, applying validations and transformations
13
+ # defined in the treaty DSL.
14
14
  #
15
15
  # ## Responsibilities
16
16
  #
17
- # 1. **Scope Processing** - Iterates through all defined scopes
17
+ # 1. **Attribute Processing** - Iterates through all defined attributes
18
18
  # 2. **Attribute Validation** - Validates each attribute's value
19
19
  # 3. **Data Transformation** - Transforms values (defaults, renaming)
20
20
  # 4. **Nested Handling** - Delegates nested structures to NestedTransformer
@@ -23,17 +23,16 @@ module Treaty
23
23
  # ## Usage
24
24
  #
25
25
  # Subclasses must implement:
26
- # - `collection_of_scopes` - Returns scopes for this context (request/response)
27
- # - `scope_data_for(name)` - Extracts data for a specific scope
26
+ # - `collection_of_attributes` - Returns attributes for this context (request/response)
28
27
  #
29
28
  # Example:
30
29
  # orchestrator = Request::Orchestrator.new(version_factory: factory, data: params)
31
30
  # validated_data = orchestrator.validate!
32
31
  #
33
- # ## Special Scopes
32
+ # ## Special Case: object :_self
34
33
  #
35
- # - Normal scope: `{ scope_name: { ... } }`
36
- # - Self scope (`:_self`): Attributes merged directly into parent
34
+ # - Normal object: `{ object_name: { ... } }`
35
+ # - Self object (`:_self`): Attributes merged directly into parent
37
36
  #
38
37
  # ## Architecture
39
38
  #
@@ -41,13 +40,13 @@ module Treaty
41
40
  # - `AttributeValidator` - Validates individual attributes
42
41
  # - `NestedTransformer` - Handles nested objects and arrays
43
42
  #
44
- # The refactored design separates concerns:
45
- # - Orchestrator: High-level flow and scope iteration
43
+ # The design separates concerns:
44
+ # - Orchestrator: High-level flow and attribute iteration
46
45
  # - Validator: Individual attribute validation
47
46
  # - Transformer: Nested structure transformation
48
47
  class Base
49
- SELF_SCOPE = :_self
50
- private_constant :SELF_SCOPE
48
+ SELF_OBJECT = :_self
49
+ private_constant :SELF_OBJECT
51
50
 
52
51
  attr_reader :version_factory, :data
53
52
 
@@ -69,17 +68,22 @@ module Treaty
69
68
  @data = data
70
69
  end
71
70
 
72
- # Validates and transforms all scopes
73
- # Iterates through scopes, processes attributes, handles :_self scope
71
+ # Validates and transforms all attributes
72
+ # Iterates through attributes, processes them, handles :_self objects
74
73
  #
75
- # @return [Hash] Transformed data with all scopes processed
74
+ # @return [Hash] Transformed data with all attributes processed
76
75
  def validate!
77
76
  transformed_data = {}
78
77
 
79
- collection_of_scopes.each do |scope_factory|
80
- transformed_scope_data = validate_and_transform_scope!(scope_factory)
81
- transformed_data[scope_factory.name] = transformed_scope_data if scope_factory.name != SELF_SCOPE
82
- transformed_data.merge!(transformed_scope_data) if scope_factory.name == SELF_SCOPE
78
+ collection_of_attributes.each do |attribute|
79
+ transformed_value = validate_and_transform_attribute!(attribute)
80
+
81
+ if attribute.name == SELF_OBJECT && attribute.type == :object
82
+ # For object :_self, merge nested attributes to root
83
+ transformed_data.merge!(transformed_value)
84
+ else
85
+ transformed_data[attribute.name] = transformed_value
86
+ end
83
87
  end
84
88
 
85
89
  transformed_data
@@ -87,103 +91,83 @@ module Treaty
87
91
 
88
92
  private
89
93
 
90
- # Returns collection of scopes for this context
94
+ # Returns collection of attributes for this context
91
95
  # Must be implemented in subclasses
92
96
  #
93
97
  # @raise [Treaty::Exceptions::Validation] If not implemented
94
- # @return [Array<ScopeFactory>] Collection of scope factories
95
- def collection_of_scopes
98
+ # @return [Treaty::Attribute::Collection] Collection of attributes
99
+ def collection_of_attributes
96
100
  raise Treaty::Exceptions::Validation,
97
101
  I18n.t("treaty.attributes.validators.nested.orchestrator.collection_not_implemented")
98
102
  end
99
103
 
100
- # Validates all attributes in a scope (deprecated, not used)
101
- #
102
- # @param scope_factory [ScopeFactory] The scope to validate
103
- # @return [void]
104
- def validate_scope!(scope_factory)
105
- scope_data = scope_data_for(scope_factory.name)
106
-
107
- validators_for_scope(scope_factory).each do |attribute, validator|
108
- value = scope_data.fetch(attribute.name, nil)
109
- validator.validate_value!(value)
110
- end
111
- end
112
-
113
- # Gets cached validators for scope or builds them
104
+ # Gets cached validators for attributes or builds them
114
105
  #
115
- # @param scope_factory [ScopeFactory] The scope factory
116
106
  # @return [Hash] Hash of attribute => validator
117
- def validators_for_scope(scope_factory)
118
- @validators_cache ||= {}
119
- @validators_cache[scope_factory] ||= build_validators_for_scope(scope_factory)
107
+ def validators_for_attributes
108
+ @validators_for_attributes ||= build_validators_for_attributes
120
109
  end
121
110
 
122
- # Builds validators for all attributes in a scope
111
+ # Builds validators for all attributes
123
112
  #
124
- # @param scope_factory [ScopeFactory] The scope factory
125
113
  # @return [Hash] Hash of attribute => validator
126
- def build_validators_for_scope(scope_factory)
127
- scope_factory.collection_of_attributes.each_with_object({}) do |attribute, cache|
114
+ def build_validators_for_attributes
115
+ collection_of_attributes.each_with_object({}) do |attribute, cache|
128
116
  validator = AttributeValidator.new(attribute)
129
117
  validator.validate_schema!
130
118
  cache[attribute] = validator
131
119
  end
132
120
  end
133
121
 
134
- # Extracts data for a specific scope
135
- # Must be implemented in subclasses
136
- #
137
- # @param _name [Symbol] The scope name
138
- # @raise [Treaty::Exceptions::Validation] If not implemented
139
- # @return [Hash] Scope data
140
- def scope_data_for(_name)
141
- raise Treaty::Exceptions::Validation,
142
- I18n.t("treaty.attributes.validators.nested.orchestrator.scope_data_not_implemented")
143
- end
144
-
145
- # Validates and transforms all attributes in a scope
122
+ # Validates and transforms a single attribute
146
123
  # Handles both nested and regular attributes
147
124
  #
148
- # @param scope_factory [ScopeFactory] The scope to process
149
- # @return [Hash] Transformed scope data
150
- def validate_and_transform_scope!(scope_factory) # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
151
- scope_data = scope_data_for(scope_factory.name)
152
-
153
- return scope_data if scope_factory.collection_of_attributes.empty?
154
-
155
- transformed_scope_data = {}
156
-
157
- validators_for_scope(scope_factory).each do |attribute, validator|
158
- source_name = attribute.name
159
- value = scope_data.fetch(source_name, nil)
160
-
161
- if attribute.nested?
162
- transformed_value = validate_and_transform_nested(attribute, value, validator)
163
- else
164
- validator.validate_value!(value)
165
- transformed_value = validator.transform_value(value)
166
- end
167
-
168
- target_name = validator.target_name
169
-
170
- transformed_scope_data[target_name] = transformed_value
125
+ # @param attribute [Attribute] The attribute to process
126
+ # @return [Object] Transformed attribute value
127
+ def validate_and_transform_attribute!(attribute) # rubocop:disable Metrics/MethodLength
128
+ validator = validators_for_attributes.fetch(attribute)
129
+
130
+ # For :_self object, get data from root; otherwise from attribute key
131
+ value = if attribute.name == SELF_OBJECT && attribute.type == :object
132
+ data
133
+ else
134
+ data.fetch(attribute.name, nil)
135
+ end
136
+
137
+ if attribute.nested?
138
+ validate_and_transform_nested(attribute, value, validator)
139
+ else
140
+ validator.validate_value!(value)
141
+ validator.transform_value(value)
171
142
  end
172
-
173
- transformed_scope_data
174
143
  end
175
144
 
176
145
  # Validates and transforms nested attribute (object/array)
177
146
  # Delegates transformation to NestedTransformer
178
147
  #
179
148
  # @param attribute [Attribute::Base] The nested attribute
180
- # @param value [Object] The value to validate and transform
149
+ # @param value [Object, nil] The value to validate and transform
181
150
  # @param validator [AttributeValidator] The validator instance
182
- # @return [Object] Transformed nested value
151
+ # @return [Object, nil] Transformed nested value or nil
152
+ #
153
+ # @note Flow control:
154
+ # - If value is nil and attribute is required → validate_required! raises exception
155
+ # - If value is nil and attribute is optional → validate_required! does nothing, returns nil
156
+ # - If value is not nil → proceeds to transformation (value guaranteed non-nil)
183
157
  def validate_and_transform_nested(attribute, value, validator)
158
+ # Step 1: Validate type if value is present
184
159
  validator.validate_type!(value) unless value.nil?
160
+
161
+ # Step 2: Validate required constraint
162
+ # This will raise an exception if attribute is required and value is nil
185
163
  validator.validate_required!(value)
186
164
 
165
+ # Step 3: Early return for nil values
166
+ # Only reaches here if attribute is optional and value is nil
167
+ return nil if value.nil?
168
+
169
+ # Step 4: Transform non-nil value
170
+ # At this point, value is guaranteed to be non-nil
187
171
  transformer = NestedTransformer.new(attribute)
188
172
  transformer.transform(value)
189
173
  end
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
@@ -18,7 +18,7 @@ module Treaty
18
18
  #
19
19
  # ```ruby
20
20
  # request do
21
- # scope :user do
21
+ # object :user do
22
22
  # object :profile do
23
23
  # object :settings do
24
24
  # object :preferences do
@@ -57,7 +57,7 @@ module Treaty
57
57
  #
58
58
  # - Keep nesting shallow (2-3 levels maximum)
59
59
  # - Consider flattening deeply nested structures
60
- # - Use separate scopes instead of deep nesting
60
+ # - Use separate objects instead of deep nesting
61
61
  # - Refactor complex structures into simpler ones
62
62
  class NestedAttributes < Base
63
63
  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