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.
- checksums.yaml +4 -4
- data/README.md +5 -0
- data/config/locales/en.yml +8 -0
- data/lib/treaty/attribute/base.rb +13 -5
- data/lib/treaty/attribute/dsl.rb +90 -0
- data/lib/treaty/attribute/entity/attribute.rb +25 -0
- data/lib/treaty/attribute/entity/builder.rb +23 -0
- data/lib/treaty/attribute/option/base.rb +17 -1
- data/lib/treaty/attribute/option/modifiers/as_modifier.rb +5 -3
- data/lib/treaty/attribute/option/registry_initializer.rb +2 -0
- data/lib/treaty/attribute/option/validators/format_validator.rb +220 -0
- data/lib/treaty/attribute/option/validators/inclusion_validator.rb +20 -8
- data/lib/treaty/attribute/option/validators/required_validator.rb +8 -2
- data/lib/treaty/attribute/option/validators/type_validator.rb +51 -40
- data/lib/treaty/attribute/option_orchestrator.rb +7 -5
- data/lib/treaty/attribute/validation/nested_array_validator.rb +18 -12
- data/lib/treaty/attribute/validation/nested_transformer.rb +18 -12
- data/lib/treaty/base.rb +1 -1
- data/lib/treaty/controller/dsl.rb +4 -1
- data/lib/treaty/entity.rb +84 -0
- data/lib/treaty/info/entity/builder.rb +50 -0
- data/lib/treaty/info/entity/dsl.rb +28 -0
- data/lib/treaty/info/entity/result.rb +15 -0
- data/lib/treaty/info/rest/builder.rb +110 -0
- data/lib/treaty/info/rest/dsl.rb +28 -0
- data/lib/treaty/info/rest/result.rb +15 -0
- data/lib/treaty/request/attribute/attribute.rb +1 -0
- data/lib/treaty/request/attribute/builder.rb +1 -0
- data/lib/treaty/request/entity.rb +33 -0
- data/lib/treaty/request/factory.rb +61 -14
- data/lib/treaty/request/validator.rb +65 -0
- data/lib/treaty/response/attribute/attribute.rb +1 -0
- data/lib/treaty/response/attribute/builder.rb +1 -0
- data/lib/treaty/response/entity.rb +33 -0
- data/lib/treaty/response/factory.rb +61 -14
- data/lib/treaty/response/validator.rb +57 -0
- data/lib/treaty/version.rb +1 -1
- data/lib/treaty/versions/execution/request.rb +10 -5
- data/lib/treaty/versions/factory.rb +16 -5
- data/lib/treaty/versions/resolver.rb +8 -2
- data/lib/treaty/versions/workspace.rb +2 -2
- metadata +16 -8
- data/lib/treaty/info/builder.rb +0 -108
- data/lib/treaty/info/dsl.rb +0 -26
- data/lib/treaty/info/result.rb +0 -13
- data/lib/treaty/request/attribute/validation/orchestrator.rb +0 -19
- data/lib/treaty/request/attribute/validator.rb +0 -50
- data/lib/treaty/response/attribute/validation/orchestrator.rb +0 -19
- 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(
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
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(
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
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(
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
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(
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
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(
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
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(
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
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(
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
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(
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
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
|
@@ -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(
|
|
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,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,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
|