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
@@ -0,0 +1,253 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Treaty
4
+ module Action
5
+ module Versions
6
+ # Factory for version configuration and DSL.
7
+ #
8
+ # ## Purpose
9
+ #
10
+ # Provides the DSL interface within `version` blocks. Captures all
11
+ # version configuration: summary, deprecation, request schema,
12
+ # response schema, and executor delegation.
13
+ #
14
+ # ## Usage
15
+ #
16
+ # Created by:
17
+ # - Versions::DSL (when `version` is called)
18
+ #
19
+ # Consumed by:
20
+ # - Versions::Resolver (to find matching version)
21
+ # - Versions::Execution::Request (to execute the service)
22
+ # - Request::Validator / Response::Validator (to get schemas)
23
+ # - Info::Builder (to build version information)
24
+ #
25
+ # ## DSL Methods
26
+ #
27
+ # | Method | Purpose |
28
+ # |--------|---------|
29
+ # | `summary` | Set version description text |
30
+ # | `deprecated` | Mark version as deprecated (bool or proc) |
31
+ # | `request` | Define request schema (block or entity class) |
32
+ # | `response` | Define response schema with status code |
33
+ # | `delegate_to` | Set service class/proc to execute |
34
+ #
35
+ # ## Example
36
+ #
37
+ # version 1, default: true do
38
+ # summary "Initial API version"
39
+ #
40
+ # deprecated { ENV["V1_DEPRECATED"] == "true" }
41
+ #
42
+ # request do
43
+ # object :post do
44
+ # string :title, :required
45
+ # end
46
+ # end
47
+ #
48
+ # response 201 do
49
+ # object :post do
50
+ # string :id
51
+ # end
52
+ # end
53
+ #
54
+ # delegate_to Posts::CreateService
55
+ # end
56
+ #
57
+ # ## Validation
58
+ #
59
+ # - `default` must be boolean or Proc
60
+ # - Cannot be both default and deprecated
61
+ class Factory
62
+ # @return [Treaty::Action::Versions::Semantic] Semantic version wrapper
63
+ attr_reader :version
64
+
65
+ # @return [Boolean] Whether this is the default version
66
+ attr_reader :default_result
67
+
68
+ # @return [String, nil] Version summary/description
69
+ attr_reader :summary_text
70
+
71
+ # @return [Boolean] Whether version is deprecated
72
+ attr_reader :deprecated_result
73
+
74
+ # @return [Treaty::Action::Versions::Executor, nil] Executor configuration
75
+ attr_reader :executor
76
+
77
+ # @return [Treaty::Action::Request::Factory, nil] Request schema factory
78
+ attr_reader :request_factory
79
+
80
+ # @return [Treaty::Action::Response::Factory, nil] Response schema factory
81
+ attr_reader :response_factory
82
+
83
+ # Creates a new version factory
84
+ #
85
+ # @param version [Integer, String, Array] Version identifier
86
+ # @param default [Boolean, Proc] Whether this is the default version
87
+ def initialize(version:, default:)
88
+ @version = Semantic.new(version)
89
+ @default_result = default.is_a?(Proc) ? default.call : default
90
+ @summary_text = nil
91
+ @deprecated_result = false
92
+ @executor = nil
93
+
94
+ validate!
95
+ end
96
+
97
+ # Validates configuration on creation
98
+ #
99
+ # @return [void]
100
+ def validate!
101
+ validate_default_option!
102
+ end
103
+
104
+ # Validates configuration after block evaluation
105
+ #
106
+ # @raise [Treaty::Exceptions::VersionDefaultDeprecatedConflict]
107
+ # @return [void]
108
+ def validate_after_block!
109
+ validate_default_deprecated_conflict!
110
+ end
111
+
112
+ # Sets version summary text
113
+ #
114
+ # @param text [String] Version description
115
+ # @return [void]
116
+ def summary(text)
117
+ @summary_text = text
118
+ end
119
+
120
+ # Marks version as deprecated
121
+ #
122
+ # Accepts boolean, Proc, or block that evaluates to boolean.
123
+ # Deprecated versions raise error when accessed.
124
+ #
125
+ # @param condition [Boolean, Proc, nil] Deprecation condition
126
+ # @yield Block that returns boolean
127
+ # @return [void]
128
+ def deprecated(condition = nil)
129
+ result =
130
+ if condition.is_a?(Proc)
131
+ condition.call
132
+ elsif condition.is_a?(TrueClass) || condition.is_a?(FalseClass)
133
+ condition
134
+ else
135
+ yield
136
+ end
137
+
138
+ @deprecated_result = result
139
+ end
140
+
141
+ # Defines request schema
142
+ #
143
+ # Accepts either an Entity class or a block with attribute definitions.
144
+ #
145
+ # @param entity_class [Class, nil] Entity class for request schema
146
+ # @yield Block with request attribute definitions
147
+ # @return [void]
148
+ def request(entity_class = nil, &block)
149
+ @request_factory ||= Request::Factory.new
150
+
151
+ if entity_class.present?
152
+ @request_factory.use_entity(entity_class)
153
+ elsif block_given?
154
+ @request_factory.instance_eval(&block)
155
+ end
156
+ end
157
+
158
+ # Defines response schema with HTTP status
159
+ #
160
+ # Accepts status code and either Entity class or block.
161
+ #
162
+ # @param status [Integer] HTTP status code (200, 201, 404, etc.)
163
+ # @param entity_class [Class, nil] Entity class for response schema
164
+ # @yield Block with response attribute definitions
165
+ # @return [void]
166
+ def response(status, entity_class = nil, &block)
167
+ @response_factory ||= Response::Factory.new(status)
168
+
169
+ if entity_class.present?
170
+ @response_factory.use_entity(entity_class)
171
+ elsif block_given?
172
+ @response_factory.instance_eval(&block)
173
+ end
174
+ end
175
+
176
+ # Configures service delegation
177
+ #
178
+ # Sets the executor (class, string, or proc) and method to call.
179
+ #
180
+ # @param executor [Class, String, Proc, Hash] Service reference
181
+ # @param method [Symbol] Method to call (default: :call)
182
+ # @return [void]
183
+ #
184
+ # @example Class reference
185
+ # delegate_to Posts::CreateService
186
+ #
187
+ # @example With custom method
188
+ # delegate_to Posts::CreateService => :call!
189
+ #
190
+ # @example String path
191
+ # delegate_to "posts/create_service"
192
+ #
193
+ # @example Lambda
194
+ # delegate_to ->(params:) { { id: SecureRandom.uuid } }
195
+ def delegate_to(executor, method = :call)
196
+ @executor = Executor.new(executor, method)
197
+ end
198
+
199
+ ##########################################################################
200
+
201
+ private
202
+
203
+ # Validates default option is boolean or Proc
204
+ #
205
+ # @raise [Treaty::Exceptions::Validation] If invalid type
206
+ # @return [Boolean, Proc]
207
+ def validate_default_option!
208
+ if @default_result.is_a?(TrueClass) || @default_result.is_a?(FalseClass) || @default_result.is_a?(Proc)
209
+ return @default_result
210
+ end
211
+
212
+ raise Treaty::Exceptions::Validation,
213
+ I18n.t(
214
+ "treaty.versioning.factory.invalid_default_option",
215
+ type: @default_result.class
216
+ )
217
+ end
218
+
219
+ # Validates version is not both default and deprecated
220
+ #
221
+ # @raise [Treaty::Exceptions::VersionDefaultDeprecatedConflict]
222
+ # @return [void]
223
+ def validate_default_deprecated_conflict!
224
+ return unless @default_result == true
225
+ return unless @deprecated_result == true
226
+
227
+ raise Treaty::Exceptions::VersionDefaultDeprecatedConflict,
228
+ I18n.t(
229
+ "treaty.versioning.factory.default_deprecated_conflict",
230
+ version: @version.version
231
+ )
232
+ end
233
+
234
+ ##########################################################################
235
+
236
+ # Catches unknown DSL methods with helpful error
237
+ #
238
+ # @raise [Treaty::Exceptions::MethodName]
239
+ def method_missing(name, *, &_block)
240
+ raise Treaty::Exceptions::MethodName,
241
+ I18n.t("treaty.versioning.factory.unknown_method", method: name)
242
+ end
243
+
244
+ # Required for method_missing
245
+ #
246
+ # @return [Boolean]
247
+ def respond_to_missing?(name, *)
248
+ super
249
+ end
250
+ end
251
+ end
252
+ end
253
+ end
@@ -0,0 +1,150 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Treaty
4
+ module Action
5
+ module Versions
6
+ # Resolves version factory based on specified or default version.
7
+ #
8
+ # ## Purpose
9
+ #
10
+ # Finds the appropriate version factory from the collection based on:
11
+ # - Specified version (from request header or parameter)
12
+ # - Default version (if no version specified)
13
+ #
14
+ # Also enforces deprecation by raising error for deprecated versions.
15
+ #
16
+ # ## Usage
17
+ #
18
+ # Called internally by:
19
+ # - Versions::Workspace (at the start of treaty execution)
20
+ #
21
+ # ## Resolution Logic
22
+ #
23
+ # 1. If version specified → find matching factory or raise VersionNotFound
24
+ # 2. If no version → use default factory or raise SpecifiedVersionNotFound
25
+ # 3. If resolved factory is deprecated → raise Deprecated
26
+ #
27
+ # ## Error Types
28
+ #
29
+ # | Error | Condition |
30
+ # |-------|-----------|
31
+ # | VersionNotFound | Specified version doesn't exist |
32
+ # | SpecifiedVersionNotFound | No version specified and no default |
33
+ # | Deprecated | Resolved version is marked deprecated |
34
+ #
35
+ # ## Example
36
+ #
37
+ # # Find specific version:
38
+ # factory = Resolver.resolve!(
39
+ # specified_version: "2",
40
+ # collection_of_versions: collection
41
+ # )
42
+ #
43
+ # # Use default version:
44
+ # factory = Resolver.resolve!(
45
+ # specified_version: nil,
46
+ # collection_of_versions: collection
47
+ # )
48
+ class Resolver
49
+ # Resolves version factory (class method shortcut)
50
+ #
51
+ # @param specified_version [String, nil] Requested version or nil for default
52
+ # @param collection_of_versions [Treaty::Action::Versions::Collection] Available versions
53
+ # @return [Treaty::Action::Versions::Factory] Resolved version factory
54
+ # @raise [Treaty::Exceptions::VersionNotFound] If version doesn't exist
55
+ # @raise [Treaty::Exceptions::SpecifiedVersionNotFound] If no default available
56
+ # @raise [Treaty::Exceptions::Deprecated] If version is deprecated
57
+ def self.resolve!(...)
58
+ new(...).resolve!
59
+ end
60
+
61
+ # Creates a new resolver instance
62
+ #
63
+ # @param specified_version [String, nil] Requested version
64
+ # @param collection_of_versions [Treaty::Action::Versions::Collection] Available versions
65
+ def initialize(specified_version:, collection_of_versions:)
66
+ @specified_version = specified_version
67
+ @collection_of_versions = collection_of_versions
68
+ end
69
+
70
+ # Resolves and returns the appropriate version factory
71
+ #
72
+ # @return [Treaty::Action::Versions::Factory] Resolved version factory
73
+ # @raise [Treaty::Exceptions::VersionNotFound] If version doesn't exist
74
+ # @raise [Treaty::Exceptions::SpecifiedVersionNotFound] If no default available
75
+ # @raise [Treaty::Exceptions::Deprecated] If version is deprecated
76
+ def resolve!
77
+ determined_factory =
78
+ if specified_version_blank?
79
+ default_version_factory || raise_specified_version_not_found!
80
+ else
81
+ version_factory || raise_version_not_found!
82
+ end
83
+
84
+ raise_version_deprecated! if determined_factory.deprecated_result
85
+
86
+ determined_factory
87
+ end
88
+
89
+ private
90
+
91
+ # Finds factory matching specified version
92
+ #
93
+ # @return [Factory, nil] Matching factory or nil
94
+ def version_factory
95
+ @version_factory ||=
96
+ @collection_of_versions.find do |factory|
97
+ factory.version.version == @specified_version
98
+ end
99
+ end
100
+
101
+ # Finds default version factory
102
+ #
103
+ # @return [Factory, nil] Default factory or nil
104
+ def default_version_factory
105
+ @default_version_factory ||=
106
+ @collection_of_versions.find(&:default_result)
107
+ end
108
+
109
+ # Checks if specified version is blank
110
+ #
111
+ # @return [Boolean] True if version is nil or empty string
112
+ def specified_version_blank?
113
+ @specified_version.to_s.strip.empty?
114
+ end
115
+
116
+ ##########################################################################
117
+
118
+ # Raises error when no version specified and no default exists
119
+ #
120
+ # @raise [Treaty::Exceptions::SpecifiedVersionNotFound]
121
+ def raise_specified_version_not_found!
122
+ raise Treaty::Exceptions::SpecifiedVersionNotFound,
123
+ I18n.t("treaty.versioning.resolver.specified_version_required")
124
+ end
125
+
126
+ # Raises error when specified version doesn't exist
127
+ #
128
+ # @raise [Treaty::Exceptions::VersionNotFound]
129
+ def raise_version_not_found!
130
+ raise Treaty::Exceptions::VersionNotFound,
131
+ I18n.t(
132
+ "treaty.versioning.resolver.version_not_found",
133
+ version: @specified_version
134
+ )
135
+ end
136
+
137
+ # Raises error when resolved version is deprecated
138
+ #
139
+ # @raise [Treaty::Exceptions::Deprecated]
140
+ def raise_version_deprecated!
141
+ raise Treaty::Exceptions::Deprecated,
142
+ I18n.t(
143
+ "treaty.versioning.resolver.version_deprecated",
144
+ version: @specified_version
145
+ )
146
+ end
147
+ end
148
+ end
149
+ end
150
+ end
@@ -0,0 +1,64 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Treaty
4
+ module Action
5
+ module Versions
6
+ # Semantic version wrapper using Gem::Version.
7
+ #
8
+ # ## Purpose
9
+ #
10
+ # Normalizes version inputs (Integer, String, Array) into a consistent
11
+ # Gem::Version object. This enables proper version comparison and
12
+ # semantic versioning support.
13
+ #
14
+ # ## Usage
15
+ #
16
+ # Created internally by:
17
+ # - Versions::Factory (to store version number)
18
+ #
19
+ # Consumed by:
20
+ # - Versions::Resolver (to match requested version)
21
+ # - Info::Builder (to display version info)
22
+ #
23
+ # ## Version Formats
24
+ #
25
+ # Accepts multiple input formats:
26
+ # - Integer: `1` → "1"
27
+ # - String: `"1.0.0"` → "1.0.0"
28
+ # - Array: `[1, 0, 0]` → "1.0.0"
29
+ #
30
+ # ## Underlying Implementation
31
+ #
32
+ # Uses Gem::Version internally which provides:
33
+ # - Semantic version comparison (1.0.0 < 1.0.1 < 1.1.0 < 2.0.0)
34
+ # - Proper handling of pre-release versions (1.0.0-alpha < 1.0.0)
35
+ # - String normalization
36
+ #
37
+ # ## Example
38
+ #
39
+ # Semantic.new(1).version # => Gem::Version.new("1")
40
+ # Semantic.new("1.2.3").version # => Gem::Version.new("1.2.3")
41
+ # Semantic.new([1, 2, 3]).version # => Gem::Version.new("1.2.3")
42
+ class Semantic
43
+ # @return [Gem::Version] Normalized semantic version
44
+ attr_reader :version
45
+
46
+ # Creates a new semantic version wrapper
47
+ #
48
+ # @param version [Integer, String, Array] Version in any supported format
49
+ def initialize(version)
50
+ version =
51
+ if version.is_a?(Array)
52
+ version.join(".")
53
+ # elsif version.is_a?(Integer)
54
+ # version.to_s
55
+ else
56
+ version # rubocop:disable Style/RedundantSelfAssignmentBranch
57
+ end
58
+
59
+ @version = Gem::Version.new(version)
60
+ end
61
+ end
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,106 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Treaty
4
+ module Action
5
+ module Versions
6
+ # Core execution module for treaty call! method.
7
+ #
8
+ # ## Purpose
9
+ #
10
+ # Provides the `call!` instance method that orchestrates the complete
11
+ # treaty execution flow: version resolution, request validation,
12
+ # service execution, and response validation.
13
+ #
14
+ # ## Usage
15
+ #
16
+ # Included via:
17
+ # - Versions::DSL (when DSL is included in treaty class)
18
+ #
19
+ # Called by:
20
+ # - Controller integration (via Treaty::Action::Base.call!)
21
+ #
22
+ # ## Execution Flow
23
+ #
24
+ # ```
25
+ # call!(context:, inventory:, version:, params:)
26
+ # │
27
+ # ├─1─► Resolver.resolve! ──► Find version factory
28
+ # │
29
+ # ├─2─► Request::Validator.validate! ──► Validate params
30
+ # │
31
+ # ├─3─► Execution::Request.execute! ──► Run service
32
+ # │
33
+ # ├─4─► Response::Validator.validate! ──► Validate response
34
+ # │
35
+ # └─5─► Result.new ──► Return result object
36
+ # ```
37
+ #
38
+ # ## Parameters
39
+ #
40
+ # | Parameter | Description |
41
+ # |-----------|-------------|
42
+ # | context | Controller instance |
43
+ # | inventory | Inventory::Collection with controller data |
44
+ # | version | Requested version string (or nil for default) |
45
+ # | params | Request parameters |
46
+ #
47
+ # ## Return Value
48
+ #
49
+ # Returns `Treaty::Action::Result` with:
50
+ # - `data` - Validated response hash
51
+ # - `status` - HTTP status code
52
+ # - `version` - Resolved version string
53
+ module Workspace
54
+ private
55
+
56
+ # Executes the complete treaty flow
57
+ #
58
+ # Orchestrates version resolution, validation, execution,
59
+ # and returns a Result object.
60
+ #
61
+ # @param context [Object] Controller instance
62
+ # @param inventory [Treaty::Action::Inventory::Collection] Controller data
63
+ # @param version [String, nil] Requested version or nil for default
64
+ # @param params [Hash] Request parameters
65
+ # @return [Treaty::Action::Result] Execution result
66
+ # @raise [Treaty::Exceptions::VersionNotFound] If version not found
67
+ # @raise [Treaty::Exceptions::Deprecated] If version is deprecated
68
+ # @raise [Treaty::Exceptions::Validation] If validation fails
69
+ # @raise [Treaty::Exceptions::Execution] If service execution fails
70
+ def call!(context:, inventory:, version:, params:, **) # rubocop:disable Metrics/MethodLength
71
+ super
72
+
73
+ version_factory = Resolver.resolve!(
74
+ specified_version: version,
75
+ collection_of_versions: @collection_of_versions
76
+ )
77
+
78
+ validated_params = Request::Validator.validate!(
79
+ params:,
80
+ version_factory:
81
+ )
82
+
83
+ executor_result = Execution::Request.execute!(
84
+ context:,
85
+ inventory:,
86
+ version_factory:,
87
+ validated_params:
88
+ )
89
+
90
+ validated_response = Response::Validator.validate!(
91
+ version_factory:,
92
+ response_data: executor_result
93
+ )
94
+
95
+ status = version_factory.response_factory&.status || 200
96
+
97
+ Result.new(
98
+ data: validated_response,
99
+ status:,
100
+ version: version_factory.version.version
101
+ )
102
+ end
103
+ end
104
+ end
105
+ end
106
+ end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Treaty
4
+ # Action namespace containing the base class and versioning system.
5
+ #
6
+ # Users should inherit from Treaty::Action::Base:
7
+ #
8
+ # class Posts::CreateTreaty < Treaty::Action::Base
9
+ # version 1, default: true do
10
+ # summary "Create a new post"
11
+ #
12
+ # request do
13
+ # object :post do
14
+ # string :title, :required
15
+ # end
16
+ # end
17
+ #
18
+ # response 201 do
19
+ # object :post do
20
+ # string :id
21
+ # end
22
+ # end
23
+ #
24
+ # delegate_to Posts::CreateService
25
+ # end
26
+ # end
27
+ #
28
+ # @see Treaty::Action::Base for full documentation and examples
29
+ module Action
30
+ end
31
+ end
@@ -57,7 +57,7 @@ module Treaty
57
57
  def treaty_build_inventory_for(action_name, block)
58
58
  return nil unless block
59
59
 
60
- factory = Treaty::Inventory::Factory.new(action_name)
60
+ factory = Treaty::Action::Inventory::Factory.new(action_name)
61
61
  factory.instance_eval(&block)
62
62
  factory.collection
63
63
  end
data/lib/treaty/engine.rb CHANGED
@@ -12,7 +12,7 @@ module Treaty
12
12
 
13
13
  initializer "treaty.register_option_processors", before: :load_config_initializers do
14
14
  # Register all option processors (validators and modifiers)
15
- require "treaty/attribute/option/registry_initializer"
15
+ require "treaty/entity/attribute/option/registry_initializer"
16
16
  end
17
17
 
18
18
  initializer "treaty.validate_configuration" do
@@ -1,10 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Treaty
4
- module Attribute
5
- module Entity
4
+ module Entity
5
+ module Attribute
6
6
  # Entity-specific attribute that defaults to required: true
7
- class Attribute < Treaty::Attribute::Base
7
+ class Attribute < Base
8
8
  private
9
9
 
10
10
  def apply_defaults!
@@ -16,7 +16,7 @@ module Treaty
16
16
  def process_nested_attributes(&block)
17
17
  return unless object_or_array?
18
18
 
19
- builder = Builder.new(collection_of_attributes, @nesting_level + 1)
19
+ builder = Treaty::Entity::Builder.new(collection_of_attributes, @nesting_level + 1)
20
20
  builder.instance_eval(&block)
21
21
  end
22
22
  end